当前位置: 首页 > news >正文

C++多继承,虚继承部分总结与示例


tags: C++ OOP

写在前面

写一下多继承, 虚继承的一些部分, 包括一些例子.

多继承

简介

多继承是指从多个直接基类中产生派生类的能力. 多继承的派生类继承了所有父类的属性, 所以会带来一些复杂的问题.

示例1: 多继承用法与调用顺序

#include <string>
#include <iostream>
using namespace std;class ZooAnimal {
public:ZooAnimal() { cout << "call ZooAnimal::ZooAnimal()\n"; }~ZooAnimal() { cout << "call ZooAnimal::~ZooAnimal()\n"; }
};class Endangered {
public:Endangered() { cout << "call Endangered::Endangered()\n"; }Endangered(int a) : m_a(a) { cout << "call Endangered::Endangered(int)\n"; }~Endangered() { cout << "call Endangered::~Endangered()\n"; }static int critical;private:int m_a;
};
int Endangered::critical = 10;class Bear : public ZooAnimal {
public:Bear() { cout << "call Bear::Bear()\n"; }Bear(string, bool, string);~Bear() { cout << "call Bear::~Bear()\n"; }
};
Bear::Bear(string name, bool onExhibit, string detail) {cout << "call Bear::Bear(string, bool, string)\n";
}// multi inherit
class Panda : public Bear, public Endangered {
public:Panda();Panda(string, bool);~Panda() { cout << "call Panda::~Panda()\n"; }
};Panda::Panda(string name, bool onExhibit): Bear(name, onExhibit, "Panda"), Endangered(Endangered::critical) {cout << "call Panda::Panda(string, bool)\n";
}
Panda::Panda() : Endangered(Endangered::critical) {cout << "call Panda::Panda()\n";
}void t1() {//Panda p1;/* call ZooAnimal::ZooAnimal() *//* call Bear::Bear() *//* call Endangered::Endangered(int) *//* call Panda::Panda() *//* call Panda::~Panda() *//* call Endangered::~Endangered() *//* call Bear::~Bear() *//* call ZooAnimal::~ZooAnimal() */
}int main(int argc, char *argv[]) {t1();return 0;
}

通过输出可以看出, 首先调用最终基类, 然后调用直接基类, 然后是第二基类, 最后是子类.

析构顺序正好相反(由子类至基类).

示例2: 多继承构造函数可能出现的问题

#include <iostream>
#include <memory>
#include <string>
using namespace std;struct Base1 {Base1() { cout << "Base1()\n"; }Base1(const string &) { cout << "Base1(const string&) \n"; }Base1(std::shared_ptr<int>);
};struct Base2 {Base2() { cout << "Base2()\n"; }Base2(const string &) { cout << "Base2(const string&) \n"; }Base2(int a) { cout << "Base2(int)\n"; }
};struct D1 : public Base1, public Base2 {using Base1::Base1;using Base2::Base2;// 定义自己版本的构造函数D1(const string &) { cout << "D1(const string &)\n"; }
};void t1() {D1 d1(1);/* Base1() *//* Base2(int) */
}
void t2() {D1 d2("abc");/* error: call of overloaded 'D1(const char [4])' is ambiguous *//* Base1() *//* Base2() *//* D1(const string &) */
}int main(int argc, char *argv[]) {// test/* t1(); */t2();return 0;
}

多继承引发的类型转换问题

在只有一个基类的情况下, 派生类的指针或引用能自动转换成一个可访问基类的指针或引用, 多基类情况类似, 可以令某个可访问基类的指针或引用直接指向一个派生类对象. 如下所示:(仍然采用上面的Panda例子)

void print(const Bear &) { cout << "call print(const Bear&)\n"; }
void highlight(const Endangered &) {cout << "call highlight(const Endangered&)\n";
}
ostream &operator<<(ostream &os, const ZooAnimal &) {os << "call operator<< (ZooAnimal)\n";return os;
}
// 如果解注释, 会导致错误
/* error: call of overloaded 'print(Panda&)' is ambiguous */
/* void print(const Endangered &) { cout << "call print(const Endangered&)\n"; } */
void t2() {Panda aa("aa", true);print(aa);highlight(aa);cout << aa << endl;/* call print(const Bear&) *//* call highlight(const Endangered&) *//* call operator<< (ZooAnimal) */
}

