c++类多重继承初始化顺序
2013-08-08 13:44
330 查看
c++类多重继承时,初始化顺序是一个基础的问题,笔者每次清楚了以后,过段时间有点含糊了,有些基础的问题,在实际开发中,用到的频率少,今天做一个总结跟大家一起分享。
这里先讨论一般的基类继承时的初始化行为,然后再讨论虚基类的情况。
using namespace std;
class CBase
{
private:
int a;
public:
CBase(int va):a(va)
{
cout<<"CBase:"<<endl<<this->a<<endl;
}
};
class A:public CBase
{
private:
int t;
public:
A(int vt,int ut):t(vt),CBase(ut)
{
cout<<"A:"<<endl<<this->t<<endl;
}
};
class B:public CBase
{
private:
int t;
public:
B(int vt,int ut):t(vt),CBase(ut)
{
cout<<"B:"<<endl<<this->t<<endl;
}
};
class C:public B,public A
{
private:
int t;
public:
//C(int vt,int ut,int kt):A(vt,ut),B(vt,ut),CBase(kt)
C(int vt,int ut,int kt):A(vt,ut),B(vt,ut),t(kt)
{
cout<<"C:"<<endl<<this->t<<endl;
}
};
int main()
{
C cc(1,2,3);
return 0;
}
输出结果:
![](https://img-blog.csdn.net/20130808132203500?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYmFieWtha2FsdW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
注意类C的继承顺序和构造函数初始化顺序,蓝色和红色字体,刚好是相反的,从输出结果可以看到,是一继承顺序为依据的,先调用B的构造函数,B的构造函数执行前又先调用CBase基类的构造函数,然后是类成员的初始化,最后是类构造函数体部分的执行,以此类推,总结下顺序:
1、根据继承顺序,父类构造函数,回退到基类先开始
2、类成员初始化
3、构造函数体部分初始化
另外有一点需要注意的是,C类(红色字体部分)如果用注释掉的语句来初始化,会报错的,这里就引入了虚基类的问题,类似这种CBase类作为A和B类的共同基类,而C类又继承A和B,C++类在继承的时候,存在一个膨胀的问题的,所以才会有一种设计模式“尽量用聚合或者组合的方式”实现,而不是首先考虑继承,继承的层级过深,在性能和资源的占用上是需要衡量的,虚基类正好是可以解决这个问题的,今天重点讨论的是,虚基类继承的初始化行为,看下面的例子2:
#include<iostream>
using namespace std;
class CBase
{
private:
int a;
public:
CBase(int va):a(va)
{
cout<<"CBase:"<<endl<<this->a<<endl;
}
};
class A:virtual public CBase
{
private:
int t;
public:
A(int vt,int ut):t(vt),CBase(ut)
{
cout<<"A:"<<endl<<this->t<<endl;
}
};
class B:virtual public CBase
{
private:
int t;
public:
B(int vt,int ut):t(vt),CBase(ut)
{
cout<<"B:"<<endl<<this->t<<endl;
}
};
class C:public B,public A
{
private:
int t;
public:
C(int vt,int ut,int kt):A(vt,ut),B(vt,ut),CBase(kt),t(kt)
//C(int vt,int ut,int kt):A(vt,ut),B(vt,ut),t(kt)
{
cout<<"C:"<<endl<<this->t<<endl;
}
};
int main()
{
C cc(1,2,3);
return 0;
}
输出结果:
![](https://img-blog.csdn.net/20130808133927281?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYmFieWtha2FsdW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
对比例子1的结果,是有比较大的区别的,虚基类的构造要最先执行,并且执行一次,当再次调用A类和B类的构造函数时,CBase类的构造函数不再调用执行,这也正说明了,虚基类解决了这种冗余继承时候的“膨胀”问题。
除了这个顺序不同外,其余的顺序还是一样的。
这里先讨论一般的基类继承时的初始化行为,然后再讨论虚基类的情况。
例子1:
#include<iostream>using namespace std;
class CBase
{
private:
int a;
public:
CBase(int va):a(va)
{
cout<<"CBase:"<<endl<<this->a<<endl;
}
};
class A:public CBase
{
private:
int t;
public:
A(int vt,int ut):t(vt),CBase(ut)
{
cout<<"A:"<<endl<<this->t<<endl;
}
};
class B:public CBase
{
private:
int t;
public:
B(int vt,int ut):t(vt),CBase(ut)
{
cout<<"B:"<<endl<<this->t<<endl;
}
};
class C:public B,public A
{
private:
int t;
public:
//C(int vt,int ut,int kt):A(vt,ut),B(vt,ut),CBase(kt)
C(int vt,int ut,int kt):A(vt,ut),B(vt,ut),t(kt)
{
cout<<"C:"<<endl<<this->t<<endl;
}
};
int main()
{
C cc(1,2,3);
return 0;
}
输出结果:
注意类C的继承顺序和构造函数初始化顺序,蓝色和红色字体,刚好是相反的,从输出结果可以看到,是一继承顺序为依据的,先调用B的构造函数,B的构造函数执行前又先调用CBase基类的构造函数,然后是类成员的初始化,最后是类构造函数体部分的执行,以此类推,总结下顺序:
1、根据继承顺序,父类构造函数,回退到基类先开始
2、类成员初始化
3、构造函数体部分初始化
另外有一点需要注意的是,C类(红色字体部分)如果用注释掉的语句来初始化,会报错的,这里就引入了虚基类的问题,类似这种CBase类作为A和B类的共同基类,而C类又继承A和B,C++类在继承的时候,存在一个膨胀的问题的,所以才会有一种设计模式“尽量用聚合或者组合的方式”实现,而不是首先考虑继承,继承的层级过深,在性能和资源的占用上是需要衡量的,虚基类正好是可以解决这个问题的,今天重点讨论的是,虚基类继承的初始化行为,看下面的例子2:
#include<iostream>
using namespace std;
class CBase
{
private:
int a;
public:
CBase(int va):a(va)
{
cout<<"CBase:"<<endl<<this->a<<endl;
}
};
class A:virtual public CBase
{
private:
int t;
public:
A(int vt,int ut):t(vt),CBase(ut)
{
cout<<"A:"<<endl<<this->t<<endl;
}
};
class B:virtual public CBase
{
private:
int t;
public:
B(int vt,int ut):t(vt),CBase(ut)
{
cout<<"B:"<<endl<<this->t<<endl;
}
};
class C:public B,public A
{
private:
int t;
public:
C(int vt,int ut,int kt):A(vt,ut),B(vt,ut),CBase(kt),t(kt)
//C(int vt,int ut,int kt):A(vt,ut),B(vt,ut),t(kt)
{
cout<<"C:"<<endl<<this->t<<endl;
}
};
int main()
{
C cc(1,2,3);
return 0;
}
输出结果:
对比例子1的结果,是有比较大的区别的,虚基类的构造要最先执行,并且执行一次,当再次调用A类和B类的构造函数时,CBase类的构造函数不再调用执行,这也正说明了,虚基类解决了这种冗余继承时候的“膨胀”问题。
除了这个顺序不同外,其余的顺序还是一样的。
相关文章推荐
- C/C++开发语言系列之5---普通继承和虚基类构造函数的初始化顺序2
- C/C++开发语言系列之5---普通继承和虚基类构造函数的初始化顺序2
- 关于c++中的类继承以及类初始化顺序
- C++——类继承以及类初始化顺序
- c++中的类继承以及类初始化顺序
- C++ Primer Plus学习笔记之继承类的初始化顺序
- C++ 多继承构造函数初始化列表调用顺序
- C/C++开发语言系列之4---普通继承和虚基类构造函数的初始化顺序1
- C/C++开发语言系列之4---普通继承和虚基类构造函数的初始化顺序1
- C++变量的初始化顺序
- C++中子类继承父类构造器和析构器的执行顺序
- C++中多重继承构造函数调用的先后顺序
- 【深入理解JVM】:Java类继承关系中的初始化顺序
- c++多重继承 和 初始化列表
- java继承 初始化顺序
- C++在单继承、多继承、虚继承时,构造函数、复制构造函数、赋值操作符、析构函数的执行顺序和执行内容 【转】 参考度4.6星
- C++ 虚继承对基类构造函数调用顺序的影响
- C++ - 类的成员变量 声明顺序 与 初始化顺序 相同
- 关于C++继承体系中类的构造与析构的顺序【转贴】
- C++中组合和继承的初始化