2.1 Default Constructor的建构操作

1.   存在错误的程序例子

class Foo
{
public:
 int m_nVal;
 Foo *m_pNext;
};

void Foo_Bar( void )
{
 Foo bar;
 
 if ( bar.m_nVal || bar.m_pNext )
 {
  int i;
  i++;
 }
}

(1)正确的程序语意是要求 Foo 有一个 default constructor,可以将 members 初始化为0。

(2)上述代码不会合成一个 default constructor,即使编译器有需要而合成一个 constructor,也只执行编译器所需的操作,而不会把 members 初始化为0。

(3)改正方法是,程序员提供一个 default constructor,并把 members 初始化。

2.    C++ Standard[ISO-C++95] 的 Section 12.1

对 class X,没有 user-declared constructor,则会有一个 default constructor 被 implicitly(隐含) 声明出来,这个 constructor 是 trivial(没有用的) 的。

3.    带有 “default constructor” 的 member class object

(1)一个 class 没有 constructor,但有一个 member object,后者有 default constructor,则这个 class 的 implicit default constructor 就是 nontrivial。编译器只有在 constructor 真正需要被调用时合成一个 default constructor。

(2)为避免在不同的编译模块中合成多个 default constructor,合成的 default constructor、copy constructor、destructor、assignment copy operator 都以 inline 方式合成。不适合做成 inline 时,会合成一个 explicit non-inline static 实体。

(3)案例分析

class Foo 
{ 
public: 
    Foo();
};

class Bar
{
public:
    Foo m_foo;
    int   m_pVal; 
};

void Func( void )
{
    Bar bar; // Bar::m_foo 此处需被初始化
}

// 被合成的 default constructor
inline Bar::Bar( void )
{
    // 调用 class Foo 的 default constructor。初始化 Bar::m_foo 是编译器的责任。
    m_foo.Foo::Foo();
    // m_pVal 不会被初始化。是程序员的责任。
}

// 存在 user-declared constructor 时,
// constructor 会被扩张,在 user code 前,以“member 声明次序”调用必要的 default constructors
Bar::Bar( void )
{
    m_foo.Foo::Foo();
    m_pVal = NULL;
}

4.    带有“default constructor”的 base class

(1)一个没有 constructor 的 class 派生自带有 default constructor 的 base class,则这个 derived class 的 default constructor 是 nontrivial,且需要被合成。将调用 base class  的 default constructor。对后继派生的 class,这个合成的 constrcutor 相当于 user-declared constrcutor。

(2)有多个 constructor,但是没有 default constructor 时,编译器会扩展现有的每一个 constructor,添加所需要的 member default constructor,而不会合成 default constructor。

(3)先调用 base class constructor,后调用 member class objects 的 default constructors。

5.    带有一个“vritual function”的 class

(1)两种情况下,也需要合成 default constructor

a.    class 声明(或继承)一个 virtual function。

b.    class 派生自一个继承串链其中有一个或更多的 virtual base class。

(2)案例分析

class Widget
{
public:
    virtual void flip(void) = 0;
};

void flip( const Widget &widget )
{
    // 此操作被重写,( *widget.vptr[1] )( &widget )
    // “1”表示 flip() 在 vtbl 中的索引。
    // &widget 表示要交给“被调用的某个 flip() 函数实体”的 this 指针。
    widget.flip();
}

void Func( void )
{
    Bell b;        // Bell、Whistle 继承 Widget
    Whistle w;
    flip(b);
    flip(w);
}

编译期间会发生两个扩展操作:

a.    一个 vtbl 被编译器产生,放 class 的 virtual functions 的地址。

b.    每个 class object 中,一个 vptr 被编译器合成,放 vtbl 的地址。

对 class 的每个 user-delcared constructor,编译器会添加一些代码来完成这两个操作。

而没有任何 constructor 时,编译器会合成 defalut constructor,来正确初始化 vptr。

6.    带有一个“virtual base class”的 class

(1)virtual base class 的实现法在不同的编译器间有极大的差异。但是每种实现法的共同点是必须使 virtual base class 在其每一个 derived class object 中的位置,能够在执行期间准备妥当。

7.    总结

(1)四种情况下,编译器会为未声明 constructor 的class 合成一个 default constructor。

(2)C++ standard 把那些合成物称为 implicit nontrivial default constrcutors。

(3)被合成的 constructor 只能满足编译器的需要,是借助“调用 member object 或 base class 的 default constructor”、“为每个 object 初始化 virtual function 机制或 virtual base class 机制”而完成的。

