默认构造函数在被需要的时候被编译器产生出来。
这句话的关键部分是:
- 被谁需要?
- 什么时候被需要?
- 做什么事情?
被谁需要?
编译器为程序构建默认构造函数是因为编译器需要它,而不是因为程序需要它。程序需要什么应该是程序员的责任,应该由程序员提供。举个例子,例如下面这段代码:
class Foo {
public:
int val;
Foo* pnext;
}
void foo_bar() {
Foo bar;
// 程序需要 bar's members 都被初始化为 0
if (bar.val || bar.pnext) {
// do something
}
}
该段程序的正确语意是希望 Foo 的默认构造函数将 val 和 pnext 初始化为 0,但此处编译器并不会为 Foo 生成默认构造函数,因为这里不满足“需要的时候“这个条件,程序需要不代表编译器需要。后面我们会了解到就算此处编译器为 Foo 生成了默认构造函数,该默认构造函数也不会对 val 和 pnext 进行初始化,具体原因请看“做什么事情?”部分。
什么时候需要?
上面解释了默认构造函数是被编译器需要的,那么编译器什么时候需要它呢?在下列四种情况下编译器会生成默认构造函数:
-
class内包含有default constructor的member object,合成default constructor为了调用member object的default constructor。 -
class继承自含有default constructor的基类,合成default constructor为了调用基类的default constructor。 - 带有虚函数的
class,合成default constructor主要为了初始化vptr(虚函数表指针)。 -
class有一个及以上的虚基类,合成default constructor主要为了初始化虚基类指针。
当满足上面的条件时,编译器会对 constructor 进行扩展,扩展的规则如下:
- 当
class没有定义constructor,编译器会合成default constructor,并加入编译器需要的操作,可能包括调用member object的default constructor,调用基类的default constructor,初始化虚函数表指针及虚基类指针。 - 当
class已经定义了一个或多个constructor时,编译器不会再去合成constructor,但会扩展所有constructor加入编译器需要的操作。
做什么事情?
从上面的分析中可以看出,默认构造函数所做的事情用一句话可以概括:只执行编译器所需要的行为。所以说即使编译器为 Foo 生成了默认构造函数,该默认构造函数也不会对 val 和 pnext 进行初始化,因为编译器并不需要该行为,这是程序员应该做的事情。
总结:
编译器只合成他需要的 default constructor 并且只做他需要的操作。C++ 新手常见的两个 误解 :
- 任何
class如果没有定义default constructor,就会被合成出一个来。 - 编译器合成出来的
default constructor会明确设定class内每一个data member的默认值。
其实做为一个学习者,有一个学习的氛围跟一个交流圈子特别重要这里我推荐一个C/C++基础交流583650410,不管你是小白还是转行人士欢迎入驻,大家一起交流成长。













网友评论