上面如果为同一函数的参数作两个基类的重载, 那么就会导致二义性错误.

基于指针类型或引用类型的查找

与只有一个基类的继承一样, 对象/指针/引用的静态类型决定了能使用的成员.

例如: 如果使用一个ZooAnimal指针, 则只有定义在ZooAnimal中的操作可以调用, 而Pandas中的其他特有部分(其他基类, Bear,Panda,Endangered)都不可见.

class ZooAnimal {
public:ZooAnimal() { cout << "call ZooAnimal::ZooAnimal()\n"; }void print() { cout << "call ZooAnimal::print()\n"; }~ZooAnimal() { cout << "call ZooAnimal::~ZooAnimal()\n"; }
};void t3() {Bear *pb = new Panda("aa", true);pb->print();delete pb;/* call ZooAnimal::ZooAnimal() *//* call Bear::Bear(string, bool, string) *//* call Endangered::Endangered(int) *//* call Panda::Panda(string, bool) *//* call ZooAnimal::print() *//* call Bear::~Bear() *//* call ZooAnimal::~ZooAnimal() */
}

多继承下的类作用域

在只有一个基类的情况下, 派生类的作用域嵌套在直接基类和间接基类的作用域中. 查找过程沿着继承体系自底向上进行, 直到找到所需的名字. 派生类的名字将隐藏基类的同名成员.

多继承中, 相同的查找过程在所有直接基类中同时进行, 若同一名字在多个基类中找到, 则二义性错误.

所以, 需要显式指明作用域, 或者定义新版本的不同名内容.

虚继承

派生列表中同一基类只能出现一次, 但是实际上派生类可以多次继承同一个类, 派生类可以通过它的两个直接基类分别继承同一个间接基类, 也可以直接继承某个基类, 然后通过另一个基类再一次间接继承该类.

默认情况下, 派生类中含有继承链上的每一个类对应的子部分, 如果某个类在派生过程中出现多次, 则派生类中将包含该类的多个子对象.

虚继承的出现就是用于解决多继承中存在的基类多次使用问题的.

其目的是: 令某一个类作出声明, 承诺愿意共享基类, 其中, 共享的基类子对象称为虚基类.

在这种机制下, 不论虚基类在继承体系中出现了多少次, 在派生类中都只包含唯一一个共享的虚基类子对象.

  • 必须在虚派生的真实需求出现之前完成派生操作.
  • 虚派生只会影响从指定了虚基类的派生类中进一步派生出的类, 不会影响派生类本身.
  • 使用virtual说明符(在public之前或者之后都可以)表明了: 在后续的派生类中共享虚基类的同一份实例, 但是并没有规定什么样的类能够作为虚基类.

示例: Panda

#include <string>
#include <iostream>
using namespace std;class ZooAnimal {
public:ZooAnimal() {}void print() { cout << "call ZooAnimal::print()\n"; }~ZooAnimal() {}
};class Endangered {
public:Endangered() {}Endangered(int a) : m_a(a) {}~Endangered() {}static int critical;private:int m_a;
};
int Endangered::critical = 10;class Raccoon : virtual public ZooAnimal {
public:Raccoon() {}Raccoon(string, bool, string);~Raccoon() {}
};
Raccoon::Raccoon(string name, bool onExhibit, string detail) {}class Bear : virtual public ZooAnimal {
public:Bear() {}Bear(string, bool, string);~Bear() {}
};
Bear::Bear(string name, bool onExhibit, string detail) {}// multi inherit
class Panda : public Bear, public Raccoon, public Endangered {
public:Panda();Panda(string, bool);~Panda() {}
};Panda::Panda(string name, bool onExhibit): Bear(name, onExhibit, "Panda"), Endangered(Endangered::critical) {}
Panda::Panda() : Endangered(Endangered::critical) {}void t1() {Panda a;/* call ZooAnimal::ZooAnimal() *//* call Bear::Bear() *//* call Raccoon::Raccoon() *//* call Endangered::Endangered(int) *//* call Panda::Panda() *//* call Panda::~Panda() *//* call Endangered::~Endangered() *//* call Raccoon::~Raccoon() *//* call Bear::~Bear() *//* call ZooAnimal::~ZooAnimal() */
}

