c++之继承三

多继承“

   一个类有多个直接基类的继承关系称为多继承

  多继承声明语法

  class  派生类名 : 访问控制  基类名1 ,  访问控制  基类名2 ,  … , 访问控制  基类名n

{

数据成员和成员函数声明

};

  多个基类的派生类构造函数可以用初始式调用基类构造函数初始化数据成员。

  执行顺序与单继承构造函数情况类似。多个直接基类构造函数执行顺序取决于定义派生类时指定的各个继承基类的顺序。

   一个派生类对象拥有多个直接或间接基类的成员。不同名成员访问不会出现二义性。如果不同的基类有同名成员,派生类对象访问时应该加以识别。

多继承的简单应用

 1 class Base1
 2 { public:
 3       Base1(int x) { value = x ; }
 4       int getData() const { return value ; }
 5    protected:
 6       int value;
 7 };
 8 class Base2
 9 { public:
10       Base2(char c) { letter=c; }
11       char getData() const { return letter;}
12    protected:
13       char letter;
14 };
15 class Derived : public Base1, public Base2
16 {    friend ostream &operator<< ( ostream &, const Derived & ) ;
17    public :
18       Derived ( int, char, double ) ;
19       double getReal() const ;
20    private :
21       double real ;
22 };

2.虚基类

如果一个派生类从多个基类派生,而这些基类又有一个共同

的基类,则在对该基类中声明的名字进行访问时,可能产生

二义性。

例如:

 1 class  B  { public : int  b ;} ;
 2
 3 class  B1 : public  B { private : int  b1 ; } ;
 4
 5 class  B2 : public  B { private : int  b2 ; } ;
 6
 7 class  C : public  B1 , public  B2
 8
 9     { public : int  f ( ) ;  private : int  d ; } ;
10
11
12
13 /*C  c ;
14
15 c . B ;  // error
16
17 c . B :: b ;  // error,从哪里继承的?
18
19 c . B1 :: b  ;  // ok,从B1继承的
20
21 c . B2 :: b  ;  // ok ,从B2继承的*/
22
23
24
25 #include<iostream>
26
27 using namespace std ;
28
29 int main ()
30
31 { C  c ;
32
33   c . B1 :: b = 5 ;       c . B2 :: b = 10 ;
34
35   cout << "path B1==> " << c . B1 :: b << endl ;
36
37   cout << "path B2==> " << c . B2 :: b << endl ;
38
39 }

建立 C 类的对象时,B 的构造函数将被调用两次:一次由B1调用,另一次由 B2 调用,以初始化 C 类的对象中所包含的两个 B 类的子对象

如果在多条继承路径上有一个公共的基类,那么在继承路径的某处

汇合点,这个公共基类就会在派生类的对象中产生多个基类子对象。

   要使这个公共基类在派生类中只产生一个子对象,必须对这个基类

声明为虚继承,使这个基类成为虚基类。

虚继承声明使用关键字      virtual

 1 #include <iostream>
 2 using namespace std;
 3
 4 //虚基类的测试
 5 class A
 6 {
 7 public:
 8     A(){ cout << "class a\n"; }
 9 };
10
11 //如果在此处不加上virtual关键字则会调用两次A类的构造函数
12 class B1:virtual public A
13 {
14 public:
15     B1(){ cout << "class b1\n"; }
16 };
17 //如果在此处不加上virtual关键字则会调用两次A类的构造函数
18 class B2:virtual public A
19 {
20 public:
21     B2(){ cout << "class b2\n";}
22 };
23 class C:public B1,public B2
24 {
25 public:
26     C(){ cout << "class C\n"; }
27 };
28 void main()
29 {
30     C c;
31 }

   继承是面向对象程序设计实现软件重用的重要方法。程序员可以在已有基类的基础上定义新的派生类。

   单继承的派生类只有一个基类。多继承的派生类有多个基类。

   派生类对基类成员的访问由继承方式和成员性质决定。

   创建派生类对象时,先调用基类构造函数初始化派生类中的基类成员。调用析构函数的次序和调用构造函数的次序相反。

   C++提供虚继承机制,防止类继承关系中成员访问的二义性。

   多继承提供了软件重用的强大功能,也增加了程序的复杂性。

时间: 2024-10-27 03:01:40

c++之继承三的相关文章

C++ 类的继承三(继承中的构造与析构)

