很多C++的教材中都讲:“如果一个定义一个类,并且不提供任何构造函数的话,那么编译器将会隐式的提供一个缺省构造函数”。
以下节录ISO C++ 99的文档的原文:
The default constructor (12.1), copy constructor and copy assignment operator (12.8), and destructor (12.4)
are special member functions. The implementation will implicitly declare these member functions for a
class type when the program does not explicitly declare them, except as noted in 12.1. The implementation
will implicitly define them if they are used, as specified in 12.1, 12.4 and 12.8.
A default constructor for a class X is a constructor of class X that can be called without an argument. If
there is no user-declared constructor for class X, a default constructor is implicitly declared. An implicitly-
declared default constructor is an inline public member of its class.
An implicitly-declared default constructor for a class is implicitly defined when it is used to create an object
of its class type (1.8). The implicitly-defined default constructor performs the set of initializations of the
class that would be performed by a user-written default constructor for that class withan empty meminitializer-list (12.6.2) and an empty function body. If that user-written default constructor would be illformed,the program is ill-formed. Before the implicitly-declared default constructor for a class is implicitly
defined, all the implicitly-declared default constructors for its base classes and its nonstatic data members
shall have been implicitly defined. [Note: an implicitly-declared default constructor has an exceptionspecification(15.4).
以下摘录自“孙鑫vc教程的勘误表”:
我说:“C++又规定,如果一个类没有提供任何的构造函数,则C++提供一个默认的构造函数(由C++编译器提供)”,这句话也是错误的,正确的是:
如果一个类中没有定义任何的构造函数,那么编译器只有在以下三种情况,才会提供默认的构造函数:
1、如果类有虚拟成员函数或者虚拟继承父类(即有虚拟基类)时;
2、如果类的基类有构造函数(可以是用户定义的构造函数,或编译器提供的默认构造函数);
3、在类中的所有非静态的对象数据成员,它们对应的类中有构造函数(可以是用户定义的构造函数,或编译器提供的默认构造函数)。
C++ Primer(第3版) 14.2中也有这样的话:
新用户常常会错误地认为:如果不存在缺省构造函数,则编译器会自动生成一个缺省构
造函数,并将其应用在对象上,以初始化类的数据成员,对于我们定义的Account 类来说这
就不是真的,系统既没有生成缺省构造函数也没有调用它。对于含有类数据成员或继承来的
比较复杂的类,这在部分上是对的,可能会生成一个缺省构造函数,但是它不会为内置或复
合型的数据成员如指针或数组提供初始值。
也可以从底层分析一下:
class A { public: int a; char *ptr; }; int main() { A a; return 0; }
这种代码不会产生默认的ctor,此时的类就貌似C下面的struct,没有一个成员需要初始化。
证据1:
97: int main() 98: { 0040D680 push ebp 0040D681 mov ebp,esp 0040D683 sub esp,48h 0040D686 push ebx 0040D687 push esi 0040D688 push edi 0040D689 lea edi,[ebp-48h] 0040D68C mov ecx,12h 0040D691 mov eax,0CCCCCCCCh 0040D696 rep stos dword ptr [edi] 99: A a; //什么都没做 100: return 0; 0040D698 xor eax,eax 101: } 0040D69A pop edi 0040D69B pop esi 0040D69C pop ebx 0040D69D mov esp,ebp 0040D69F pop ebp 0040D6A0 ret
但是,
(1)如果加入需要构造函数的成员变量,则默认的ctor就会被调用,比如加入std::string
#include <string> class A { public: int a; char *ptr; std::string test; }; int main() { A a; return 0; }
int main() 99: { 0040D680 push ebp 0040D681 mov ebp,esp 0040D683 sub esp,5Ch 0040D686 push ebx 0040D687 push esi 0040D688 push edi 0040D689 lea edi,[ebp-5Ch] 0040D68C mov ecx,17h 0040D691 mov eax,0CCCCCCCCh 0040D696 rep stos dword ptr [edi] 100: A a; 0040D698 lea ecx,[ebp-18h];this指针 0040D69B call @ILT+35(A::A) (00401028);默认的ctor被调用 101: return 0; 0040D6A0 mov dword ptr [ebp-1Ch],0 0040D6A7 lea ecx,[ebp-18h] 0040D6AA call @ILT+40(A::~A) (0040102d) 0040D6AF mov eax,dword ptr [ebp-1Ch] 102: } 0040D6B2 pop edi 0040D6B3 pop esi 0040D6B4 pop ebx 0040D6B5 add esp,5Ch 0040D6B8 cmp ebp,esp 0040D6BA call __chkesp (00401170) 0040D6BF mov esp,ebp 0040D6C1 pop ebp 0040D6C2 ret
(2)有虚函数的存在,也将调用默认的ctor,比如:
class A { public: int a; char *ptr; virtual void dd(){a=1;} }; int main() { A a; return 0; }
相应的Assembly
100: A a; 00401048 lea ecx,[ebp-0Ch] 0040104B call @ILT+15(A::A) (00401014);这里面主要是将虚函数表首地址放入前面4个字节
可以总结得出:编译器总是在需要ctor的时候,而用户没提供ctor的时候,才产生默认的ctor。这么做可以产生最优的效率。