博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++虚继承和虚基类详解
阅读量:4092 次
发布时间:2019-05-25

本文共 2059 字,大约阅读时间需要 6 分钟。

一、问题的提出

多继承(Multiple Inherice)是指从多个直接基类中产生派生类的能力,多继承的派生类继承了所有父类的成员。尽管概念上非常简单,但是多个基类的相互交织可能会带来错综复杂的设计问题,命名冲突就是不可回避的一个。

多继承时很容易产生命名冲突,即使我们很小心地将所有类中的成员变量和成员函数都命名为不同的名字,命名冲突依然有可能发生,比如典型的是菱形继承,如下图所示:

类 A 派生出类 B 和类 C,类 D 继承自类 B 和类 C,这个时候类 A 中的成员变量和成员函数继承到类 D 中变成了两份,一份来自 A-->B-->D 这条路径,另一份来自 A-->C-->D 这条路径。

在一个派生类中保留间接基类的多份同名成员,虽然可以在不同的成员变量中分别存放不同的数据,但大多数情况下这是多余的:因为保留多份成员变量不仅占用较多的存储空间,还容易产生命名冲突。假如类 A 有一个成员变量 a,那么在类 D 中直接访问 a 就会产生歧义,编译器不知道它究竟来自 A -->B-->D 这条路径,还是来自 A-->C-->D 这条路径。下面是菱形继承的具体实现:

//间接基类A    class A{    protected:        int m_a;    };    //直接基类B    class B: public A{    protected:        int m_b;    };    //直接基类C    class C: public A{    protected:        int m_c;    };    //派生类D    class D: public B, public C{    public:        void seta(int a){ m_a = a; }  //命名冲突        void setb(int b){ m_b = b; }  //正确        void setc(int c){ m_c = c; }  //正确        void setd(int d){ m_d = d; }  //正确    private:        int m_d;    };    int main(){        D d;        return 0;    }

这段代码实现了上图所示的菱形继承,第 25 行代码试图直接访问成员变量 m_a,结果发生了错误,因为类 B 和类 C 中都有成员变量 m_a(从 A 类继承而来),编译器不知道选用哪一个,所以产生了歧义。

二、解决方案
为了消除歧义,我们可以在 m_a 的前面指明它具体来自哪个类:

void seta(int a){ B::m_a = a; }

这样表示使用 B 类的 m_a。当然也可以使用 C 类的:

void seta(int a){ C::m_a = a; }

三、虚继承(Virtual Inheritance)

为了解决多继承时的命名冲突和冗余数据问题, 提出了虚继承,使得在派生类中只保留一份间接基类的成员。

在继承方式前面加上 virtual 关键字就是虚继承,请看下面的例子:

//间接基类A    class A{    protected:        int m_a;    };    //直接基类B    class B: virtual public A{  //虚继承    protected:        int m_b;    };    //直接基类C    class C: virtual public A{  //虚继承    protected:        int m_c;    };    //派生类D    class D: public B, public C{    public:        void seta(int a){ m_a = a; }  //正确        void setb(int b){ m_b = b; }  //正确        void setc(int c){ m_c = c; }  //正确        void setd(int d){ m_d = d; }  //正确    private:        int m_d;    };    int main(){        D d;        return 0;    }

这段代码使用虚继承重新实现了上图所示的菱形继承,这样在派生类 D 中就只保留了一份成员变量 m_a,直接访问就不会再有歧义了。

虚继承的目的是让某个类做出声明,承诺愿意共享它的基类。其中,这个被共享的基类就称为虚基类(Virtual Base Class),本例中的 A 就是一个虚基类。在这种机制下,不论虚基类在继承体系中出现了多少次,在派生类中都只包含一份虚基类的成员。

参考:

转载地址:http://xkiii.baihongyu.com/

你可能感兴趣的文章
Java中String类型与Date日期类型互相转换的方法
查看>>
JS获取7天后日期的方法
查看>>
Java中ArrayList初始化的4种方法
查看>>
Vue中格式化对比json串插件
查看>>
Java将Object类型对象转换为指定的实体类对象
查看>>
Mysql中不同字段类型对应的Java类型
查看>>
使用Gson判断两个Json字符串是否相等
查看>>
Mybatis中获取新添加记录的主键id且不受并发影响的方法
查看>>
Mybatis中使用selectKey标签得到新增数据的主键
查看>>
Java中ArrayList的删除元素方法总结
查看>>
Java判断集合中是否存在某个元素的方法
查看>>
Java中split()用法
查看>>
Java中打印程序执行的开始时间和结束时间
查看>>
Java中实现对象克隆的方法
查看>>
Java深拷贝和浅拷贝的区别
查看>>
Mybatis的xml文件中大于小于符号的正确替换写法
查看>>
Mysql获取所有查询结果中N条记录
查看>>
Gson实现将Json字符串转为Map类型
查看>>
Git查看与切换分支
查看>>
Git合并分支
查看>>