//继承中的构造与析构 #include<iostream> using namespace std; /* 继承中的构造析构调用原则 1.子类对象在创建时会首先调用父类的构造函数 2.父类构造函数执行结束后,执行子类的构造函数 3.当父类的构造函数有参数时,需要在子类的初始化列表中显示调用 4.析构函数调用的先后顺序与构造函数相反 继承与其他类做成员变量混搭的情况下,构造和析构嗲用原则 1.先构造父类,在构造成员变量,最后构造自己 2.先析构自己,再析构成员变量,最后析构父类 */ clas

【C++】浅谈三大特性之一继承(三)

四,派生类的六个默认成员函数 在继承关系里,如果我们没有显示的定义这六个成员函数,则编译系统会在适合场合为我们自动合成. 继承关系中构造函数和析构函数的调用顺序: class B { public: B() { cout<<"B()"<<endl; } ~B() { cout<<"~B()"<<endl; } }; class D:public B { public: D() { cout<<"D

黑马程序员------继承(三)

1.1 多态:可以理解为某一类事物存在的多种体现形态. 人:男人,女人 动物:猫,狗. 猫 x = new 猫(); 动物 x = new 猫(); 1,体现 父类的引用指向了自己的子类对象. 父类的引用也可以接收自己的子类对象.2,前提 必须是类与类之间有关系.要么继承,要么实现. 通常还有一个前提:存在覆盖. 3,好处 多态的出现大大的提高程序的扩展性. 4,弊端: 提高了扩展性,但是只能使用父类的引用访问父类中的成员. 示例1: 1 /* 2 动物, 3 猫,狗. 4 */ 5 6 abs

【Java学习笔记之二十二】解析接口在Java继承中的用法及实例分析

一.定义 Java接口(Interface),是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能). 接口定义的一般形式为: [访问控制符]interface <接口名> { 类型标识符final 符号常量名n = 常数: 返回值类型  方法名([参数列表]); … } 二.接口的特点 1.Java接口中的成员变量默认都是public,static,final类型的(都可省略),必须被显

《Effective C++》之条款34:区分接口继承和实现继承

<Effective C++> 条款34:区分接口继承和实现继承 Public继承由两部分组成 函数接口继承 函数实现继承 三种可能面对的继承 derived class 只继承成员函数的接口 derived class 同时继承函数的接口和实现,但又希望能够覆写它们所继承的实现 derived class 同时继承函数的接口和实现,但不允许覆写任何东西 总结: 接口继承和实现继承不同.在public继承下,derived classes 总是继承base class 的接口. Pure vi

实习第一周第一天:接口 extends是继承类,implement是实现接口,原接口里面的方法填充,方法名也是不变,重写override是父类的方法名不变,把方法体给改了

一.定义 Java接口(Interface),是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能). 接口定义的一般形式为: [访问控制符]interface <接口名> { 类型标识符final 符号常量名n = 常数: 返回值类型  方法名([参数列表]); - } 二.接口的特点 1.Java接口中的成员变量默认都是public,static,final类型的(都可省略),必须被显

JS面向对象编程之:封装、继承、多态

最近在实习公司写代码,被隔壁的哥们吐槽说,代码写的没有一点艺术.为了让我的代码多点艺术,我就重新温故了<javascript高级程序设计>(其中几章),然后又看了<javascript设计模式>,然后觉得要写点心得体会,来整理自己所学的吧.以下是我个人见解,错了请轻喷,欢迎指出错误,乐于改正. 一.封装 (1)封装通俗的说,就是我有一些秘密不想让人知道,就通过私有化变量和私有化方法,这样外界就访问不到了.然后如果你有一些很想让大家知道的东西,你就可以通过this创建的属性看作是对象

javascript 中面向对象实现 如何继承

继承,同样不是真正严格意义上面向对象的继承,而是通过javascript中的原型链关系实现函数之间的属性,方法共享.下面简单分享几种封装的方法. 既然说到继承,我们必须有一个基类 1 2 3 4 5 6 7 8 9 function Person(){ this.eat=function(){ return '吃食物'; } } Person.prototype.sport=function(){ return '运动'; } Person 这个基类包含了2个属性,吃和运动.但是奇怪的是在构造函

深入理解JS继承和原型链

对于那些熟悉基于类的面向对象语言(Java 或者 C++)的开发者来说,JavaScript 的语法是比较怪异的,这是由于 JavaScript 是一门动态语言,而且它没有类的概念( ES6 新增了class 关键字,但只是语法糖,JavaScript 仍旧是基于原型). 涉及到继承这一块,Javascript 只有一种结构,那就是:对象.在 javaScript 中,每个对象都有一个指向它的原型(prototype)对象的内部链接.这个原型对象又有自己的原型,直到某个对象的原型为null 为止