隐藏在default construct后面的是什么
C++新手很容易陷入两个认识上的误区:
1.任何类如果不显示的定义一个构造函数那么编译器就会构造出一个默认构造函数。
2.默认构造函数负责类的所有数据成员的初始化,显然不是这样的。
为什么不是这样的,下面来进行详细的说明和解答,下面会说明在什么情况下一种有用的构造函数会被编译器构造出来。
类的默认构造函数:default construct,一个c++类什么时候需要构造出一个默认的构造函数,答案是在编译器需要的时候,这里指的是编译器需要的时候,举个例子。
Class Foo
{
Public :
Foo * pNext;
char * str;
}
在这个例子里面对象成员的初始化不应该交给编译器来做,因为对于类的对象的初始化是程序需要考虑的事情,当然也需要交由Foo类的构造者来完成。比如
Foo :: Foo()
{
Str = 0;
pNext =NULL;
}
- 默认构造函数由编译器声明分为多种的情形,其中情形一位:当一个类之中含有了一个已经存在默认构造函数其他类的对象时,那么这个类就需要声明出默认的构造函数来完成类的成员对象的初始化。
Class Foo
{
Public :
Foo ();
Foo(int);
}
Class Bar
{
Public :
Foo foo;
Char * str;
}
此时就需要类的构造函数来进行Foo类对象的初始化,这里再次分为两种情况,第一种就是Bar类的构造着不进行显示的构造函数编写,那么就会由编译器来进行默认构造函数的构建就像下面这样,编译器默认的构造函数只负责foo对象的初始胡他并不会负责str的初始化。
Bar::bar()
{
Foo.Foo::Foo();
}
当Bar类的构造着显示的声明了一个构造函数的时候编译器在用户代码之前也会负责进行Foo对象的初始化就像下面一样。
用户代码:Bar::bar()
{
Str = 0;
}
编译器添加了初始化代码之后的结构:
Bar::bar()
{
//在用户代码之前编译器必须负责构造foo对象
// Foo.Foo::Foo();
Str = 0;
}
需要注意的是当一个类包含了多个其他类的成员对象的时候需要按照顺序进行类的对象初始化向下面的例子。
Class point {public : point()}
Class line {public: line(); line(int)}
Class shape {public: shape()……}
Class test
{
Public :
Point m_point;
Line m_line;
Shape m_shape;
Private :
Int m_ival;
}
显示的构造函数,用户代码:test::test():line(1024)
{
M_ival = 0;
}
编译器代码:
Test:test():line(1024)
{
//首先需要对对象point和shape进行初始化,这些操作都将由编译器完成
//Point:point::point();
Line:line::line(1024);
//Shape.shape::shape();
M_ival = 0;
}
2.带有默认构造函数的基类
带有默认构造函数的基类,对于这种类型的构造函数和之前提到过的相似,因为派生类对象在构造之前必须要先构造出基类的构造函数,所以编译器在编译阶段会进行代码扩展,将基类的默认构造函数添加到派生类的构造函数代码中。
3.基类含有vritual function 的派生类对象
因为这种类型的类编译器在编译阶段需要产生一个虚表vtab和一个指向vtab的虚表指针vptr,vptr内含虚表的地址值。出于这种考虑如果用户不声明一个构造函数,那么编译器必须合成出一个默认的构造函数来进行每一个对象的虚表指针vptr的初始化。
4.含有virtual class 的派生类
和上面的道理一样,编译器也必须产生出一个指向虚基类的指针进行虚基类成员的操作,这个阶段就发生在默认构造函数中。