您的位置:首页 > 编程语言 > C语言/C++

深度搜索C++对象模型 - 构造函数

2014-09-21 09:23 288 查看

深度搜索C++对象模型: 构造函数

Default Constructor 构造函数:

C++ARM告诉我们: Default Constructor在需要的时候被编译器产生出来.

关键字: 在需要的时候 --> 被谁需要 需要来干什么?

例子:

class Foo

{

 public:

  int m_val;

  Foo *next;

};

void FooBar()

{

 Foo bar;

 if( bar.m_val || bar.next )

 {

  //do something

 }

}

这个程序本身的语义是:要求Foo有一个默认的构造函数, 可以将内部的两个data member初始化为0;

但是实际上结果是不符合语义的; 他可曾符合ARM所说? 答案是no;

其间最重要的一点是:  被程序需要 ?  被编译器需要 ?

很自然 把两个data member初始化为0, 这是程序的需要, 这是需要程序员保证的;

而对于编译器来说 他根本就没有被需要; ( 所以根本不会有默认构造函数, 后面会讲 )

//*********************************************************************************************//

对于编译器来说 "被编译器需要的 有用的默认构造函数" 有4种 分别介绍:

//-----------------------------------------------------------------------------------------------------------------------//

---> "含有 带有Default Constructor 的 Member Class Object 的 class":

如果一个Class内没有任何Constructor, 但是他内含一个Member Class Object, 而且这个Mmeber Class Object有Default Constructor,

那么这个Class的隐式默认构造函数就是有用的;

例子:

class Foo

{

 public:

  Foo();

};

class Bar

{

 public:

  Foo foo;

  char *str;

};

这种情况下, Bar里内含了一个成员类对象, 而且这个成员类对象含有默认构造函数, 那么编译器就会为class Bar合成一个默认构造函数;

当我们 Bar bar;的时候 Bar::foo 必须在此处被初始化, 被合成的Bar的默认构造函数内含必要的代码,能够调用class Foo的默认构造函数来初始化foo;

但是他并不产生任何代码来初始化str;  所以"将Bar::foo初始化是编译器的责任, 但是将Bar::str初始化是程序员的责任";

被合成的Bar的默认构造函数也许像这样:

inline

Bar::Bar()

{

 foo.Foo::Foo();

}

重申: "被合成的默认构造函数是编译器的需要 不是程序的需要";

至此 编译器的需要已经满足了, 所以我们要来满足程序的需要, 所以我们需要一个"显式默认构造函数"

Bar::Bar()

{

 str = nullptr;

}

此时, 程序的需要满足了 但是编译器还需要初始化member object foo ;

但是程序无法再次定义一个默认构造函数 因为我们已经显式的定义了一个,

此时 编译器行动如下: 如果class A内含一个或一个以上的member class object,

那么class A的"每一个构造函数"都会调用"每一个member calss object的默认构造函数";

编译器会扩张已存在的构造函数, 在其中安插一些代码, 使得我们user使用之前先执行默认构造,

如上 扩张后的默认构造函数可能如下:

Bar::Bar()

{

 foo.Foo::Foo();

 str = nullptr;

}

如果有多个member class object 则会按照声明的顺序来调用默认构造函数,

例如:

class A{ public: A(); };

class B{ public: B( int ); };

class C{ public: C(); };

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

如上: class D没有定义默认构造函数 则会有一个"有用的默认构造函数"被合成出来;

D::D() : b( 1024 )

{

 num = 2048;

}

那么他也许会被扩张为:

D::D : b( 1024 )

{

 a.A::A();

 b.B::B( 1024 );

 c.C::C();

 num = 2048;

}

//-----------------------------------------------------------------------------------------------------------------------//

---> "带有Default Constructor 的 Base Class":

如果一个没有任何constructor的class派生自一个"带有Default Constructor"的 base class,

那么这个 derived class 的默认构造函数为有用的;

例子:

class A{ public: int num_a; };

class B{ public: A a; int num_b; };

class C : public B

对于这个例子, class B是一个上文的 "含有 带有Default Constructor 的 Member Class Object 的 class";

那么 class C 派生自 class B; 那么 class C 的默认构造函数为有用的;

他将调用上一层( class B ) 的 "默认构造函数" 来 "构造其内含的 Member Class Object";

如果设计中提供多个构造函数,但是其中都"没有默认构造函数",

编译器会遍历所有构造函数, 内插上一层( class B )的构造函数 ( class B的构造函数又内插了Member Class Object的构造函数 );

//-----------------------------------------------------------------------------------------------------------------------//

---> "带有一个 Virtual Function 的 class":

对于一个 带有 virtual Function 的 class , 他的默认构造函数为有用的;

而一个 class 带有virtual Function 分为两种情况:

其一: 类申明( 或继承 ) 一个 virtual function;

其二: class 派生自一个继承串链, 其中有一个或多个 virtual base class ;

例子:

class Widget

{

 public:

  virtual void Func( const Wieget &idget ) = 0;

};

class Bell : public Widget

class Whistle : public Widget

Bell b;

Whistle w;

Func( b );

Func( w );

"两个扩张行动" 会在编译期间发生:

-> 一个 virtual function table ( vtbl )会被编译器产生出来, 其中存放着 class 的 virtual functions 地址;

-> 在每一个 class object 中, 一个额外的 pointer member ( vptr )会被编译器合成出来 内含有 virtual function table 的地址;

此外 weidget.Func() 的虚拟调用操作将被改写, 以使用 widget 的 vptr 和 vtbl 中的 Func() 条目;

为了让这个 "virtual function 机制" 发挥作用, 编译器必须"为每一个Widget Object 和 其派生类的Object 设置 vptr 的初值 放置适当的 vtbl地址";

对于 class 的每一个 Constructor ,编译器会安插一些代码来完成这个操作;

//-----------------------------------------------------------------------------------------------------------------------//

---> "带有一个 Virtual Base Class 的 Class":

class X

class A : public virtual X

class B : public virtual X

class C : public A, public B

带有 virtual Base Class 的 Class C, 他的构造函数是有用的;

//-----------------------------------------------------------------------------------------------------------------------//

总结: 以上4种情况, "编译器必须为未声明构造函数的类合成一个默认构造函数",

标准称这些合成出来的构造函数为"隐式有用的构造函数", 合成出来的构造函数能够满足编译器( 而非程序 )的需要,

至于"不属于以上4种情况的而且又没有声明构造函数" 标准称他们为"隐式无用的构造函数", 事实上他们"不会被合成出来";

在合成的"隐式有用的构造函数"中, 只有 base class subobjects ( 基类的子对象 ) 和 class member object ( 类成员对象 ) 会被初始化;

而其他的 data member, 等等都不会被初始化 ( 虽然他们也许对程序是有用的 );

---->"误解":

---> 任何class如果没有定义默认构造函数 就会被合成出来一个,

---> 编译器合成出来的默认构造函数会设定class内的每一个data member,

很明显 都是错误的,
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c++ 多态 对象 语言