您的位置:首页 > 其它

编译器肯定会为没有constructor的类生成一..

2012-01-24 07:57 204 查看
看完了《inside c++ object model》,接下来,就是亲自动手实践验证了。 依然记得大二时候那本清华大学出版社出版的C++教材,我用了2周时间就看完了,那时候的我还没有任何面向对象的思想,更别提项目经验了。感觉整个C++就是把C的struct扩充了一下,又加了点多态机制和泛型编程罢了(事实上,那时候对多态和泛型编程的概念也不是很清楚,只知道virtual和templete)。呵呵。。 而今看来很是自负啊。 事实上那本书虽然简单,但我却看过很多遍,在讲到构造函数时,书中有一条很明确的写到:“当一个类没有构造函数时候,那么编译器就会为它生成一个默认的构造函数”。 在我没有读到Lippman大牛的著作权,或许我会一直以为这是个永恒不变的真理。Lippman对于很多程序员的这一点认识如是评论道:

“C++新手一般有两个常见的误解:

1.任何class如果没有定义default construtor,就会被合成一个出来;

2.编译器合成出来的default constructor会明确设定class内每一个data member”

看看第一条,莫不是说那个写教科书的人也是个C++新手?呵呵。。

Lippman又明确解释道,编译器只有在需要的时候才会自动生成一个default constructor。至于什么时候是必要的时候:符合以下4点就是有必要的时候:

1.带有default constructor的成员class member object;

2.带有default constructor的基类;

3.带有virtual function;

4.带有vitrual base class。

Lippman对于这四点没有给出明确的验证实例,因为要验证一个编译器是否为一个类合成了default constructor,除了从汇编语言的角度来看汇编代码外,貌似没有其它任何方法了。。感叹自己汇编很弱,不能从汇编角度来分析,但幸运的是我在VS2008里面无意中发现了一种验证方法。先来看看如下代码:(这点简单代码能验证上述4个条款)

#include <iostream>

using namespace std;

class BaseClass
{
public:
int a;
int b;
//virtual void showClassInfo(){};
//BaseClass(){}
};

class DerivedClass:public BaseClass
{
public:
int c;
};

int main(int *argc,char **argv)
{
BaseClass baseClass;
//cout<<baseClass.a<<" "<<baseClass.b<<endl;
cout<<sizeof(baseClass)<<endl;
DerivedClass derivedClass;
//cout<<derivedClass.c<<endl;
cout<<sizeof(derivedClass)<<endl;
return 0;
}


得出的结果将会是:8 12

这证明类的nonstatic data member被正确的申请了内存空间。而如果我们去掉:

//cout<<baseClass.a<<" "<<baseClass.b<<endl;

这行的注释,会出现runtime error. 给出的提示信息为:the variable “baseClass”is being used without being initialized.(baseClass未进行初始化),我假设这句话意图在指出这个异常是由于baseClass没有设定默认的构造函数,而并不是因为没有给baseClass.a和baseClass.b赋初值,为了验证这一点,我加了一个什么也没做的构造函数,去掉

//BaseClass(){}

这一行的注释,那么得出的结果会是:

-858993460 -858993460

8

12

此时程序没有任何异常。验证了我之前的假设是对的。构造函数的确没有给baseClass的data member做初始化操作,而却得以正常运行。

如果我们将上述代码中的这一样注释掉:(注意BaseClass的构造函数此时是注释掉的)

//virtual void showClassInfo(){};

这行代码的注释去掉,那么程序会照样正常运行,得出的结果会是:

-858993460 -858993460

12

16

此时baseClass中隐含了一个vptr指向virtual function table,造就了baseClass的重新布局(增加了4个byte)。对于C++对象布局,可以看看我之前的一篇博文“点击这里” 。这也就验证了Lippman所说的第三条。为了验证第四条,我们将上述代码中的这一行:

//cout<<derivedClass.c<<endl;

注释去掉,此时又会出现runtime error.而给出的信息为:the variable “derivedClass”is being used without being initialized.(derivedClass未进行初始化)。证明编译器又没有为非vitual继承的derived class合成默认的构造函数。 那么正常的virtual 继承会出现什么状况呢?再试着将这行代码

class DerivedClass:public BaseClass

改为如下:

class DerivedClass:virtual public BaseClass

(注意//cout<<derivedClass.c<<endl;的注释是去掉的)

程序又将会正常运行,而且得出的结果是:

8

-858993460

16

如此便验证了第四条。

至此,第一条和第二条的验证方法也就没必要再说下去了,大同小异。

最后,不得不感叹国外教科书作家Lippman和国内教科书作家的的差异。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