从零开始学C++之继承(三):多重继承、虚继承与虚基类

一、多重继承

单重继承——一个派生类最多只能有一个基类 多重继承——一个派生类可以有多个基类

class 类名: 继承方式 基类1,继承方式 基类2,…. {….};

派生类同时继承多个基类的成员,更好的软件重用 可能会有大量的二义性,多个基类中可能包含同名变量或函数

多重继承中解决访问歧义的方法:

基类名::数据成员名(或成员函数(参数表)) 明确指明要访问定义于哪个基类中的成员

#include <iostream>
using namespace std;

class Bed
{
public:
    Bed(int weight) : weight_(weight)
    {

    }
    void Sleep()
    {
        cout << "Sleep ..." << endl;
    }
    int weight_;
};

class Sofa
{
public:
    Sofa(int weight) : weight_(weight)
    {

    }
    void WatchTV()
    {
        cout << "Watch TV ..." << endl;
    }
    int weight_;
};

class SofaBed : public Bed, public Sofa
{
public:
    SofaBed() : Bed(0), Sofa(0)
    {
        FoldIn();
    }
    void FoldOut()
    {
        cout << "FoldOut ..." << endl;
    }
    void FoldIn()
    {
        cout << "FoldIn ..." << endl;
    }
};

int main(void)
{
    SofaBed sofaBed;
    //sofaBed.weight_ = 10; error
    //sofaBed.weight_ = 20; error

    sofaBed.Bed::weight_ = 10;
    sofaBed.Sofa::weight_ = 20;

    sofaBed.WatchTV();
    sofaBed.FoldOut();
    sofaBed.Sleep();

    return 0;
}

不能直接写 sofaBed.weight_ = 10; 因为sofaBed 继承了Sofa 和 Bed ,实际上有weigh_的两份拷贝,这样指向不明。只能通过

sofaBed.Bed::weight_ = 10; 访问,但实际上一个sofaBed理应只有一个weight_,下面通过虚基类和虚继承可以解决这个问题。

二、虚继承与虚基类

当派生类从多个基类派生,而这些基类又从同一个基类派生,则在访问此共同基类中的成员时,将产生二义性,可以采用虚基类来解决。

虚基类的引入 用于有共同基类的场合

声明 以virtual修饰说明基类 例:class B1:virtual public BB

作用

主要用来解决多继承时可能发生的对同一基类继承多次而产生的二义性问题. 为最远的派生类提供唯一的基类成员,而不重复产生多次拷贝

#include <iostream>
using namespace std;

class Furniture
{
public:
    Furniture(int weight) : weight_(weight)
    {
        cout << "Furniture ..." << endl;
    }
    ~Furniture()
    {
        cout << "~Furniture ..." << endl;
    }
    int weight_;
};

class Bed : virtual public Furniture
{
public:
    Bed(int weight) : Furniture(weight)
    {
        cout << "Bed ..." << endl;
    }
    ~Bed()
    {
        cout << "~Bed ..." << endl;
    }
    void Sleep()
    {
        cout << "Sleep ..." << endl;
    }

};

class Sofa : virtual public Furniture
{
public:
    Sofa(int weight) : Furniture(weight)
    {
        cout << "Sofa ..." << endl;
    }
    ~Sofa()
    {
        cout << "~Sofa ..." << endl;
    }
    void WatchTV()
    {
        cout << "Watch TV ..." << endl;
    }
};

class SofaBed : public Bed, public Sofa
{
public:
    SofaBed(int weight) : Bed(weight), Sofa(weight), Furniture(weight)
    {
        cout << "SofaBed ..." << endl;
        FoldIn();
    }
    ~SofaBed()
    {
        cout << "~SofaBed ..." << endl;
    }
    void FoldOut()
    {
        cout << "FoldOut ..." << endl;
    }
    void FoldIn()
    {
        cout << "FoldIn ..." << endl;
    }
};

int main(void)
{
    SofaBed sofaBed(5);
    sofaBed.weight_ = 10;


    sofaBed.WatchTV();
    sofaBed.FoldOut();
    sofaBed.Sleep();

    return 0;
}

此时只有一份weigh_,不存在访问歧义的问题。

从输出可以总结出:

1、虚基类的成员是由最远派生类的构造函数通过调用虚基类的构造函数进行初始化的。 2、在整个继承结构中,直接或间接继承虚基类的所有派生类,都必须在构造函数的成员初始化表中给出对虚基类的构造函数的调用。如果未列出,则表示调用该虚基类的默认构造函数。 3、在建立对象时,只有最远派生类的构造函数调用虚基类的构造函数,该派生类的其他基类对虚基类构造函数的调用被忽略。

参考:

C++ primer 第四版 Effective C++ 3rd C++编程规范

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏nnngu

经典Java面试题收集

2、访问修饰符public,private,protected,以及不写(默认)时的区别?

93813
来自专栏linux驱动个人学习

Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析【转】

Android系统的运行时库层代码是用C++来编写的,用C++ 来写代码最容易出错的地方就是指针了,一旦使用不当,轻则造成内存泄漏,重则造成系统崩溃。不过系统为...

592
来自专栏小樱的经验随笔

【Java学习笔记之二十五】初步认知Java内部类

可以将一个类的定义放在另一个类的定义内部,这就是内部类。   内部类是一个非常有用的特性但又比较难理解使用的特性(鄙人对内部类也只是略知一二)。 第一次...

2935
来自专栏代码拾遗

反射基础之Method

一个方法声明包括:方法名,描述符,参数,返回类型和异常。可以通过java.lang.reflect.Method类获取这些信息。 下面的例子说明了如何获取一个类...

823
来自专栏机器学习入门

POJ 刷题系列:2632. Crashing Robots

题意: 在一张地图(A x B)中给出N个robot的位置和初始移动方向,以及M条指令,任意两个robot不能同时移动,问是否存在非法的crash状态(撞墙,...

1958
来自专栏代码拾遗

反射基础之Class

Java中每个类型要么是引用类型,要么是原生类型。类,枚举,数组(他们都继承于java.lang.Object)和接口都是引用类型。例如:java.lang.S...

824
来自专栏一个会写诗的程序员的博客

《Kotin 极简教程》第7章 面向对象编程(OOP)(2)《Kotlin极简教程》正式上架:

在上面的代码中,我们通过向注解类添加元注解(meta-annotation)的方法来指定其他属性:

1062
来自专栏一个会写诗的程序员的博客

Kotlin 扩展函数与属性 实例代码

771
来自专栏Java爬坑系列

【Java入门提高篇】Day13 Java中的反射机制

  前一段时间一直忙,所以没什么时间写博客,拖了这么久,也该更新更新了。最近看到各种知识付费的推出,感觉是好事,也是坏事,好事是对知识沉淀的认可与推动,坏事是感...

3519
来自专栏编码小白

ofbiz实体引擎(四) ModelReader的作用

public class ModelReader implements Serializable { public static final Stri...

2718

扫码关注云+社区