C++构造函数语意学——默认构造函数

概述

在 class 中,若程序员没有为该 class object 定义 default constructors,则编译器会根据需要产生一个 implicit default constructor,该 implicit default constructor 被认为是 trivial(无用的)。那编译器怎样才能产生一个 nontrivial implicit default constructor?以下四个方面会产生nontrivial implicit default constructor:

  1. class 中存在带有 default constructor 的 member class object(成员对象);
  2. class 继承自带有 default constructor 的 base class(基类);
  3. 带有一个 virtual function 的 class;
  4. 带有一个 virtual base class 的 class;

带有 default constructor 的 member class object

若一个 class 中没有定义任何 constructor,但是 class 中存在带有 default constructor 的 member class object,则编译器会在需要的时候合成一个 nontrivial implicit default constructor;例如:

#include <iostream> 

using namespace std;  

class Foo {  
public:  
    Foo() { cout << "The constructor of Foo was exist." << endl; }    
};  

class Bar {  
public:  
    Foo foo;  
    int x;  
};  

int main()  
{  
    Bar bar;  
    if(bar.x)
    {
        cout<<"The value of x is: "<<bar.x<<endl;
    }  
    return 0;  
}  

使用 gdb 调试结果如下所示:

(gdb) r
Starting program: /ObjectModel/chap02/test 

