用wordpress做微站企业网站 jquery
news/
2025/10/1 22:08:44/
文章来源:
用wordpress做微站,企业网站 jquery,表白网站制作,linux代码做网站多重继承派生类
除去一个类从一个基类派生#xff0c;C还支持一个派生类同时继承多个基类
MI#xff1a;有多个直接基类的类
1.多重继承派生类的定义
如果已经定义了多个基类#xff0c;那么定义多重继承的派生类的形式为#xff1a;
class 派生类名:访问标号1 基类名…多重继承派生类
除去一个类从一个基类派生C还支持一个派生类同时继承多个基类
MI有多个直接基类的类
1.多重继承派生类的定义
如果已经定义了多个基类那么定义多重继承的派生类的形式为
class 派生类名:访问标号1 基类名1访问标号2 基类名2... { //类体成员列表
};
举个例子
class A { };
class B : public A { }; //A-B
class C : public A { }; //A-C
class D : public B,public C { }; //B-D,C-D
这里的D类就是一个MI.
2.多重继承派生类的构造函数
多重继承派生类的构造函数形式与单一继承时的构造函数形式基本相同只是在派生类的构造函数初始化列表中调用多个基类构造函数。
一般形式为
派生类名(形式参数列表):基类名1(基类1构造函数实参列表),基类名2(基类2构造函数实参列表),...,成员对象名1(子对象1属类构造函数实参列表),...,派生类初始化列表
{派生类初始化函数体
}
其调用顺序是 1调用基类构造函数各个基类按定义时的次序先后调用 2调用成员对象构造函数各个子对象按声明时的次序先后调用 3执行派生类初始化列表 4执行派生类初始化函数体
例多重继承举例
#includeiostream
using namespace std; class Base1 {private:int b1;public:Base1() {b10;cout默认构造Base1b1b1endl;}Base1(int i) {b1i;cout构造Base1b1b1endl;}
};class Base2 {private:int b2;public:Base2() {b20;cout默认构造Base2b2b2endl;}Base2(int j) {b2j;cout构造Base2b2b2endl;}
};class Base3 {public:Base3() {cout默认构造Base3endl;}
};class Derive : public Base1,public Base2,public Base3 {private:Base1 memberBase1;Base2 memberBase2;Base3 memberBase3;public:Derive() {cout默认构造函数Derive.endl; }Derive(int a,int b,int c,int d): Base1(a),Base2(b),memberBase1(c),memberBase2(d) {cout构造Derive.endl;}
};int main()
{coutendl创建派生类对象obj1endl;Derive obj1;coutendl创建派生类对象(1,2,3,4)endl;Derive obj2(1,2,3,4);return 0;
} 运行结果
创建派生类对象obj1:
默认构造Base1:b10//基类默认构造函数下面2个也是
默认构造Base2:b20
默认构造Base3:
默认构造Base1:b10//成员对象的构造函数下面2个也是
默认构造Base2:b20
默认构造Base3:
默认构造函数Derive,//派生类默认构造函数创建派生类对象(1.2.3.4):
构造Base1:b11 //基类构造函数下面2个也是
构造Base2:b22
默认构造Base3:
构造Base1:b13 //成员对象的构造函数下面2个也是
构造Base2:b24
默认构造Base3:
构造Derive. //派生类构造函数 二义性问题及名字支配规则
1.二义性问题
多重继承时多个基类可能出现同名的成员。在派生类中如果使用一个表达式的含义能解释为可以访问多个基类的成员则这种对基类成员的访问就是不确定的称这种访问具有二义性。C要求派生类对基类成员的访问必须是无二义性的
例如
class A {public:void fun() { couta.funendl; }
};
class B {public:void fun() { coutb.funendl; }void gun() { coutb.gunendl; }
};
class C:public A,public B {public:void gun() { coutc.gunendl; } //重写gun()void hun() { fun(); } //出现二义性
};
int main()
{C c,*pc;return 0;
} 使用成员名限定可以消除二义性例如
//成员名限定消除二义性
c.A::fun();
c.B::fun();
p-A::fun();
p-B::fun(); 基本形式为
对象名.基类名::成员名
对象指针名-基类名::成员名 2.名字支配规则
C对于在不同的作用域声明的名字可见性原则是如果存在两个或多个具有包含关系的作用域外层声明了一个名字而内层没有再次声明相同的名字那么外层名字在内层可见如果在内层声明了相同的名字则外层名字在内层不可见这时称内层名字隐藏或覆盖了外层名字这种现象称为隐藏规则
在类的派生层次结构中基类的成员和派生类新增的成员都具有类作用域二者的作用域是不同的基类在外层派生类在内层
如果派生类声明了一个和基类成员同名的新成员派生的新成员就覆盖了基类同名成员直接使用成员名只能访问到派生类的成员
如果派生类中声明了与基类成员函数同名的新函数即使函数的参数不同从基类继承的同名函数的所有重载形式也都会被覆盖
如果要访问被覆盖的成员就需要使用基类名和作用域限定运算符来限定
派生类D中的名字N覆盖基类B中同名的名字N称为名字支配规则。如果一个名字支配另一个名字则二者之间不存在二义性当选择该名字时使用支配者的名字如
c.gun(); //使用C::gun 如果要使用被支配者的名字则应使用成员名限定例如
c.B::gun(); //使用B::gun 虚基类
C引入虚基类的目的是为了解决多继承时可能出现的冲突问题。当一个类通过多个路径继承了同一个基类时如果不使用虚基类那么在派生类中就会存在多个基类子对象这可能会导致数据重复和二义性的问题。
通过使用虚基类可以确保在派生类中只有一个基类子对象从而避免数据重复和二义性的问题。虚基类的成员在派生类中只有一个副本不会重复出现。
另外虚基类还可以实现多态性能够让派生类对象按照基类的指针或引用进行使用从而提高代码的灵活性和可扩展性。
1.虚基类的定义
虚基类是在派生类定义时指定继承方式时声明的。声明虚基类的一般形式为
class 派生类名: virtual 访问标签 虚基类名... { //类体成员列表
};
还有一种形式是
class 派生类名: 访问标签 virtual 虚基类名... { // 成员列表
};
需要注意为了保证虚基类在派生类中只继承一次应当在该基类的所有直接派生类中声明为虚基类。否则仍然会出现对基类的多次继承我们下面会举例子
例虚基类举例
#includeiostream
using namespace std; class A { //声明为基类Apublic:A(int n) { //A类的构造函数 nvn;coutMember of Aendl;} void fun() {coutfun of Aendl;}private:int nv;
};class B1: virtual public A { //声明A为虚基类 public:B1(int a):A(a) { //B1类的构造函数 coutMember of B1endl;}private:int nv1;
};class B2: virtual public A { //声明A为虚基类public:B2(int a):A(a) { //B2类的构造函数coutMember of B2endl; } private:int nv2;
};class C: public B1,public B2 {public://派生类的构造函数的成员初始化列表中必须列出对虚基类构造函数的调用C(int a):A(a),B1(a),B2(a) {coutMember of Cendl;}void fund() {coutfun of Cendl;}private:int nvd;
};int main()
{C c1(1);c1.fund();c1.fun(); //不会产生二义性return 0;
} 现在C对象只将包含A对象的一个副本。从更本质的说继承的B1和B2对象共享一个A对象而不是各种引入自己的A对象副本。这样子调用A类方法就不会有二义性了不知道调用B!继承的还是B2继承的A类方法。
如果我们不引入虚基类再看看这个例子
#includeiostream
using namespace std;class A { //声明为基类A
public:A(int n) { //A类的构造函数 nv n;cout Member of A endl;}void fun() {cout fun of A endl;}
private:int nv;
};class B1 : virtual public A { //声明A为虚基类
public:B1(int a) :A(a) { //B1类的构造函数 cout Member of B1 endl;}
private:int nv1;
};class B2 : public A { //注意这里没有声明A为虚基类
public:B2(int a) :A(a) { //B2类的构造函数cout Member of B2 endl;}
private:int nv2;
};class C : public B1, public B2 {
public://派生类的构造函数的成员初始化列表中必须列出对虚基类构造函数的调用C(int a) :A(a), B1(a), B2(a) {cout Member of C endl;}void fund() {cout fun of C endl;}
private:int nvd;
};int main()
{C c1(1);c1.fund();c1.fun(); //产生了二义性return 0;
}
我们将B2后面的virtual去掉使A类失去虚基类的性质。发现上面这个程序出现了二义性编译器不知道调用B1继承的A类方法还是B2继承的A类方法。 2.虚基类的初始化
如果在虚基类中定义了带参数的构造函数而且没有定义默认构造函数则在其所有派生类包括直接派生和间接派生中都要通过构造函数的初始化表对虚基类进行初始化。例如
class A { public: A(int) { } }; //定义构造函数有参数的基类
class B: virtual public A {public:B(int a):A(a) { } //对基类A初始化
};
class C: virtual public A {public:C(int a):A(a) { } //对基类A初始化
};
class D: public B,public C {public:D(int a):A(a),B(a),C(a) { }
};
在最后的派生类中不仅要负责对其直接基类进行初始化还要负责对虚基类初始化
关于虚基类的说明
1一个类可以在一个类族中即被用作虚基类也被用作非虚基类
2派生类的构造函数的成员初始化列表中必须列出对虚基类构造函数的调用如果未列出则表示使用该虚基类的默认构造函数
3在一个成员初始化列表中同时出现对虚基类和非虚基类构造函数的调用时虚基类的构造函数先于非虚基类的构造函数执行多重继承应用举例
#includeiostream
using namespace std; enum Color { //颜色枚举类型 Red,Yellow,Green,White
};class Circle { //圆类Circle的定义private:float radius;public:Circle(float r) {radiusr;coutCircle initialized!endl;} ~Circle() {coutCircle destroyed!endl;}float Area() {return 3.1415926*radius*radius;}
};class Table { //桌子类Table的定义private:float height;public:Table(float h) {heighth;coutTable initialized!endl;}~Table() {coutTable destroyed!endl;}float Height() {return height;}
};class RoundTable: public Table,public Circle { //圆桌类的定义private:Color color;public:RoundTable(float h,float r,Color c);int GetColor() {return color;}~RoundTable() {coutRoundTable destroyed!endl;}
};RoundTable::RoundTable(float h,float r,Color c):Table(h),Circle(r) { //圆桌构造函数的定义colorc;coutRoundTable initialized!endl;
}int main()
{RoundTable cir_table(15.0,2.0,Yellow);coutThe table properties are:endl;coutHeightcir_table.Height()endl; //调用Table类的成员函数coutAreacir_table.Area()endl; //调用circle类的成员函数coutColorcir_table.GetColor()endl; //调用RoundTable 类的成员函数return 0;
} 运行结果
Table initialized!
Circle initialized!
RoundTable initialized!
The table properties are:
Height15
Area12.5664
Color1
RoundTable destroyed!
Circle destroyed!
Table destroyed!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/924325.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!