虚派生中, 虚基类是由最底层的派生类初始化的, 以上面的程序为例, 当创建Panda对象时, 由Panda构造函数独自控制ZooAnimal的初始化过程.

支持向基类的常规类型转换

与非虚基类一样, 派生类对象也可以被可访问基类的指针或引用操作.

void dance(const Bear &) { cout << "call dance(const Bear&)\n"; }
void rummage(const Raccoon &) { cout << "call rummage(const Raccoon&)\n"; }
ostream &operator<<(ostream &os, const ZooAnimal &) {os << "call operator<< (ZooAnimal)\n";return os;
}void t2() {Panda a;dance(a);rummage(a);cout << a;/* call dance(const Bear&) *//* call rummage(const Raccoon&) *//* call operator<< (ZooAnimal) */
}

虚基类成员的可见性

因为在每一个共享的虚基类中只有唯一一个共享的子对象, 所以该基类的成员可以被直接访问, 并且不会产生二义性.

如果虚基类的成员只被一条派生路径覆盖, 则我们仍可以直接访问这个被覆盖的成员, 但是如果成员被多于一个的基类覆盖(例子: 菱形继承), 派生类就必须为该成员自定义一个新版本.

虚继承对象的构造方式

  • 首先使用提供给最底层派生类构造函数的初始值初始化该对象的虚基类子部分;
  • 接下来按照直接基类在派生列表中出现的次序依次对其初始化.

例子中的顺序:

  1. 使用Panda的构造函数初始值列表中提供的初始值构造虚基类ZooAnimal部分
  2. 构造Bear
  3. 构造Raccoon
  4. 构造Endangered
  5. 构造Panda

如果Panda没有显式初始化ZooAnimal基类, 则调用ZooAnimal的默认构造函数, 所以此时一定要有默认构造函数.

相关文章:

C++多继承,虚继承部分总结与示例

tags: C OOP 写在前面 写一下多继承, 虚继承的一些部分, 包括一些例子. 多继承 简介 多继承是指从多个直接基类中产生派生类的能力. 多继承的派生类继承了所有父类的属性, 所以会带来一些复杂的问题. 示例1: 多继承用法与调用顺序 #include <string> #include <…...

程序员35岁以后就没有出路了吗?听听京东10年测开的分析

国内的互联网行业发展较快&#xff0c;所以造成了技术研发类员工工作强度比较大&#xff0c;同时技术的快速更新又需要员工不断的学习新的技术。因此淘汰率也比较高&#xff0c;超过35岁的基层研发类员工&#xff0c;往往因为家庭原因、身体原因&#xff0c;比较难以跟得上工作…...

数据结构(六):冒泡排序、选择排序、插入排序、希尔排序、快速排序

数据结构&#xff08;六&#xff09;一、大O表示法二、冒泡排序三、选择排序一、大O表示法 在计算机中采用粗略的度量来描述计算机算法的效率&#xff0c;这种方法被称为“大O”表示法。 我们判断一个算法的效率&#xff0c;不能只凭着算法运行的速度&#xff0c;因为随着数据…...

C++之类与对象(上)

目录 一、类的定义 二.类的访问限定及封装 1.访问限定 2.封装 三.类的作用域和实例化 2.类的实例化 四.类的对象大小的计算 1.类成员存储方式 2.结构体内存对齐规则 五.类成员函数的this指针 1.this指针的引出 2.this指针的特性 3.C语言和C实现Stack的对比 一、类的定义 class …...

Java岗面试题--Java并发 计算机网络(日积月累,每日三题)

目录1. 面试题一&#xff1a;在 Java 程序中怎么保证多线程的运行安全&#xff1f;1.1 追问一&#xff1a;Java 线程同步的几种方法&#xff1f;2. 面试题二&#xff1a;JMM3. 面试题三&#xff1a;计算机网络的各层协议及作用&#xff1f;1. 面试题一&#xff1a;在 Java 程序…...