(4)对不存在那四种情况,有没有任何 constructor 的 class,拥有的是 implicit trivial defatule constructor,实际上不会被合成出来。

(5)在合成的 default constructor 中,只有 base class subobjects 和 member class objects 会被初始化,其他 nonstatic data members 不会被初始化。

时间: 2024-08-05 20:20:00

2.1 Default Constructor的建构操作的相关文章

C++对象模型——Default Constructor的建构操作(第二章)

第2章    构造函数语意学 (The Semantics of Constructor) 关于C++,最常听到的一个抱怨就是,编译器背着程序员做了太多事情.Conversion运算符就是最常被引用的一个例子. 2.1    Default Constructor的建构操作 C++ Annotated Reference Manual(ARM)指出"default constructors ...在需要的时候被编译器产生出来".关键字眼是"在需要的时候".被谁需要?

C++对象模型——Copy Constructor 的建构操作(第二章)

2.2    Copy Constructor 的建构操作 有三种情况,会以一个object的内容作为另一个 class object的初值,最明显的一种情况就是对一个object做显式的初始化操作,例如: class X { ... }; X x; // 明确地以一个object的内容作为另一个class object的初值 X xx = x; 另两种情况是当object被当作参数交给某个函数时,例如 extern void foo(X x); void bar() { X xx; // 以x

构造函数语义学——Copy Constructor的建构操作

?在三种情况下,会以一个object的内容作为另一个class object的初值: object明确初始化 123 class {...};X x;X xx = x; object被当作参数交与某个函数 12345 extern void foo(X x);void bar(){ X xx; foo(xx);} 函数返回值是一个class object 12345 X foo_bar(){ X xx; ... return xx;} 如果开发者已经明确定义了一个copy constructor

Default Constructor的构建操作

在<C++ Annotated Reference Manual(ARM)[ELLIS90]>中的Section 12.1告诉我们:"Default constructors...在需要的时候被编译器产生出来". 其实默认构造函数也是分为两类的:有用的(nontrivial ).无用的(trivial ). 所谓有用的标准也是就默认构造函数会为我们的类做一些初始化操作.那么无用的就不会做任何工作,从而对我们的类也就没有任何意义. 所以,我们通常所说的默认构造函数是指有用的默

深度探索C++对象模型之第二章:构造函数语意学之Default constructor的构造操作

C++新手一般由两个常见的误解: 如果任何class没有定义默认构造函数(default constructor),编译器就会合成一个来. 编译器合成的的default constructor会显示的设定“class内每一个data member的默认值” 一.编译器在哪种情况下才会合成默认构造函数: 对于未声明构造函数的类,只有在以下四种情况下编译器才会为它们合成默认构造函数: 类的成员有一个类对象(Member Class Object),且该成员含有默认构造函数(default Const

第二章---Default constructor 的构建操作

成员对象的构造顺序 C++语言要求"member objects "在class 中的声明次序"来调用各个构造器.这一点由编译器完成. 带有"Default Constructor" 的 Base Class 带有一个"Virtual Function" 的  Class 带有一个Virtual Base Class 的Class        virtual base class 的实现法在不同的编译器之间有极大的差异.但是有一个共通

深入探索C++对象模型-&gt;2.1 Default Constructor的构造操作

一.对于class X,有四种情况,会造成“编译器必须为未声明constructor的classes合成一个default constructor或者扩充user-constructor”,对于其它情况,编译器什么也不做,如果程序需要,那是程序员的责任. 1.带有Default Constructor的Member Class Object:“如果class A内含一个或一个以上的member class objects,那么编译器会为没有构造函数的类添加构造函数来调用每一个member cla

重温《Inside The C++ Object Model》(2) --Default-Constructor的建构操作

//constructor/non-constructor的区别 class Foo { public: //Foo():val(0),next(NULL) {} int val; Foo *next; }; void foo_bar() { Foo bar; if ( bar.val && bar.next ) { cout << bar.val << endl; printf("%p\n", bar.next); cout <<

深度探索C++对象模型-----编译器’何时‘自动合成nontrivial default constructor

有4种情况,会造成"编译器必须为 未申明constructor的classes合成default constructor. 1.带有default constructor的member class object 如果一个class没有任何constructor,但是内含一个member object ,而后者有default constructor,那么这个class的implicit default constructor就是 nontrivial,编译器需要为改class合成出一个defau