一、何时合成Default Constructor及其行为
下面程序段不会合成一个default constructor
#include <iostream>
#include <stdlib.h>
using namespace std;
class Foo{
public:
int val;
Foo *pnext;
};
void foo_bar()
Foo bar;
if(bar.val||bar.pnext){
cout<<"var:"<<bar.val<<endl;
cout<<"pnext:"<<bar.pnext->val<<endl;
}
}
int main()
{
foo_bar();
system("pause");
return 0;
}
何时合成:编译器需要之时
行为:只执行编译器所需之行动
因此,即使有需要为class Foo合成一个default constructor,也不会将val 和 pnext初始化为0
故如需初始化,应提供明显的default constructor
二、nontrivial default constructor的四种情况“
1.带有“default consrtructor ”的成员类对象
2.带有“default consrtructor ”基类
3.带有“一个virtual Function”的基类
4.带有“virtual base class ”的类
1.带有“default consrtructor ”的成员类对象
下面这段程序,编译器为class Bar合成一个default constructor,这个默认构造函数能调用Foo的默认构造函数,但不产生任何码来初始化Bar::str,若需初始化str,需要显示定义
#include <iostream>
#include <stdlib.h>
using namespace std;
class Foo{
public:
Foo():val(0),pnext(0){
cout<<"var:"<<val<<endl;
cout<<"pnext:"<<pnext<<endl;
}
Foo(int v,Foo* p):val(v),pnext(p){
cout<<"var:"<<val<<endl;
cout<<"pnext:"<<pnext<<endl;
}
public:
int val;
Foo *pnext;
};
class Bar{
public:
Foo foo; //不是继承而是内含
char *str;
};
void foo_bar(){
Bar bar; //必须在此处初始化
if(bar.str){
cout<<bar.str<<endl;
}
}
int main()
{
foo_bar();
system("pause");
return 0;
}
如果class A内含一个或一个以上的Member class objects,那么class A的每一个constructor 必须调用每一个member classes的default constructor
//扩张后的default constructor
//伪码
inline
Bar::Bar() //inline因为是类内定义的
{
foo.Foo::Foo(); //编译器附加上的code
str=0; //用户显示定义的
}
如果多个class member objects都要求constructor初始化操作,以声明顺序来调用各个constructors
2.带有“default consrtructor ”基类
如果base class有default constructor,derived class的default constrcutor被视为nontrival,将被合成,根据其声明顺序依次调用上一层Base classes的defalut constructor。
如果提供了多个constructor,但都没有default constructor,编译器不会合成新的default constructor,但会在现有的所有constructor中,自动加入必要的default constructor。
★调用顺序:先base class constructor=>再调用member class objects
#include <iostream>
#include <stdlib.h>
using namespace std;
class A{
public:
A(){
cout<<"A's contructor"<<endl;
}
};
class B{
public:
B(){
cout<<"B's contructor"<<endl;
}
};
class C:public A{
public:
C(){
cout<<"C's contructor"<<endl;
}
};
class D:public C{
public:
D(int dd):d(dd){
cout<<"D's contructor,"<<"d:"<<d<<endl;
}
public:
B b;
int d;
};
int main()
{
D d(1);
system("pause");
return 0;
}
3.带有“一个virtual
Function”的基类
编译期间会发生如下,扩张操作:
1.一个virtual function table(vtbl)会在编译期间产生,内放class的virtual function地址。
2.在每一个class object中,一个额外的pointer member(vtpr)会被编译器合成,内含相关的class vtbl的地址。
此外,下述例子中widget.flip的虚拟引发操作(virtual invocation)会被重新改写,以使用widget的vtpr和vtbr中的flip()条目:
( *widget.vtpr[1] )( &widget )
■1表示flip()在virtual table中的固定索引
■&widget代表要交给“被调用的某个flip的函数实体”的this指针
因此,对于class定义的每个constuctor,编译器会插入一些码完成相关工作,对于未声明constructor的class,编译器会合成一个default constructor来正确初始化每一个class object的vptr。
#include <iostream>
#include <stdlib.h>
using namespace std;
class Widget{
public:
virtual void flip()=0;
};
class Bell:public Widget{
public:
void flip(){
cout<<"Bell flip"<<endl;
}
};
class Whistle:public Widget{
public:
void flip(){
cout<<"Whistle flip"<<endl;
}
};
void flip(Widget &w){
w.flip();
}
void foo(){
Bell b;
Whistle w;
flip(b);
flip(w);
}
int main()
{
foo();
system("pause");
return 0;
}
4.带有“virtual base class ”的类
virtual base class 在其每一个derived class object中的位置,必须在执行期准备妥当。
class X{public :int i;}
class A:public virtual X{public: int j;};
class B:public virtual X{public: double d;};
class C:public A,public B{public:int k;};
//无法再编译期间决定出pa->X::i的位置
void foo(const A* pa){pa->i=1024;}
main()
{
foo(new A);
foo(new C);
}
因为pa的真正类型可以改变,所以编译器无法固定住foo()之中“经由pa而存取的X::i”的实际偏移位置,编译器必须改变“执行存取操作”的那些码,安插在每一个constructor中,如果没有constructor,即合成一个default constructor