三菱FX3U与威纶MT8071IP走RS422通讯

一、准备工作 1.需要工具&#xff1a; 电脑一台、PLC&#xff1a;三菱FX3U一个、触摸屏&#xff1a;威纶MT8071一个、 &#xff08;三菱圆形编程口转USB&#xff09;一根、触摸屏与电脑通讯线一根&#xff08;T型口数据线&#xff09;、PLC与触摸屏通讯线&#xff1a;电烙…...

给想考CISP的一点建议

如果你正在考虑参加CISP认证考试&#xff0c;以下是我对你的几点建议&#xff1a; 了解CISP考试&#xff1a; 在报名参加考试之前&#xff0c;要充分了解CISP认证考试的考试内容、考试形式、考试难度等相关信息&#xff0c;这有助于你制定更有效的备考计划。制定备考计划&…...

ACM 记忆化搜索

一.记忆化搜索概述 1.概念 搜索是一种简单有效但是效率又很低下的算法结构&#xff0c;其低效的原因主要在于存在很多重叠子问题。而记忆化搜索则是在搜索的基础上&#xff0c;利用数组来记录已经计算出来的重叠子问题状态&#xff0c;进行合理化的剪枝&#xff0c;从而降低时…...

spring框架常用注解简单说明

1、Configuration&#xff1a;标注在类上&#xff0c;相当于把当前类作为spring的xml配置文件中的&#xff1b; 2、Bean&#xff1a;标注在方法上&#xff0c;相当于spring配置文件中的&#xff1b; 3、Service&#xff1a;标注在类上&#xff0c;表明当前类是一个服务层的Be…...

2023-02-24 mysql/innodb-聚合-临时表避免OOM-使用磁盘文件-分析

摘要: mysql/innodb在执行聚合时, 当聚合的数据量太大时, 也就是临时表的大小超过tmp_table_size 限制时, 将进行写磁盘操作, 以避免OOM。 本文记录聚合数据写磁盘的操作。 参考: https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_tmp_table_…...

cracklib与libpwquality 评估密码的安全性

一、cracklib 检测密码强弱linux中采用pam pam_cracklib module来实现对密码强度的检测&#xff0c;可以通过配置让linux系统自动检测用户的密码是否为弱密码。yuminstall cracklib # centos apt-get install libcrack2 # ubuntu # 如果需要依赖此库做开发的话需要安装这个 y…...

【Java】保证并发安全的三大特性

一、并发编程三大特性的定义和由来 并发编程这三大特性就是为了在多个线程交替执行任务的过程中保证线程安全性。 二、为什么会出现线程不安全的现象呢&#xff1f; 接下来我们从这三个特性切入来介绍线程不安全的原因。 1.原子性&#xff1a; 一组操作要么全部执行&#…...

如何优雅的用golang封装配置项(Functional Options)

导读 最近要封装一个公共服务&#xff0c;涉及到配置项的地方总是找不到合理的方案&#xff0c;后来看了一下grpc在配置方面的封装&#xff0c;了解到原来是golang特有的Functional Options编程模式&#xff0c;今天分享给大家&#xff0c;希望你能用到&#xff0c;咱们直接来看…...

Springboot 使用thymeleaf 服务器无法加载resources中的静态资源异常处理

目录一、异常错误二、原因三、解决方法方法1. 将无法编译的静态资源放入可编译目录下方法2. 重新编译项目加载资源方法3. 修改pom.xml资源配置文件方法4. 不连接远程数据库启动&#xff0c;使用本地数据库一、异常错误 Springboot使用thymeleaf&#xff0c;并连接远程数据库启…...

服务端IOS订阅类型支付接入详细说明与注意事项

一、说明 由于本人在开发ios订阅类型支付接入的时候&#xff0c;遇到了很多坑&#xff0c;也查了不少资料&#xff0c;逐步完善了整个ios订阅支付服务端接入的功能&#xff0c;在这里写下总结和一些注意事项的记录&#xff0c;方便未来需要重新接入或者避免一些不必要的坑,这里…...

