C++中类的多继承
在写这一主题的文章之前,在网上找到一篇很非常好的文章C++之继承与多态。就没有必要做重复造轮子的事件了,那就从这篇文章开始吧!
在c++中一个类可以从多个基类中派生(即可以有多个父类),这就是多继承。多继承的方式主要有两种:
1. 简单版本
类C会同时拥有类A和类B的特性(属性和方法,也就是两个类的所有成员)。这种方式很简单这里就不多说,主要讲下面这种方式。
2. 复杂版本
同样的,这个结构中类C也会同时拥有类A和类B的特性,但这就会有一个问题,类B1和B2都继承自A,那么类C的对象会同时包含两个A的对象。这样就会带来很多歧义性。
我们看一个典型的例子“沙发-床”:
类的关系图
代码:
#pragma once
#include <iostream>
#include <string>
using namespace std;
class Furniture
{
public:
Furniture(void) : m_weight(0){}
Furniture(double weight) : m_weight(weight){}
~Furniture(void){}
double GetWeight() const { return m_weight; }
void SetWeight(double val) { m_weight = val; }
private:
double m_weight;
};
class Bed : public Furniture
{
public:
Bed() : Furniture(), m_second(0) {}
Bed(double weight, int second) : Furniture(weight), m_second(second){}
void Sleep(int second)
{
m_second = second;
cout << "休息" << m_second << "秒..."<< endl;
}
private:
int m_second;
};
class Sofa : public Furniture
{
public:
Sofa() : Furniture() {}
Sofa(double weight) : Furniture(weight){}
void WatchTV(string programme)
{
cout << "正在看" << programme << "节目..." << endl;
}
};
class SleepSofa : public Bed, public Sofa
{
public:
SleepSofa() : Bed(), Sofa() {}
SleepSofa(double weight, int second) : Bed(weight, second), Sofa(weight) {}
void FoldOut()
{
cout << "展开沙发当床用." << endl;
Sleep(360);
}
};
SleepSofa类继承自Bed和Sofa两个类,因此,SleepSofa类拥有这两个类的特性,但在实际编码中会存在如下几个问题。
1.SleepSofa类该如何定义?
Class SleepSofa : public Bed, public Sofa
{
…
}
构造顺序为:Bed sofa sleepsofa (也就是书写的顺序)
2.Bed和Sofa类都继承自Furniture,都有Weight属性也都有GetWeight和SetWeight方法,在SleepSofa类中使用这些属性和方法时,如何确定调用的是哪个类的成员?
我们看一下测试样例:
void Test()
{
SleepSofa sleepSofa;
sleepSofa.SetWeight(55);
double weight = sleepSofa.GetWeight();
}
这时会有以下错误:
.cpp(76): error C3861: ‘SetWeight’: identifier not found
error C2385: ambiguous access of ‘GetWeight’
就是说SetWeight和GetWeight是有歧义的。
解决方法:
(1). 可以使用完全限定名(即加上类的作用域)的方式,比如:
SleepSofa sleepSofa;
sleepSofa.Bed::SetWeight(55);
sleepSofa.Sofa::SetWeight(80);
这时可以看到sleepSofa对象有两个Furniture对象。如下:
(2). 虚继承
倘若,我们定义一个SleepSofa对象,让我们分析一下它的构造过程:它会构造Bed类和Sofa类,但Bed类和Sofa类都有一个父类,因此Furniture类被构造了两次,这是不合理的,因此,我们引入了虚继承的概念。
class Furniture{……};
class Bed : virtual public Furniture{……}; // 这里我们使用虚继承
class Sofa : virtual public Furniture{……};// 这里我们使用虚继承
class SleepSofa : public Bed, public Sofa {……};
这样,Furniture类就只会构造一次,sleepSofa对象只会包含一个Furniture对象。
我们看一下测试样例:
SleepSofa sleepSofa;
sleepSofa.SetWeight(80);
这时我们Debug模式可以看到SleepSofa的m_weight值都是80。
这里虽然显示着两个Furniture对象,但其实指向的是同一个对象。我们可以看看它们的地址都是一样的。
总结
- 在程序设计中最好不要出现多继承,要有也是继承多个作为接口使用抽象类(只声明需要的功能,没有具体的实现)。因为出现一般的多继承本身就是一种不好的面向对象程序设计。
- 在出现版本2的多继承时使用虚继承的方式。
C++中类的多继承的更多相关文章
- Python中类的__init__继承
Python中类的__init__继承 概念: 定义父类 In [10]: class Person: ....: def __init__(self,name,age,sex): ....: sel ...
- Python中类的多层继承和多重继承
- Lua面向对象----类、继承、多继承、单例的实现
(本文转载)学习之用,侵权立删! 原文地址 http://blog.csdn.net/y_23k_bug/article/details/19965877?utm_source=tuicool&a ...
- 面向对象编程(九)——面向对象三大特性之继承以及重写、Object类的介绍
面向对象三大特性 面向对象三大特征:继承 :封装/隐藏 :多态(为了适应需求的多种变化,使代码变得更加通用!) 封装:主要实现了隐藏细节,对用户提供访问接口,无需关心方法的具体实现. 继承:很好的实现 ...
- 24 类:组合 继承 super关键字 面向对象的三大性
组合 组合:自定义类的对象作为另外一个类的属性 class Teacher: def __init__(self, name, age): self.name = name self.age = ag ...
- day23--面向对象之封装、继承、多态
面向对象的三大特性: 封装: 在类的内部(class内部)可以由属性和方法,外部代码可以通过直接调用实例变量的方法来操作数据,这样就隐藏了内部的逻辑,但是外部还是可以直接修改实例的属性,因此当需求中存 ...
- JAVA基础复习与总结<一> 对象与类的概念_内部类_继承与多态
一.对象与类 类:类是一个模版,它描述了一类对象的行为和状态. class animal { private int color; private int size; public void eat ...
- C++ 深入理解 虚继承、多重继承和直接继承
[摘要] 本文从5段代码实例出发,通过类中类的普通继承,类的虚继承,类的多重继承,多个虚函数类的普通继承.虚继承与多重继承,几个交叉概念,详细的阐释了继承.虚函数与虚继承的基本概念,深入剖析了继承于虚 ...
- [18/11/29] 继承(extends)和方法的重写(override,不是重载)
一.何为继承?(对原有类的扩充) 继承让我们更加容易实现类的扩展. 比如,我们定义了人类,再定义Boy类就只需要扩展人类即可.实现了代码的重用,不用再重新发明轮子(don’t reinvent w ...
随机推荐
- [UE4]实例化材质
在虚幻引擎 4 中,材质实例化用来更改材质的外观,而不会引起成本高昂的材质重新编译. 实例化材质官方文档
- [UE4]RPC,远程调用
RPC 一.Remote Procedure Call:远程程序调用 二.一个进程调用另外一个进程上的函数 由于“Server-shoot”方法被标记为“在服务器上运行”,所以尽管是在第二个窗口(客户 ...
- Css学习(三)
1 行高 ◆浏览器默认文字大小 浏览器默认文字大小:16px 行高:是基线与基线之间的距离 行高=文字高度+上下边距 一行文字行高和父元素高度一致的时候,垂直居中显示. 行高的单位 总结:单位除了像素 ...
- 00009 - cat、tail、head、tee、wc、sort文件操作和过滤
绝大多数命令行工作是针对文件的.我们会在本节中讨论如何观察及过滤文件内容,使用一条命令从文件中提取所需信息,以及对文件的内容进行排序. cat.tail.head.tee:文件打印命令这些命令的语法基 ...
- 修改Linux终端提示符颜色
修改Linux终端提示符颜色 作者:Eric 微信:loveoracle11g [root@linux-node2 ~]# tail -1 .bashrc PS1='[\[\033[1;31m\]\u ...
- 搭建(WSTMart)php电商环境时缺少fileinfo函数
搭建WSTMart环境步骤: 第一步:安装phpstudy,一键安装即可 第二步:把下好的系统源码,放到一个文件夹中,并放到刚刚安装好的phpstudy下WWW文件夹下,如WWW>WSTMart ...
- sqlalchemy精华版
上一篇主要粗略讲了Flask+mysql+sqlalchemy的使用,这次精讲下sqlalchemy的用法,话不多说,上代码. ----------sqlalchemy_test.py # -*- c ...
- Django中的路由系统:urls
Django的路由系统 URL配置(URLconf)就像Django 所支撑网站的目录.它的本质是URL与要为该URL调用的视图函数之间的映射表. 你就是以这种方式告诉Django,对于这个URL调用 ...
- Github上 vue-element-admin项目配置
Github对应地址 https://github.com/PanJiaChen/vue-element-admin 其中git为最新版本才支持github 的 clone代码 步骤如下 # clo ...
- LeetCode 5. Longest Palindromic Substring & 回文字符串
Longest Palindromic Substring 回文这种简单的问题,在C里面印象很深啊.希望能一次过. 写的时候才想到有两种情况: 454(奇数位) 4554(偶数位) 第1次提交 cla ...