Breakpoint 1, main () at test.cpp:18
18      Bar bar;  
(gdb) s
Bar::Bar (this=0xbffff038) at test.cpp:10
10  class Bar {  
(gdb) s
Foo::Foo (this=0xbffff038) at test.cpp:7
7       Foo() { cout << "The constructor of Foo was exist." << endl; }    
(gdb) s
The constructor of Foo was exit.
main () at test.cpp:19
19      if(bar.x)
(gdb) s
21          cout<<"The value of x is: "<<bar.x<<endl;
(gdb) s
The value of x is: -1209307148
23      return 0;  

从调试结果可以知道,执行Bar bar语句时,编译器会合成一个 Barnontrivial implicit default constructor,合成的 Barnontrivial implicit default constructor 内含必要的代码,能够调用 class Foo的 default constructor 来处理 member class objectBar::foo,但是并不会产生代码来初始化 Bar::x,将Bar::foo初始化是编译器所做的事,而初始化Bar::x则是程序编写者的事情;编译器会合成一个 Barnontrivial implicit default constructor 类似如下代码所示:

inline Bar::Bar()
{ foo.Foo::Foo(); }

由于编译器合成的 Barnontrivial implicit default constructor 并没有对 Bar::x进行初始化,因此,被合成的 nontrivial implicit default constructor 只是满足编译器的需求,并不是程序员的需求,若要满足程序员需求必须初始化 Bar::x,例如:

Bar::Bar(){x=0;}

上面显示的默认构造函数,编译器同样会初始化 member class objectfoo,即相当于:

Bar::Bar()
{
 foo.Foo::Foo();
    x = 0;
}

class A内含一个或一个以上的 member class objects,则class A的每一个 constructor 必须安装声明的顺序调用每一个 member classes 的 default constructor。例如:

#include <iostream> 

using namespace std;  

class A {  
public:  
    A() { cout << "class A" << endl; }  
};  

class B {  
public:  
    B() { cout << "class B" << endl; }  
};  

class C {  
public:  
    C() { cout << "class C" << endl; }   
};  

class D{
public:
    B b;
    A a;
    C c;
public:
    int x;
};

int main(void)  
{  
    D c;  
    if(c.x)
    {
        cout<<"noninitial the x "<<endl;
    }
    return 0;  
}  

输出结果:从结果可知道,编译器合成的 nontrivial implicit default constructor 会按照 member objects 在 class 中的声明顺序调用各个 constructors。

(gdb) r
Starting program: /ObjectModel/chap02/test 

Breakpoint 1, main () at test.cpp:31
31      D c;  
(gdb) s
D::D (this=0xbffff038) at test.cpp:20
20  class D{
(gdb) s
B::B (this=0xbffff038) at test.cpp:12
12      B() { cout << "class B" << endl; }  
(gdb) s
class B
A::A (this=0xbffff039) at test.cpp:7
7       A() { cout << "class A" << endl; }  
(gdb) s
class A
C::C (this=0xbffff03a) at test.cpp:17
17      C() { cout << "class C" << endl; }   
(gdb) s
class C
main () at test.cpp:32
32      if(c.x)
(gdb) s
34          cout<<"noninitial the x "<<endl;
(gdb) s
noninitial the x 
36      return 0; 

带有 default constructor 的 base class

若一个没有任何 constructors 的 class 继承一个带有 default constructor 的 base class,那么编译器合成的 derived class 的 default constructor 也是 nontrivial 的,它将按照顺序调用 base class 的 default constructor;

#include <iostream> 

using namespace std;  

class BaseClass {  
public:  
    BaseClass() { cout << "Base class" << endl; }  
};  

class Foo {  
public:  
    Foo() { cout << "class Foo" << endl; }   
};  

class Bar: public BaseClass {  
public:  
    Foo foo;  
    int x;  
};  

int main()  
{  
    Bar bar;  
    if(bar.x)
    {
        cout << bar.x<<endl;
    }  
    return 0;  
}  

输出结果如下所示:Bar 继承自 BaseClass 基类,而且包含一个 Foo 成员对象,编译器合成一个默认构造函数,该默认构造函数先调用基类的默认构造函数,再调用成员对象的默认构造函数。

(gdb) r
Starting program: /ObjectModel/chap02/test 

Breakpoint 1, main () at test.cpp:23
23      Bar bar;  
(gdb) s
Bar::Bar (this=0xbffff038) at test.cpp:15
15  class Bar: public BaseClass {  
(gdb) s
BaseClass::BaseClass (this=0xbffff038) at test.cpp:7
7       BaseClass() { cout << "Base class" << endl; }  
(gdb) s
Base class
Foo::Foo (this=0xbffff038) at test.cpp:12
12      Foo() { cout << "class Foo" << endl; }   
(gdb) s
class Foo
main () at test.cpp:24
24      if(bar.x)
(gdb) s
26          cout << bar.x<<endl;
(gdb) s
-1209307148
28      return 0;

带有一个 virtual function 的 class

当 class 内声明或继承一个 virtual function,编译器会根据需要合成一个 nontrivial default constructor,在编译期间会进行以下扩充:

  • 编译器产生一个存放 class 的 virtual functions 地址的 virtual function table(vtbl);
  • 在每一个 class object 中,会存在一个指向该 vtbl 的 pointer member(vptr);

编译器会为每一个 class 或其派生类 object 的 vptr 设定初值,放置适当的 virtual table 地址。

带有一个 virtual base class 的 class

virtual base class 中的 data member 能够通过 derived class object 进行读取,同时 virtual base class 只有一个实例,编译器在合成 default constructor 时,每个derived class object 必须要记录 virtual base class 地址的信息,即每个 derived class object 保存有指向 virtual base class 地址的指针。例如:

#include <iostream> 

using namespace std;  

class X {  
public:  
    int x;  
};  

class A: public virtual X {public: int i;};  

class B: public virtual X {public: int j;};  

class C: public virtual A, public virtual B {public: int k;};  

int main()  
{  
    C c;  
    A a;  
    B b;  

    cout <<"first level derived A:"<< a.x << endl;  
    cout <<"first level derived B:"<< b.x << endl;  
    cout <<"second level derived C:"<< c.x << endl;  
    cout <<"second level derived C->A:"<< c.A::x << endl;  
    cout <<"second level derived C->B:"<< c.B::x << endl;  

    return 0;  
}  

输出结果:不同 derived class object 中virtual base class 不是共享的,而同一继承层次中的 virtual base class 是共享的。对象a、b、c 都需要存储各自virtual base class 的地址。因此编译器会在每个对象中产生指向 virtual base class 地址的指针,指向 virtual base class X,对 virtual base class 读取操作在执行期间才能确定的。

(gdb) r
Starting program: /ObjectModel/chap02/test 

Breakpoint 1, main () at test.cpp:18
18      C c;  
(gdb) s
C::C (this=0xbffff024, __in_chrg=<optimized out>, __vtt_parm=<optimized out>)
    at test.cpp:14
14  class C: public virtual A, public virtual B {public: int k;};  
(gdb) s
X::X (this=0xbffff034) at test.cpp:5
5   class X {  
(gdb) s
A::A (this=0xbffff02c, __vtt_parm=0x8048c1c <VTT for C+12>, 
    __in_chrg=<optimized out>) at test.cpp:10
10  class A: public virtual X {public: int i;};  
(gdb) s
B::B (this=0xbffff038, __vtt_parm=0x8048c20 <VTT for C+16>, 
    __in_chrg=<optimized out>) at test.cpp:12
12  class B: public virtual X {public: int j;};  
(gdb) s
main () at test.cpp:19
19      A a;  
(gdb) s
A::A (this=0xbffff00c, __in_chrg=<optimized out>, __vtt_parm=<optimized out>)
    at test.cpp:10
10  class A: public virtual X {public: int i;};  
(gdb) s
X::X (this=0xbffff014) at test.cpp:5
5   class X {  
(gdb) s
main () at test.cpp:20
20      B b;  
(gdb) s
B::B (this=0xbffff018, __in_chrg=<optimized out>, __vtt_parm=<optimized out>)
    at test.cpp:12
12  class B: public virtual X {public: int j;};  
(gdb) s
X::X (this=0xbffff020) at test.cpp:5
5   class X {  
(gdb) s
main () at test.cpp:22
22      cout <<"first level derived A:"<< a.x << endl;  
(gdb) n
first level derived A:-1210826250
23      cout <<"first level derived B:"<< b.x << endl;  
(gdb) n
first level derived B:1
24      cout <<"second level derived C:"<< c.x << endl;  
(gdb) n
second level derived C:0
25      cout <<"second level derived C->A:"<< c.A::x << endl;  
(gdb) n
second level derived C->A:0
26      cout <<"second level derived C->B:"<< c.B::x << endl;  
(gdb) n
second level derived C->B:0
28      return 0;  

总结:

当 class 中没有显式声明 default constructor,若是上述四种情况之一,编译器会根据需要合成 nontrivial default constructor。但是编译器不会初始化 class 中 nonstatic data member,只会初始化 base class subobjects 和 member class objects;

你可能感兴趣的:(C++,构造函数,C++对象模型,构造语意学)