【剑指Offer】重建二叉树(递归+迭代)

重建二叉树一、递归法二、迭代法题目链接 题目描述&#xff1a; 输入某二叉树的前序遍历和中序遍历的结果&#xff0c;请构建该二叉树并返回其根节点。 假设输入的前序遍历和中序遍历的结果中都不含重复的数字。 示例 1: Input: preorder [3,9,20,15,7], inorder [9,3,15,…...

注解@Transactional 原理和常见的坑

这篇文章&#xff0c;会先讲述 Transactional 的 4 种不生效的 Case&#xff0c;然后再通过源码解读&#xff0c;分析 Transactional 的执行原理&#xff0c;以及部分 Case 不生效的真正原因1 项目准备下面是 DB 数据和 DB 操作接口&#xff1a;uidunameusex1张三女2陈恒男3楼仔…...

2023年全国最新交安安全员精选真题及答案4

百分百题库提供交安安全员考试试题、交安安全员考试预测题、交安安全员考试真题、交安安全员证考试题库等&#xff0c;提供在线做题刷题&#xff0c;在线模拟考试&#xff0c;助你考试轻松过关。 31.特种劳动防护用品必须具有“三证”&#xff0c;下列不属于“三证”的是&#…...

扬帆优配|半天翻倍,“蹭热点”翻车,前期“牛股”已近腰斩

周五上午&#xff0c;A股商场整体走低&#xff0c;多数职业板块和个股跌落&#xff0c;军工和核算机等板块逆势上涨&#xff0c;北向资金半天净卖出额约38亿元。 个股方面&#xff0c;昨夜公告被证监会立案查询的奥联电子股价再度大跌&#xff0c;盘中最贱价较近期高位已腰斩。…...

6 种易于上手的编程副业,每月赚取 1,000 多美元——没有废话

没有自由职业者或博客&#xff0c;也不需要前期费用。你们中的大多数人阅读这样的故事是希望其中的一些故事能帮助您赚更多的钱。好吧&#xff0c;几年前我还是同一个人。我希望尝试一些新的副业并赚点钱。其中一个视频建议我在网上写作&#xff0c;此后我写了很多技术文章。在…...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15

缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下&#xff1a; struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

return this;返回的是谁

一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请&#xff0c;不同级别的经理有不同的审批权限&#xff1a; // 抽象处理者&#xff1a;审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...

STM32HAL库USART源代码解析及应用

STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

深入浅出Diffusion模型:从原理到实践的全方位教程

I. 引言&#xff1a;生成式AI的黎明 – Diffusion模型是什么&#xff1f; 近年来&#xff0c;生成式人工智能&#xff08;Generative AI&#xff09;领域取得了爆炸性的进展&#xff0c;模型能够根据简单的文本提示创作出逼真的图像、连贯的文本&#xff0c;乃至更多令人惊叹的…...

HTTPS证书一年多少钱?

HTTPS证书作为保障网站数据传输安全的重要工具&#xff0c;成为众多网站运营者的必备选择。然而&#xff0c;面对市场上种类繁多的HTTPS证书&#xff0c;其一年费用究竟是多少&#xff0c;又受哪些因素影响呢&#xff1f; 首先&#xff0c;HTTPS证书通常在PinTrust这样的专业平…...

Java中HashMap底层原理深度解析:从数据结构到红黑树优化

一、HashMap概述与核心特性 HashMap作为Java集合框架中最常用的数据结构之一&#xff0c;是基于哈希表的Map接口非同步实现。它允许使用null键和null值&#xff08;但只能有一个null键&#xff09;&#xff0c;并且不保证映射顺序的恒久不变。与Hashtable相比&#xff0c;Hash…...

【Java】Ajax 技术详解

文章目录 1. Filter 过滤器1.1 Filter 概述1.2 Filter 快速入门开发步骤:1.3 Filter 执行流程1.4 Filter 拦截路径配置1.5 过滤器链2. Listener 监听器2.1 Listener 概述2.2 ServletContextListener3. Ajax 技术3.1 Ajax 概述3.2 Ajax 快速入门服务端实现:客户端实现:4. Axi…...