当前位置:主页   - 电脑 - 程序设计 - C/C++
继承关系中基类和子类构造函数的调用顺序
来源:网络   作者:CLive Studio   更新时间:2011-08-26
收藏此页】    【字号    】    【打印】    【关闭

  首先回顾并讨论先有鸡还是先有蛋的问题在C++中将会是什么情况。如果编写:

class Egg;
class Hen
{
public:
int n;
Egg egg;
    Hen() {
        n=5;
        cout<<"Hen's con "<<n<<endl;
    }
};
class Egg : public Hen
{
public:
    int m;
    Egg(){
        m=10;
        cout<<"Egg's con"<<endl;
    }
};
int main()
{
    Egg dan;
}

  这在C++中是无法编译通过的,首先,学过编译原理的都应该知道,所有语言在编译的时候都需要确定一个类的大小。C++的编译器在编译一个类的时候,需要分析这个类的大小,而sizeof(Egg)=sizeof(Hen)+sizeof(Egg)+…,编译器无法获知其大小,自然也无法编译通过;而JAVA、C#则不同,其类的成员皆为基本类型或引用。同时,和Java、C#等语言不同,C++不能做全局优化编译(即使打开全局优化开关也没有用),它的编译是逐步向后的分析方式。C++这样做,也在编译时就防止出现先有鸡还是先有蛋而产生的矛盾。大家可以尝试在C++中尝试其他方法看编译是否能够通过。

  JAVA虽然可以在Hen类的初始化时对Egg进行构造(通过new Egg()),但运行时会出现堆栈溢出的错误:

Exception in thread "main" java.lang.StackOverflowError
    at Egg.<init>(…)
    at Hen.<init>(…)
    at Egg.<init>(…)
    at Hen.<init>(…)

  下面回到本文的主题。我们知道,C++和JAVA不一样,C++子类是默认调用基类构造函数的,而JAVA则需要super()。为了研究基类和子类构造函数的调用顺序问题,以上述程序为基础,我编写了这样一个测试:

class Hen
{
public:
    int n;
    Hen() {
        n=5;
        cout<<"Hen's con "<<n<<endl;
    }
    Hen(int i) {
        n=i;
        cout<<"Hen's con "<<n<<endl;
    }
};
class Hen1
{
public:
    int x;
    Hen1() {
        x=6;
        cout<<"Hen1's con "<<x<<endl;
    }
};
 
class Hen2
{
public:
    int y;
    Hen2() {
        y=7;
        cout<<"Hen2's con "<<y<<endl;
    }
};
class Egg : public Hen, public Hen2, public Hen1
{
public:
    int m;
    Hen hen;
    Hen1 hen1;
    Hen2 hen2;
    Egg(int i) : Hen2(),Hen1(),Hen(),hen(i), hen2(), hen1(){
        m=10;
        cout<<"Egg's con"<<endl;
    }
};
int main()
{
    Egg dan(1);
}

  Output:

Hen's con 5 
Hen2's con 7 
Hen1's con 6 
Hen's con 1 
Hen1's con 6 
Hen2's con 7 
Egg's con

  通过这段程序可得如下结论:

  1、基类构造函数。如果有多个基类,则构造函数的调用顺序是某类在类继承表中出现的顺序,而不是它们在成员初始化表中的顺序。如这里,是按照“class Egg : public Hen, public Hen2, public Hen1”的顺序

  2、成员类对象构造函数。如果有多个成员类对象,则构造函数的调用顺序是对象在类中被声明的顺序,而不是它们出现在成员初始化表中的顺序。如这里,是按照Egg声明里

  Hen hen; 
  Hen1 hen1; 
  Hen2 hen2;

  的顺序。

  总1、2而言之,成员初始化表顺序对于构造和赋值顺序没有任何意义

  3、成员类对象并不是一开始就被构造,再根据初始化表赋值,而是在调用构造函数的时候,根据传入的参数根据成员初始化表中进行一次构造,构造顺序是对象在类中声明的顺序。

其它资源
来源声明

版权与免责声明
1、本站所发布的文章仅供技术交流参考,本站不主张将其做为决策的依据,浏览者可自愿选择采信与否,本站不对因采信这些信息所产生的任何问题负责。
2、本站部分文章来源于网络,其版权为原权利人所有。由于来源之故,有的文章未能获得作者姓名,署“未知”或“佚名”。对于这些文章,有知悉作者姓名的请告知本站,以便及时署名。如果作者要求删除,我们将予以删除。除此之外本站不再承担其它责任。
3、本站部分文章来源于本站原创,本站拥有所有权利。
4、如对本站发布的信息有异议,请联系我们,经本站确认后,将在三个工作日内做出修改或删除处理。
请参阅权责声明