<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>e度人 &#187; 编程开发</title>
	<atom:link href="http://www.eduren.net/post/tag/%e7%bc%96%e7%a8%8b%e5%bc%80%e5%8f%91/feed" rel="self" type="application/rss+xml" />
	<link>http://www.eduren.net</link>
	<description>2012年最新Godaddy 优惠码,Godaddy 教程,GoDaddy主机信息</description>
	<lastBuildDate>Wed, 08 Feb 2012 03:44:38 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>设置c++程序的堆栈空间解决栈溢出问题</title>
		<link>http://www.eduren.net/post/109.html</link>
		<comments>http://www.eduren.net/post/109.html#comments</comments>
		<pubDate>Fri, 02 Apr 2010 12:12:27 +0000</pubDate>
		<dc:creator>winday</dc:creator>
				<category><![CDATA[编程开发]]></category>
		<category><![CDATA[c]]></category>
		<category><![CDATA[IT]]></category>
		<category><![CDATA[vc]]></category>

		<guid isPermaLink="false">http://www.eduren.net/?p=104</guid>
		<description><![CDATA[<p style="text-indent: 2em;">设置c++程序的堆栈空间解决栈溢出问题</p><p style="text-indent: 2em;">程序的静态数据量大的时候，有时候会出现栈溢出问题，往往是程序还没运行算法呢，就down掉了， 比如你在创建包含大数组的类（或数据）的时候，栈就溢出了。这是由于系统分配给程序的栈空间太小。</p><p style="text-indent: 2em;">一种方法，就是不要静态分配，用new动态创建，是从堆中分配的，堆的空间足够大，不过记得写析构 函数，delete你申请的堆空间。其实这样也挺方便，类结束的时候会自动调用析构函数释放空间。养成&#34;不在栈上定义大数组/大对象&#34;的好习惯很重要，否 则再大的栈也会被撑爆的。</p>...
]]></description>
			<content:encoded><![CDATA[<p style="text-indent: 2em;">设置c++程序的堆栈空间解决栈溢出问题</p>
<p style="text-indent: 2em;">程序的静态数据量大的时候，有时候会出现栈溢出问题，往往是程序还没运行算法呢，就down掉了， 比如你在创建包含大数组的类（或数据）的时候，栈就溢出了。这是由于系统分配给程序的栈空间太小。</p>
<p style="text-indent: 2em;">一种方法，就是不要静态分配，用new动态创建，是从堆中分配的，堆的空间足够大，不过记得写析构 函数，delete你申请的堆空间。其实这样也挺方便，类结束的时候会自动调用析构函数释放空间。养成”不在栈上定义大数组/大对象”的好习惯很重要，否 则再大的栈也会被撑爆的。</p>
<p style="text-indent: 2em;">当然，如果你不喜欢new，delete的话，还是静态 分配（毕竟静态分配有很多好处），那么可以通过改变默认栈空间来解决。</p>
<p style="text-indent: 2em;">
<p style="text-indent: 2em;">LINK的/STACK选项</p>
<p style="text-indent: 2em;">/STACK   :reserve[,commit]</p>
<p style="text-indent: 2em;">reserve:栈总大小</p>
<p style="text-indent: 2em;">commit:程序开始时系统提供的实际内存量</p>
<p style="text-indent: 2em;">缺省：1M,8K</p>
<p style="text-indent: 2em;">参数为0取缺省值</p>
<p style="text-indent: 2em;">
<p style="text-indent: 2em;">今天在VC++.NET 中运行聚类程序，老是说Stack   OverFlow,  后来才发现是栈空间太小了。</p>
<p style="text-indent: 2em;">单单保存100个网页的数据量就比较大了。</p>
<p style="text-indent: 2em;">把堆栈的大小已经设置 为:</p>
<p style="text-indent: 2em;">堆栈保留大小为：100000000；</p>
<p style="text-indent: 2em;">堆栈提交大小为:   100000000;</p>
<p style="text-indent: 2em;">就没问题了。</p>
<p style="text-indent: 2em;">
<p style="text-indent: 2em;">设置：项目-&gt; 属性-&gt; 链接器-&gt; system-&gt;  堆栈保留大小/堆栈提交大小</p>
<p style="text-indent: 2em;">
<p style="text-indent: 2em;">
<p style="text-indent: 2em;">问题解答：</p>
<p>方 法一：STACKSIZE   定义.def文件</p>
<p>语法：STACKSIZE reserve[,commit]<br />
reserve：栈的大小；commit：可选项，与操作系统有关，在NT上只一次分配物理内存的大小</p>
<p>方法二：设定/STACK</p>
<p>打开工程，依次操作菜单如下：Project-&gt;Setting-&gt;Link，在Category 中选中Output，然后<br />
在 Reserve中设定堆栈的最大值和commit。</p>
<p>注意：reserve默认值为1MB,最小值为4Byte；commit是保留在虚拟 内存的页文件里面，它设置的较<br />
大会使栈开辟较大的值，可能增加内存的开销和启动时间</p>
<h3  class="related_post_title">您可能还对这些文章感兴趣</h3><ul class="related_post"><li>七月 14, 2009 -- <a href="http://www.eduren.net/post/44.html" title="vc++6.0中view消失的BUG">vc++6.0中view消失的BUG</a> (0)</li><li>五月 1, 2009 -- <a href="http://www.eduren.net/post/8.html" title="c++中的指针">c++中的指针</a> (0)</li><li>五月 1, 2009 -- <a href="http://www.eduren.net/post/3.html" title="VC++是如何编译的">VC++是如何编译的</a> (0)</li><li>六月 18, 2010 -- <a href="http://www.eduren.net/post/wordpress-3-released.html" title="WordPress 3.0 正式版发布">WordPress 3.0 正式版发布</a> (0)</li><li>六月 11, 2010 -- <a href="http://www.eduren.net/post/the-best-way-to-transfer-your-domain-name.html" title="快速转移国际域名的方法">快速转移国际域名的方法</a> (24)</li><li>四月 18, 2010 -- <a href="http://www.eduren.net/post/125.html" title="从进程中判断出病毒和木马">从进程中判断出病毒和木马</a> (0)</li><li>四月 17, 2010 -- <a href="http://www.eduren.net/post/121.html" title="本站域名今日更换解析服务器">本站域名今日更换解析服务器</a> (0)</li><li>四月 3, 2010 -- <a href="http://www.eduren.net/post/111.html" title="本站论文板块即将开启，尽请期待！">本站论文板块即将开启，尽请期待！</a> (0)</li><li>四月 2, 2010 -- <a href="http://www.eduren.net/post/108.html" title="你会用shutdown吗？看看吧">你会用shutdown吗？看看吧</a> (0)</li><li>三月 20, 2010 -- <a href="http://www.eduren.net/post/106.html" title="网站链接优化">网站链接优化</a> (0)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.eduren.net/post/109.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>vc++6.0中view消失的BUG</title>
		<link>http://www.eduren.net/post/44.html</link>
		<comments>http://www.eduren.net/post/44.html#comments</comments>
		<pubDate>Tue, 14 Jul 2009 03:34:29 +0000</pubDate>
		<dc:creator>winday</dc:creator>
				<category><![CDATA[编程开发]]></category>
		<category><![CDATA[e]]></category>
		<category><![CDATA[IT]]></category>
		<category><![CDATA[vc]]></category>
		<category><![CDATA[软件技巧]]></category>

		<guid isPermaLink="false">http://www.eduren.net/?p=46</guid>
		<description><![CDATA[<p>在vc++6.0中进行基于MFC编程时，窗口左侧的class view中会显示有一个名为CXXXView的类</p><p>在我们执行某些操作的时候（例如在上面点击右键&#8212;&#8220;&#8221;add member function&#34;或者&#8220;add windows message handler&#34;时），这个类可能就不见了（有一定的概率）</p><p>这个时候我们该怎么办呢？</p><p>很简单</p><p>只要切换到fileview 然后在双击相应的XXXVIEW.h，打开这个头文件，在头文件的前部随便打上几个空格，然后再切换到class view，这时候，CXXXview就又出现了</p>...
]]></description>
			<content:encoded><![CDATA[<p>在vc++6.0中进行基于MFC编程时，窗口左侧的class view中会显示有一个名为CXXXView的类</p>
<p>在我们执行某些操作的时候（例如在上面点击右键—“”add member function”或者“add windows message handler”时），这个类可能就不见了（有一定的概率）</p>
<p>这个时候我们该怎么办呢？</p>
<p>很简单</p>
<p>只要切换到fileview 然后在双击相应的XXXVIEW.h，打开这个头文件，在头文件的前部随便打上几个空格，然后再切换到class view，这时候，CXXXview就又出现了</p>
<h3  class="related_post_title">您可能还对这些文章感兴趣</h3><ul class="related_post"><li>四月 2, 2010 -- <a href="http://www.eduren.net/post/109.html" title="设置c++程序的堆栈空间解决栈溢出问题">设置c++程序的堆栈空间解决栈溢出问题</a> (0)</li><li>三月 20, 2010 -- <a href="http://www.eduren.net/post/105.html" title="告诉你C盘里的每个文件夹都是干嘛的，哪个可以删除，哪些不能碰呢">告诉你C盘里的每个文件夹都是干嘛的，哪个可以删除，哪些不能碰呢</a> (0)</li><li>二月 28, 2010 -- <a href="http://www.eduren.net/post/91.html" title="免费数据恢复软件：NTFSUndelete">免费数据恢复软件：NTFSUndelete</a> (0)</li><li>二月 28, 2010 -- <a href="http://www.eduren.net/post/89.html" title="WinXP中CPU占用率100%原因及解决方法">WinXP中CPU占用率100%原因及解决方法</a> (0)</li><li>二月 28, 2010 -- <a href="http://www.eduren.net/post/87.html" title="一条命令解决解决该内存不能为“read”或“written”">一条命令解决解决该内存不能为“read”或“written”</a> (0)</li><li>二月 28, 2010 -- <a href="http://www.eduren.net/post/85.html" title="我印象中的Internet Explorer浏览器">我印象中的Internet Explorer浏览器</a> (0)</li><li>十一月 11, 2009 -- <a href="http://www.eduren.net/post/76.html" title="轻松安装系统驱动">轻松安装系统驱动</a> (0)</li><li>七月 25, 2009 -- <a href="http://www.eduren.net/post/51.html" title="卡巴斯基2010key的添加方法 （命令行）">卡巴斯基2010key的添加方法 （命令行）</a> (0)</li><li>七月 23, 2009 -- <a href="http://www.eduren.net/post/47.html" title="卡巴斯基2010简体中文版上市">卡巴斯基2010简体中文版上市</a> (0)</li><li>七月 13, 2009 -- <a href="http://www.eduren.net/post/42.html" title="加密文件或文件夹">加密文件或文件夹</a> (0)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.eduren.net/post/44.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>c++中的指针</title>
		<link>http://www.eduren.net/post/8.html</link>
		<comments>http://www.eduren.net/post/8.html#comments</comments>
		<pubDate>Fri, 01 May 2009 02:01:20 +0000</pubDate>
		<dc:creator>winday</dc:creator>
				<category><![CDATA[编程开发]]></category>
		<category><![CDATA[vc]]></category>

		<guid isPermaLink="false">http://www.eduren.net/?p=11</guid>
		<description><![CDATA[<p>指针是c++语言中的一个非常重要的概念，指针是用来存放内存单元地址的数据类型。</p><p>合理的使用指针可以使你的程序更加高效，而且程序中的很多操作都必须使用指针来完成。</p><div>&#160;&#160;&#160;&#160;&#160;&#160;指针的声明：</div><div>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;数据类型 *标识符;</div><div>&#160;&#160;&#160;&#160;&#160;&#160;例如：</div>...
]]></description>
			<content:encoded><![CDATA[<p>指针是c++语言中的一个非常重要的概念，指针是用来存放内存单元地址的数据类型。</p>
<p>合理的使用指针可以使你的程序更加高效，而且程序中的很多操作都必须使用指针来完成。</p>
<div>指针的声明：</div>
<div>数据类型 *标识符;</div>
<div>例如：</div>
<div>int *i; //声明一个指向int类型的指针</div>
<div>刚开始声明的指针变量没有确切的值，他的地址值只是一个随机数，也就是说，不能确定这时候指针变量中存放的是哪个内存单元的地址。因此，指针声明之后必须先赋值才能使用。</div>
<div>与指针相关的两个运算符：“*”和“&amp;”</div>
<div>”*“ ：称为指针运算符，表示获取指针指向的变量的值，是一元操作符。</div>
<div>“&amp;”：称为取地址运算符，也是一元操作符，用来得到一个对象的内存地址。</div>
<div>”*”和“&amp;”出现在生命语句和执行语句中其含义是不一样的。如：int *i表示声明一个int类型的指针。cout &lt;&lt; *i 输出i所指向的内容。int &amp;rf表明int类型的引用，int a=1;int *b=&amp;a这里表示取地址。</div>
<div>特俗指针*void：可以存储任何类型的指针（类成员函数除外）</div>
<div>指向常量的指针本身不能改变，但是可以改变他所指向的内容。如：</div>
<div>const char *name=”Adolph”; //adolph是个字符常量</div>
<div>name=”llt”; //这是允许的</div>
<div>*name=”microsoft”; //错误，指向常量的指针本身不能改变</div>
<div>常量指针不能改变本身的值。如：</div>
<div>char const *name=”adolph”;</div>
<div>name=”microsoft”; //错误，name是常量指针，不能改变</div>
<div>指针运算。</div>
<div>int a[5]={1,2,3,4,5};</div>
<div>int i;</div>
<div>//循环输出数组元素</div>
<div>for(i=0;i&lt;5;i++)</div>
<div>{</div>
<div>cout &lt;&lt; *(a+i) &lt;&lt; endl;</div>
<div>}</div>
<div>或者</div>
<div>int *i;</div>
<div>for(i=a;i&lt;a+5;i++)</div>
<div>{</div>
<div>cout &lt;&lt; *i &lt;&lt; endl;</div>
<div>}</div>
<h3  class="related_post_title">您可能还对这些文章感兴趣</h3><ul class="related_post"><li>四月 2, 2010 -- <a href="http://www.eduren.net/post/109.html" title="设置c++程序的堆栈空间解决栈溢出问题">设置c++程序的堆栈空间解决栈溢出问题</a> (0)</li><li>七月 14, 2009 -- <a href="http://www.eduren.net/post/44.html" title="vc++6.0中view消失的BUG">vc++6.0中view消失的BUG</a> (0)</li><li>五月 1, 2009 -- <a href="http://www.eduren.net/post/3.html" title="VC++是如何编译的">VC++是如何编译的</a> (0)</li><li>四月 30, 2009 -- <a href="http://www.eduren.net/post/1.html" title="给C++初学者的50个忠告">给C++初学者的50个忠告</a> (0)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.eduren.net/post/8.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>VC++是如何编译的</title>
		<link>http://www.eduren.net/post/3.html</link>
		<comments>http://www.eduren.net/post/3.html#comments</comments>
		<pubDate>Thu, 30 Apr 2009 23:06:05 +0000</pubDate>
		<dc:creator>winday</dc:creator>
				<category><![CDATA[编程开发]]></category>
		<category><![CDATA[vc]]></category>

		<guid isPermaLink="false">http://www.eduren.net/?p=6</guid>
		<description><![CDATA[<p><span style="font-size: small"><span style="font-family: 黑体"><font color="#333300">很多人都用vc++来写程序，但是不知道你们想没想过，在vc++的内部，它是如何进行编译的？</font></span></span></p><p><span style="font-size: small"><span style="font-family: 黑体"><font color="#333300">下面就是对vc++内部机制的简单介绍。</font></span></span></p>...
]]></description>
			<content:encoded><![CDATA[<p><span style="font-size: small;"><span style="font-family: 黑体;"><span style="color: #333300;">很多人都用vc++来写程序，但是不知道你们想没想过，在vc++的内部，它是如何进行编译的？</span></span></span></p>
<p><span style="font-size: small;"><span style="font-family: 黑体;"><span style="color: #333300;">下面就是对vc++内部机制的简单介绍。</span></span></span></p>
<p>Jan Gray在1994曾经写了一篇叫做C++ under the Hood的文章，介绍了Visual C++的实现细节。这篇指南就是基于Jan的文章之上，我同时会将Jan文章中让人难于理解的地方详细阐述。希望这篇指南可以让更多的人了解C++的底层 实现机制。</p>
<p><strong><span style="color: #ff0000; font-size: small;">The layout of a Class</span></strong></p>
<p>struct B {<br />
public:<br />
int bm1;<br />
protected:<br />
int bm2;<br />
private:<br />
int bm3;<br />
};<br />
<span style="color: #800000;">Struct B 在内存中的layout是怎么样的？ Visual C++保证B中的member variables 在内存中的layout与它们生命的顺序一致。</span>Struct B在内存的中layout应该是这个样子的：</p>
<p><img src="http://www.eduren.net/wp-content/uploads/2010/06/2209_11.JPG" alt="" width="95" height="87" /></p>
<p><strong><span style="color: #ff0000; font-size: small;">Single Inheritance</span></strong><br />
struct C {<br />
int c1;<br />
void cf();<br />
};<br />
struct D : C {<br />
int d1;<br />
void df();<br />
};<br />
<span style="color: #0000ff;">在Visual C++中保证在C的member variables 在内存中的位置永远在D的起始位置。</span>就像这样:</p>
<p><img src="http://www.eduren.net/wp-content/uploads/2010/06/4492_2.JPG" alt="" width="168" height="68" /></p>
<p>这样做的好处是当C* pC = new D();Visual C++不需要为pC做额外的displacement 转换。pC 的address equal D* pD = new D();中的pD.</p>
<p><strong><span style="color: #ff0000; font-size: small;">Multiple Inheritance</span></strong><br />
比较复杂：<br />
struct E {<br />
int e1;<br />
void ef();<br />
};<br />
struct F : C, E {<br />
int f1;<br />
void ff();<br />
};<br />
<span style="color: #0000ff;">多重继承比较复杂，他们的Base和Derived的指针的位置不再相同。</span><br />
F f;<br />
// (void*)&amp;f == (void*)(C*)&amp;f;<br />
// (void*)&amp;f &lt; (void*)(E*)&amp;f;<br />
通过如下的Diagram of layout你可以看得更加清楚：</p>
<p><img src="http://www.eduren.net/wp-content/uploads/2010/06/bdc7_3.JPG" alt="" width="424" height="102" /></p>
<p><span style="color: #800000;">为什么在图中C在E的上面？</span>这是Visual C++ 的convention罢了，基类在内存中的layout correspond to 他们的的声明顺序。因为C的声明在E的前面，所以我们看到的F在内存的layout就是这样子的。<br />
由 此图可知，E *pE = new F() 与C *pC = new F()中的pE 和pC指向的内存位置并不相同，<span style="color: #003366;">对于pC 来说compiler不需要额外做任何事情，但是对于pE，为了让它指向E在内存中的位置compiler需要进行一种叫做displacement的调 整。</span></p>
<p><strong><span style="color: #ff0000; font-size: small;">Virtual Inheritance</span></strong><br />
请考虑这种情形：<br />
struct Employee { &#8230; };<br />
struct Manager : Employee { &#8230; };<br />
struct Worker : Employee { &#8230; };<br />
struct MiddleManager : Manager, Worker { &#8230; };</p>
<p>无疑，按照我们之前的叙述，MiddleManager在内存中的layout应该是这个样的:</p>
<p><img src="http://www.eduren.net/wp-content/uploads/2010/06/649b_4.JPG" alt="" width="145" height="135" /></p>
<p>在内存中的有两个Employee的实例，如何Employee 很小那么这种冗余是可以忽略的，可是如果Employee很大呢？ 那么有没有什么方法可以让Manager 和Worker在内存中共享同一个Instance呢？这就是Virtual Inheritance需要解决的问题。<br />
在享受这种优化的服务之前，你应该将你的类体系结构编程这样：<br />
struct Employee { &#8230; };<br />
struct Manager : virtual Employee { &#8230; };<br />
struct Worker : virtual Employee { &#8230; };<br />
struct MiddleManager : Manager, Worker { &#8230; };</p>
<p>也就是在希望被sharing 的基类前面加上Virtual关键字，多么直观啊。<br />
struct G : virtual C {<br />
int g1;<br />
void gf();<br />
};<br />
struct H : virtual C {<br />
int h1;<br />
void hf();<br />
};<br />
struct I : G, H {<br />
int i1;<br />
void _if();<br />
};</p>
<p>之后你的类在内存中的就应该是这个样子：</p>
<p><img src="http://www.eduren.net/wp-content/uploads/2010/06/8732_5.JPG" alt="" width="186" height="164" /></p>
<p>其中vbptr中存储的是对Employee的相对displacement.<br />
Data Member Access<br />
在没有继承的情形：<br />
C* pc;<br />
pc-&gt;c1; // *(pc + dCc1);</p>
<p>c1 的访问类似于*(pC + displacement of c1 within C);在本例子中根据Class C的定义和Diagram of layout我们可以发现displacement == 0.<br />
在单继承的情形中：<br />
D* pd;<br />
pd-&gt;c1; // *(pd + dDC + dCc1); // *(pd + dDCc1);<br />
pd-&gt;d1; // *(pd + dDd1);</p>
<p>根据我们之前的Diagram不难看出pd-&gt;c1 == *(pd + displacement from D to C + displacement from C to c1).这种情形中displacement == 0。<br />
pd-&gt;d1 == *(pd + displacement from D to d1). 这种情形中 displacement == 4。<br />
在多重继承中，情形稍微复杂些，但所有的displacement 还都是常量(constant)。<br />
F* pf;<br />
pf-&gt;c1; // *(pf + dFC + dCc1); // *(pf + dFc1);<br />
pf-&gt;e1; // *(pf + dFE + dEe1); // *(pf + dFe1);<br />
pf-&gt;f1; // *(pf + dFf1);<br />
我想何以根据我们之前的Diagram轻松的算出每一个displacement。<br />
虚拟继承又是怎么的呢？<br />
I* pi;<br />
pi-&gt;c1; // *(pi + dIGvbptr + (*(pi+dIGvbptr))[1] + dCc1);<br />
pi-&gt;g1; // *(pi + dIG + dGg1); // *(pi + dIg1);<br />
pi-&gt;h1; // *(pi + dIH + dHh1); // *(pi + dIh1);<br />
pi-&gt;i1; // *(pi + dIi1);<br />
I i;<br />
i.c1; // *(&amp;i + IdIC + dCc1); // *(&amp;i + IdIc1);</p>
<p>对g1,h1,以及i1的访问很容易理解，我想说说对c1的访问。<br />
pi-&gt;c1 是一种动态的访问。在runtime的时候编译器不知道pi的真正type是什么，这时就要用到之前说过的vbptr，(*(pi + dIGvbptr))[1]是指在特定的vbptr中(不论vbptr是属于 G还是H)其对于base virtual class的偏移地址。至于为什么是(*(pi + dIGvbptr))[1] 而不是 (*(pi + dIGvbptr))[0]，我猜这也是Visual C++的设计使然吧。 如果你知道(*(pi + dIGvbptr))[0]中放的什么，请让我知道<br />
对于i.c1的访问，因为这是一种静态的访问，为了节省开销C++对它的处理直接而干脆。之所以C++敢于这么做是因为在I中displacement of i在这种静态声明中是固定不变的。</p>
<p><strong><span style="color: #ff0000; font-size: small;">Casts</span></strong><br />
理解了以上概念相信Casts between 2 types就不是什么问题了，一下是我们常见的一些cast在Visual C++中的实现手段。<br />
对于多重继承来说：<br />
F* pf;<br />
(C*)pf; // (C*)(pf ? pf + dFC : 0); // (C*)pf;<br />
(E*)pf; // (E*)(pf ? pf + dFE : 0);<br />
对于虚拟继承来说：<br />
I* pi;<br />
(G*)pi; // (G*)pi;<br />
(H*)pi; // (H*)(pi ? pi + dIH : 0);<br />
(C*)pi; // (C*)(pi ? (pi+dIGvbptr + (*(pi+dIGvbptr))[1]) : 0);</p>
<p>什么，没看懂？那么就再看一遍我对Data Member Access的描述吧。<br />
Member Functions<br />
struct P {<br />
int p1;<br />
void pf(); // new<br />
virtual void pvf(); // new<br />
};<br />
对于一个non-static 成员变量的访问应该是这样的(我想因该大部分程序员都会了解吧)member function被调用的的时候会被传入一个this指针他的类型是:<br />
Type X * co<br />
nst。(有人想过为什么是会是这样的声明而不是const Type X * const 或者const Type X *么？<br />
如 果声明为const Type X *那么我们将无法通过this指针修改member variables。至于const Type X * const么实际上当你 将pf定义成：void pf() const;那么传入的this就是const Type X * const的。通过Type X * const 我们不能擅自修改this指针本身，不信你试试。)<br />
所以对于pf的调用实际上应该是这个样子的：<br />
void P::pf() { // void P::pf([P *const this])<br />
++p1;   // ++(this-&gt;p1);<br />
}</p>
<p><strong><span style="color: #ff0000; font-size: small;">Overriding Member Functions</span></strong><br />
考虑以下声明：<br />
struct Q : P {<br />
int q1;<br />
void pf(); // overrides P::pf<br />
void qf(); // new<br />
void pvf(); // overrides P::pvf<br />
virtual void qvf(); // new<br />
};<br />
Overridden member function包括 static 和 dynamic 调用。在C++中使用virtual关键字来区分。<br />
情形1：static resolution:<br />
当一个member function被重写且没有virtual那么，对他的调用在compiling 的时候就已经determined.<br />
P p; P* pp = &amp;p; Q q; P* ppq = &amp;q; Q* pq = &amp;q;<br />
pp-&gt;pf(); // pp-&gt;P::pf(); // P::pf(pp);<br />
ppq-&gt;pf(); // ppq-&gt;P::pf(); // P::pf(ppq);<br />
pq-&gt;pf(); // pq-&gt;Q::pf(); // Q::pf((P*)pq);<br />
pq-&gt;qf(); // pq-&gt;Q::qf(); // Q::qf(pq);</p>
<p>当pp-&gt;pf() 以及 ppq-&gt;pf()这两种情形，调用它们的指针类型在compiling是就已经安插。因为没有Virtual 那么就没有多态的干扰，Visual C++将忠实于-&gt;运算符左侧的类型，并且将此类型作为this传入此函数。</p>
<p>情形 2：dynamic resolution：<br />
pp-&gt;pvf(); // pp-&gt;P::pvf(); // P::pvf(pp);<br />
ppq-&gt;pvf(); // ppq-&gt;Q::pvf(); // Q::pvf((Q*)ppq);<br />
pq-&gt;pvf(); // pq-&gt;Q::pvf(); // Q::pvf((P*)pq);</p>
<p>可怜的C++编译器，将如何决议overridden member function 的类型呢？为了解决这个问题vfptr被引入。<br />
通常被安插在memory layout的第一个位置，它指向此class的 vftable。 Vftable中存储的是所有virtual functions的地址。就像这样：</p>
<p><img src="http://www.eduren.net/wp-content/uploads/2010/06/79df_6.JPG" alt="" width="515" height="103" /></p>
<p>当子类重写了父类的方法那么vftable中相应的entry 就应该被改写，如图：</p>
<p><img src="http://www.eduren.net/wp-content/uploads/2010/06/4532_7.JPG" alt="" width="501" height="122" /></p>
<p>C++就是通过这种方式来进行overridden member function 的dynamic resolution。</p>
<p><strong><span style="color: #ff0000; font-size: small;">Virtual Functions: Multiple Inheritance</span></strong><br />
这是本指南最刺激和有趣的一部分，我要向你介绍著名的Thunk技术。<br />
考虑一下情形：<br />
struct R {<br />
int r1;<br />
virtual void pvf(); // new<br />
virtual void rvf(); // new<br />
}；<br />
struct S : P, R {<br />
int s1;<br />
void pvf(); // overrides P::pvf and R::pvf<br />
void rvf(); // overrides R::rvf<br />
void svf(); // new<br />
};</p>
<p>这样的layout应该如何画？我猜是这样的：</p>
<p><img src="http://www.eduren.net/wp-content/uploads/2010/06/8bab_8.JPG" alt="" width="495" height="175" /><br />
S s; S* ps = &amp;s;<br />
((P*)ps)-&gt;pvf(); // ((P*)ps)-&gt;P::vfptr[0])((S*)(P*)ps)<br />
((R*)ps)-&gt;pvf(); // ((R*)ps)-&gt;R::vfptr[0])((S*)(R*)ps)<br />
当 我lunching以上两种调用，我所期望的的函数语义应该是就像每个函数注释后面的一样。毕竟-&gt;运算符左侧的是一个S*对吧，所以传入 member function的指针也应该是S*。当使用P*是问题很简单，P*和S*指向的是相同的内存地址，C++ compiler不需要做任何事情。但是当使用R*后有点问题，R*和S*指向的内存地址不同。那么我们就要使用一些技巧让R*指针转化为S*。对于这个 问题的解决办法基本上就是使用一种叫做Thunk的技术。重写 entry of pvf within vftable。<br />
重写的方法很多，在VC++中重写后的结果像这样：</p>
<p>S::pvf-adjust: // MSC++<br />
this -= SdPR;<br />
goto S::pvf()<br />
呵呵，很简单是么，将原先指向R*的this指针- displacement of S from R, 然后jump 到真正的S::pvf()的函数地址中。</p>
<p><strong><span style="color: #ff0000; font-size: small;">Constructors and Destructors</span></strong><br />
Constructor 和 Destructor我们常见，但是不能使用。通常有compiler将其分解成为多部构造。<br />
Constructor 被分解后应该是这样的：<br />
1)对于一个most derived类，初始化vbptr，并调用virtual base 的构造函数。<br />
2)调用non-virtual base classes 的构造函数。<br />
3)调用data members的构造函数<br />
4)初始化vfptr。<br />
5)执行用户写在constructor中的代码。<br />
Destructor被分解后应该是这样的：<br />
1） 初始化vfptr<br />
2） 执行用户卸载destructor中的代码。<br />
3） 调用data member 的析构函数，顺序是与data member 在类中声明的顺序相反。<br />
4） 调用non-virtual bases的析构函数，与声明的顺序相反。<br />
5） 对于一个most derived 的类，调用它的virtual base的析构函数。</p>
<h3  class="related_post_title">您可能还对这些文章感兴趣</h3><ul class="related_post"><li>四月 2, 2010 -- <a href="http://www.eduren.net/post/109.html" title="设置c++程序的堆栈空间解决栈溢出问题">设置c++程序的堆栈空间解决栈溢出问题</a> (0)</li><li>七月 14, 2009 -- <a href="http://www.eduren.net/post/44.html" title="vc++6.0中view消失的BUG">vc++6.0中view消失的BUG</a> (0)</li><li>五月 1, 2009 -- <a href="http://www.eduren.net/post/8.html" title="c++中的指针">c++中的指针</a> (0)</li><li>四月 30, 2009 -- <a href="http://www.eduren.net/post/1.html" title="给C++初学者的50个忠告">给C++初学者的50个忠告</a> (0)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.eduren.net/post/3.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>给C++初学者的50个忠告</title>
		<link>http://www.eduren.net/post/1.html</link>
		<comments>http://www.eduren.net/post/1.html#comments</comments>
		<pubDate>Thu, 30 Apr 2009 13:54:02 +0000</pubDate>
		<dc:creator>winday</dc:creator>
				<category><![CDATA[编程开发]]></category>

		<guid isPermaLink="false">http://www.eduren.net/?p=4</guid>
		<description><![CDATA[<p>1.把C++当成一门新的语言学习（和C没啥关系！真的。）；&#160;&#160;&#160; <br />　　2.看《Thinking&#160;In&#160;C++》，不要看《C++变成死相》；&#160;&#160;&#160; <br />　　3.看《The&#160;C++&#160;Programming&#160;Language》和《Inside&#160;The&#160;C++&#160;Object&#160;Model》,不要因为他们很难而我们自己是初学者所以就不看；&#160;&#160;&#160; <br />...</p>
]]></description>
			<content:encoded><![CDATA[<p>1.把C++当成一门新的语言学习（和C没啥关系！真的。）；<br />
2.看《Thinking In C++》，不要看《C++变成死相》；<br />
3.看《The C++ Programming Language》和《Inside The C++ Object Model》,不要因为他们很难而我们自己是初学者所以就不看；<br />
4.不要被VC、BCB、BC、MC、TC等词汇所迷惑——他们都是集成开发环境，而我们要学的是一门语言；<br />
5.不要放过任何一个看上去很简单的小编程问题——他们往往并不那么简单，或者可以引伸出很多知识点；<br />
6.会用Visual C++，并不说明你会C++；<br />
7.学class并不难，template、STL、generic programming也不过如此——难的是长期坚持实践和不遗余力的博览群书；<br />
8.如果不是天才的话，想学编程就不要想玩游戏——你以为你做到了，其实你的C++水平并没有和你通关的能力一起变高——其实可以时刻记住：学C++是为了编游戏的；<br />
9.看Visual C++的书，是学不了C++语言的；<br />
10.浮躁的人容易说：XX语言不行了，应该学YY；——是你自己不行了吧！？<br />
11.浮躁的人容易问：我到底该学什么；——别问，学就对了；<br />
12.浮躁的人容易问：XX有钱途吗；——建议你去抢银行；<br />
13.浮躁的人容易说：我要中文版！我英文不行！——不行？学呀！<br />
14.浮躁的人容易问：XX和YY哪个好；——告诉你吧，都好——只要你学就行；<br />
15.浮躁的人分两种：a)只观望而不学的人；b)只学而不坚持的人；<br />
16.把时髦的技术挂在嘴边，还不如把过时的技术记在心里；<br />
17.C++不仅仅是支持面向对象的程序设计语言；<br />
18.学习编程最好的方法之一就是阅读源代码；<br />
19.在任何时刻都不要认为自己手中的书已经足够了；<br />
20.请阅读《The Standard C++ Bible》(中文版：标准C++宝典)，掌握C++标准；<br />
21.看得懂的书，请仔细看；看不懂的书，请硬着头皮看；<br />
22.别指望看第一遍书就能记住和掌握什么——请看第二遍、第三遍；<br />
23.请看《Effective C++》和《More Effective C++》以及《Exceptional C++》；<br />
24.不要停留在集成开发环境的摇篮上，要学会控制集成开发环境，还要学会用命令行方式处理程序；<br />
25.和别人一起讨论有意义的C++知识点，而不是争吵XX行不行或者YY与ZZ哪个好；<br />
26.请看《程序设计实践》，并严格的按照其要求去做；<br />
27.不要因为C和C++中有一些语法和关键字看上去相同，就认为它们的意义和作用完全一样；<br />
28.C++绝不是所谓的C的“扩充”——如果C++一开始就起名叫Z语言，你一定不会把C和Z语言联系得那么紧密；<br />
29.请不要认为学过XX语言再改学C++会有什么问题——你只不过又在学一门全新的语言而已；<br />
30.读完了《Inside The C++ Object Model》以后再来认定自己是不是已经学会了C++；<br />
31.学习编程的秘诀是：编程，编程，再编程；<br />
32.请留意下列书籍：《C++面向对象高效编程（C++ Effective Object- Oriented Software Construction）》《面向对象软件构造(Object- Oriented Software Construction)》《设计模式（Design Patterns）》《The Art of Computer Programming》；<br />
33.记住：面向对象技术不只是C++专有的；<br />
34.请把书上的程序例子亲手输入到电脑上实践，即使配套光盘中有源代码；<br />
35.把在书中看到的有意义的例子扩充；<br />
36.请重视C++中的异常处理技术，并将其切实的运用到自己的程序中；<br />
37.经常回顾自己以前写过的程序，并尝试重写，把自己学到的新知识运用进去；<br />
38.不要漏掉书中任何一个练习题——请全部做完并记录下解题思路；<br />
39.C++语言和C++的集成开发环境要同时学习和掌握；<br />
40.既然决定了学C++,就请坚持学下去，因为学习程序设计语言的目的是掌握程序设计技术，而程序设计技术是跨语言的；<br />
41.就让C++语言的各种平台和开发环境去激烈的竞争吧，我们要以学习C++语言本身为主；<br />
42.当你写C++程序写到一半却发现自己用的方法很拙劣时，请不要马上停手；请尽快将余下的部分粗略的完成以保证这个设计的完整性，然后分析自己的错误并重新设计和编写（参见43）；<br />
43.别心急，设计C++的class确实不容易；自己程序中的class和自己的class设计水平是在不断的编程实践中完善和发展的；<br />
44.决不要因为程序“很小”就不遵循某些你不熟练的规则——好习惯是培养出来的，而不是一次记住的；<br />
45.每学到一个C++难点的时候，尝试着对别人讲解这个知识点并让他理解——你能讲清楚才说明你真的理解了；<br />
46.记录下在和别人交流时发现的自己忽视或不理解的知识点；<br />
47.请不断的对自己写的程序提出更高的要求,哪怕你的程序版本号会变成Version 100.XX；<br />
48.保存好你写过的所有的程序——那是你最好的积累之一；<br />
49.请不要做浮躁的人；<br />
50.请热爱C++!</p>
<h3  class="related_post_title">您可能还对这些文章感兴趣</h3><ul class="related_post"><li>四月 2, 2010 -- <a href="http://www.eduren.net/post/109.html" title="设置c++程序的堆栈空间解决栈溢出问题">设置c++程序的堆栈空间解决栈溢出问题</a> (0)</li><li>七月 14, 2009 -- <a href="http://www.eduren.net/post/44.html" title="vc++6.0中view消失的BUG">vc++6.0中view消失的BUG</a> (0)</li><li>五月 1, 2009 -- <a href="http://www.eduren.net/post/8.html" title="c++中的指针">c++中的指针</a> (0)</li><li>五月 1, 2009 -- <a href="http://www.eduren.net/post/3.html" title="VC++是如何编译的">VC++是如何编译的</a> (0)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.eduren.net/post/1.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

