目录
继承的构造函数多重继承1.多重继承的概念2.静态成员变量3.派生类构造函数与析构函数4.从多个父类继承构造函数类型转换虚基类、虚继承(虚派生)总结继承的构造函数
C++语言同时支持单一继承和多重继承。单一继承是指派生类只从一个基类继承而来;相应的,多重继承指派生类同时从两个或更多的基类继承而来。继承时,子类只能继承其直接基类(父类)的构造函数。默认(也即编译器自动给我们生成的)、拷贝、移动构造函数都是不能被继承的。那么怎么写继承的构造函数呢?格式:using 类名::类名(构造函数名);
class A {public:A(int i,int j,int k){}public:static int m_static;};int A::m_static = 100; //后续要使用的话必须初始化,不使用的话可以不用定义class B : public A {public://B(int i,int j,int k):A(i,j,k) {};using A::A;//继承A的构造函数,会把基类都生成与之对应的派生类构造函数//B(int i,int j,int k):A(i,j,k) {};//如果有默认参数的话,会构造多个派生类构造函数//一个默认参数就会生成2个构造函数//A(int i,int j,int k=5){} ;//B(int i,int j,int k):A(i,j,k) {};//B(int i,int j):A(i,j) {};};int main () {B test(10,20,3);return 1;}
如果子类中只含有使用using 类名::类名;继承过来的构造函数时,编译器不认为我们给该子类定义了构造函数的。因此编译器还会为我们自动生成子类的默认构造函数如果基类的构造函数中带有默认的参数值,那么编译器一遇到using A::A;时,就会帮我们在子类中构造出多个构造函数来.
多重继承
class grand{public:grand(int v):m_valuegrad(v) {cout << "grand的构造函数" << endl;};~grand() {cout << "grand的析构函数" << endl;}void initData() {cout << "grand initData" << endl;}void init() {cout << "grand init" << endl;}static int valuegrand;int m_valuegrad;};int grand::valuegrand = 100;class A1 : public grand {public:A1(int v):grand(v),m_valuea1(v) {cout << "A1的构造函数" << endl;};~A1() {cout << "A1的析构函数" << endl;}void initData() {cout << "A1 initData" << endl;}int m_valuea1;};class B1{public:B1(int v):m_valueb1(v) {cout << "B1的构造函数" << endl;};~B1() {cout << "B1的析构函数" << endl;};void initData() {cout << "B1 initData" << endl;}int m_valueb1;};class C: public B1 ,public A1 {public:C(int v):B1(v),A1(v),m_valuec(v) {cout << "C的构造函数" << endl;};~C() {cout << "C的析构函数" << endl;}int m_valuec;};
1.多重继承的概念
一个子类继承自多个(2个及以上)父类。
2.静态成员变量
int grand::valuegrand = 100;
后续要使用的话必须初始化,不使用的话可以不用定义。
类跟类对应的对象都可以使用。
int main () {C c(1);c.init();//会调用基类grandc.A1::initData();//2个父类有同名函数需要标明具体类名c.B1::initData();c.valuegrand = 10000;A1::valuegrand = 1000;C::valuegrand = 1000;cout << c.valuegrand << endl;return 1;}
3.派生类构造函数与析构函数
构造一个派生类对象将同时构造并初始化所有的直接基类的成分。派生类的构造函数初始化列表只初始化它的直接基类,在多继承时也不例外。这样就会一层一层地把参数传递回最原始的基类,并把all的基类成分都构造好。基类的构造顺序跟“派生列表”中基类的出现顺序是保持一致的!析构顺序则相反。每个类的析构函数都只会进行自己这个类本身的成分的释放工作(类与类之间的析构函数是互不干扰的)。4.从多个父类继承构造函数
class A {public:A(int tv) {}};class B {public:B(int tv) {}};class C : public A,public B {public:using A::A;//继承A类的构造函数 ==> C(int tv):A(tv){}using B::B;//错误!继承B类的构造函数是 ==> C(int tv):B(tv){}该构造函数和继承自A类的一模一样};
上述code中C多继承自父类A和父类B的构造函数已经重定义了。因此我们只能自己定义一个属于子类C的构造函数,应该在C中添加:
C(int tv):A(tv),B(tv){cout << "C类的构造函数执行了!" << endl;}
类型转换
基类指针是可以指向一个派生类(子类)对象的:因为编译器会帮助我们隐式地执行这种派生类到基类的转换。究其原因:因为每个派生类对象都会包含基类对象的成分。在多继承中,基类指针也是可以指向一个派生类(子类)对象的!
grand *g = new C(1);A1 *a = new C(1);B1 *b = new C(1);C tc(2);grand gg(tc);
这些写法都是正确的。
虚基类、虚继承(虚派生)
派生列表中,同一个基类只能出现一次,但是如下两种特殊情况例外:
派生类可以通过它的两个直接基类分别继承自同一个间接基类。直接继承某个基类,然后通过另一个基类间接继承该类。
class grand{public:grand(int v):m_valuegrad(v) {cout << "grand的构造函数" << endl;};~grand() {cout << "grand的析构函数" << endl;}void initData() {cout << "grand initData" << endl;}void init() {cout << "grand init" << endl;}static int valuegrand;int m_valuegrad;};int grand::valuegrand = 100;class A1 : public grand {public:A1(int v):grand(v),m_valuea1(v) {cout << "A1的构造函数" << endl;};~A1() {cout << "A1的析构函数" << endl;}void initData() {cout << "A1 initData" << endl;}int m_valuea1;};class A2 : public grand {public:A2(int v):grand(v),m_valuea2(v) {cout << "A2的构造函数" << endl;};~A2() {cout << "A2的析构函数" << endl;}int m_valuea2;};class B1{public:B1(int v):m_valueb1(v) {cout << "B1的构造函数" << endl;};~B1() {cout << "B1的析构函数" << endl;};void initData() {cout << "B1 initData" << endl;}int m_valueb1;};class C: public B1 ,public A1 ,public A2{public:C(int v):B1(v),A1(v),A2(v),m_valuec(v) {cout << "C的构造函数" << endl;};~C() {cout << "C的析构函数" << endl;}int m_valuec;};int main() {C ccc(1);//ccc.m_valuegrad = 100;return 1;}
运行结果为:
可以发现grand调用了2次构造2次析构函数。当调用共享基类的成员是会出现不明确错误。这就是多继承时对于基类成员变量的二义性问题
比如 ccc.m_valuegrad = 100; 提示C::m_valuegrad" 不明确。为了解决这样的错误同时为了提高效率,怎么才能调用一个呢?
只需在A1和A2继承grand的添加virtual。
class A1 :virtual public grand
class A2 :virtual public grand
同时把C(int v):B1(v),A1(v),A2(v),m_valuec(v)改为
C(int v):B1(v),A1(v),A2(v),gand(v),m_valuec(v)
修改之后再次运行结果为:
OK,完美!