清远市网站建设_网站建设公司_Logo设计_seo优化
2025/12/17 19:27:35 网站建设 项目流程

多继承派生类的语法格式:

class 派生类名 : <继承方式1> 基类名1,

<继承方式2> 基类名2,

…… {

……//派生类新添加的成员

};

多继承派生类对象的构造和析构:

派生类名(参数表):基类名1(参数表1),

基类名2(参数表2),

对象成员1(参数表3),

对象成员2(参数表4),

… {

//派生类新添加的成员

}

派生类构造执行顺序是按照:基类对象、成员对象、普通变量的高到低优先级执行的,其中其中基类对象的调用顺序和声明继承关系的顺序有关。

但是析构函数的执行顺序与之相反,先调用派生类的析构函数,再调用对象成员的析构函数,最后调用基类的析构函数。

访问不同基类同名成员时的二义性

class A{ public: int value; void f(){}; }; class B{ public: int value; void f(){}; void g(){}; }; class C: public A, public B{ public: void g(){}; void h(){}; }; int main(){ C C1; C1.f(); C1.value=9; return 0; }

这里在调用f()和value时会出现二义性,因为编译器不知道你访问的是A和B中的哪一个()和value。

所以在此我们需要填写他的“绝对路径”,类名对成员加以限定:改成:

int main(){
C C1;
C1.A::f();
C1.A::value=9//访问A的f()和value。
return 0;
}

第二种情况:

class A{ public: int a; void g( ){}; }; class B1: public A{ int b1; }; class B2: public A{ int b2; }; class C: public B1, public B2{ int c; public: int f(){}; }; int main(){ C Cobj; Cobj.a=8; Cobj.A::a=9; Cobj.g( ); return 0; }

这一二义性的冲突是因为B1、B2都有一个公共基类A,这个公共基类会在派生类对象中产生两个基类子对象,于是我们也要来对此进行限定:

Cobj.B1::a=9;或 Cobj.B2::a=9;

但是这还有一个问题,使用绝对路径找到的基类,我们也可以得知派生类对象中存在多个基类对象的拷贝,导致空间浪费,解决方法也很简单,将A设为虚基类即可,这样 B1 和 B2 继承 A 时,C 最终只会保留一份 A 的子对象,就不会有二义性了。

虚基类

虚基类子对象被合并成一个子对象,这种“合并”作用,使得可能出现的二义性被消除。下面是使用虚基类与没使用虚基类的概念图:

class A { public: int a = 10; void g() { cout << "A的g()函数,a=" << a << endl; } }; // B1虚继承A class B1 : virtual public A {}; // B2虚继承A class B2 : virtual public A {};

虚基类构造函数的调用次序有着自己独特的次序,规则:

1:对于最终派生类来说,虚基类的构造必须在非虚基类之前调用;

2:同一个层次中包含多个虚基类,那么按照虚基类构造函数按它们说明的次序调用。

若虚基类由非虚基类派生,则遵守先调用基类构造函数,再调用派生类构造函数的规则。

举个栗子:

class base{…}; class bas2{…}; class level1 : public base2, vitrual public base{…}; class level2 : public base2, vitrual public base{…}; class toplevel : public level1, vitrual public level2{…};

声明toplevel 时,构造顺序是从 “最顶层虚基类” 开始,再到 “普通基类 / 中间类”,最后到自身

第一步,先调用全局虚基类

base被level1、level2都虚继承了,所以base是全局虚基类,会被优先构造且只构造 1 次→ 顺序第 1 位:base

第二步,按照规则优先调用虚基类

level2是toplevel的虚基类,所以要先构造level2(规则1),而构造level2时,要先构造它的基类:
level2的基类:base2(普通,先构造) + base(虚基类,已经构造过了,不再构造)(规则2
→ 顺序第 2-3 位:base2(level2 的普通基类) → level2

第三步

level1是toplevel的普通基类,构造level1时,要先构造它的基类:
level1的基类:base2(普通,先构造) + base(虚基类,已构造)(规则2
→ 顺序第 4-5 位:base2(level1 的普通基类) → level1

第四步

最后构造toplevel→ 顺序第 6 位:toplevel

综合

base(全局虚基类)→ base2(level2 的普通基类)→ level2(toplevel 的虚基类)→ base2(level1 的普通基类)→ level1(toplevel 的普通基类)→ toplevel

例2:

class base{…}; class base2{…}; class level1 : virtual public base2, virtual public base{…}; class level2 : virtual public base2, virtual public base{…}; class toplevel : public level1, virtual public level2{…};

同样的道理,但不同的是level1和level2都是虚基类。

此时base与base2都是全局变量,当有多个全局虚基类时,构造顺序遵循:
最终派生类继承链中,虚基类首次出现的 继承声明顺序排序。

最终派生类toplevel的继承链中,base2和base首次出现在level1、level2的继承声明里,且声明顺序是base2在前、base在后 → 先构造base2,再构造base。所以按照构造顺序定下base2为第一位,basee为第二位。

再通过规则1优先构造toplevel的虚基类level2为第三位,再构造普通类level1为第五位,最后构造自身toplevel。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询