[c++] 继承和多态整理一

1 private 和 protected 继承,子类指针不能赋值给父类指针

如下代码,有一个基类 Base,Derived1,Derived2,Derived3 3 个子类继承了基类 Base,分别是 private 继承,protected 继承,public 继承。在 main 函数里,分别使用 new 来创建 3 个子类,将 3 个子类指针赋值给 Base 指针,private 和 protected 继承的时候,子类指针无法赋值给父类指针。

private 继承或者 protected 继承下,父类的属性和函数在子类中的权限发生了变动。所以使用父类指针指向子类,可能会导致不安全的行为。

#include <iostream>
#include <string>class Base {
public:Base() {std::cout << "Base()" << std::endl;}~Base() {std::cout << "~Base()" << std::endl;}virtual void Do() {std::cout << "Base() Do()" << std::endl;}
};class Derived1 : private Base {
public:Derived1() {std::cout << "Derived1()" << std::endl;}~Derived1() {std::cout << "~Derived1()" << std::endl;}
};class Derived2 : protected Base {
public:Derived2() {std::cout << "Derived2()" << std::endl;}~Derived2() {std::cout << "~Derived2()" << std::endl;}
};class Derived3 : public Base {
public:Derived3() {std::cout << "Derived3()" << std::endl;}~Derived3() {std::cout << "~Derived3()" << std::endl;}
};int main() {Base *b1 = new Derived1();Base *b2 = new Derived2();Base *b3 = new Derived3();b1->Do();b2->Do();b3->Do();return 0;
}

编译结果如下:

2 子类和父类中的同名函数

在类继承中,一般子类可以覆盖父类中的虚函数,这是我们使用继承和多态常用的方式。如果子类中的函数和父类中的函数同名,并且这个函数不是虚函数呢,父类指针调用函数的时候调用的是父类中的函数,还是子类中的函数 ?在实际开发中,一般不会这么使用,这样的代码是毫无意义的,是自相矛盾的,因为继承了父类,那么就是要复用父类中的方法与属性,即使要覆盖也应该覆盖虚函数,如果不是虚函数,那么显得不伦不类。这里只是对这种情况做一个探讨。

#include <iostream>
#include <string>class Base {
public:Base() {std::cout << "Base()" << std::endl;}~Base() {std::cout << "~Base()" << std::endl;}void Do() {std::cout << "Base() Do()" << std::endl;}virtual void VDo() {std::cout << "Base() VDo()" << std::endl;}
};class Derived : public Base {
public:Derived() {std::cout << "Derived()" << std::endl;}~Derived() {std::cout << "~Derived()" << std::endl;}void Do() {std::cout << "Derived() Do()" << std::endl;}void VDo() {std::cout << "Derived() VDo()" << std::endl;}
};int main() {std::cout << "----------------" << std::endl;Base *b = new Derived();b->Do();b->VDo();std::cout << "----------------" << std::endl;Base b1 = *(new Derived);b1.Do();b1.VDo();std::cout << "----------------" << std::endl;Base &b2 = *(new Derived);b2.Do();b2.VDo();return 0;
}

Derived 和 Base 之间的赋值,不管是指针赋值,引用赋值还是值赋值,Base 指针,引用,值调用的都是 Base 中的 Do() 函数;Base 指针和引用调用的是 Derived 中的 VDo(),Base 值调用的是 Base 中的 VDo。

3 编译器默认生成的函数

面向对象的语言中 =、& 这么基础的运算符也是需要函数来实现的,这就是 c++ 的特点,一切皆对象。这个在 c 语言中很难理解的。

如果声明了一个对象,这个对象中什么也没有声明,那么为了使用这些基础的运算,编译器会默认生成一些函数。

构造函数类的构造
拷贝构造函数拷贝构造
析构函数析构
赋值运算符赋值
取地址运算符取值
取值运算符取地址
#include <iostream>
#include <string>class Base {
};int main() {Base b1;Base b2;b2 = b1;Base b3 = b2;std::cout << "&b1 = " << &b1 << std::endl;std::cout << "&b2 = " << &b2 << std::endl;return 0;
}

c++ 默认生成的函数,比如构造函数,如果我们在定义类的时候定义了自己的构造函数,那么编译器就不会生成默认的了。

如下代码中,Base 是一个基类,Derived 继承了 Base 类。在 Base 类中声明了构造函数 Base(int i),这样就不会有默认构造函数 Base() 了。在 Derived 类构造时,没有显式调用 Base 的构造函数,那么就会调用默认构造函数 Base(),但是默认构造函数又不存在,所以在编译的时候就会报错。需要在 Derived 构造列表中对 Base 进行构造,比如 Base(10)。

#include <iostream>
#include <string>class Base {
public:Base(int i) : i_(i) {std::cout << "Base(), i = " << i_ << std::endl;}private:int i_;
};class Derived : public Base {
public:Derived() {std::cout << "Derived(), i " << Base::i_ << std::endl;}
};int main() {Derived d;return 0;
}

4 私有继承,继承和组合

在讨论设计模式的时候,有一个原则经常被提到: 多用组合,少用继承,能用组合就用组合,万不得已的时候才使用继承。

私有继承的两个特点:

(1)私有继承的派生类指针不能赋值给基类指针

(2)私有继承之后,基类中的 public 和 protected 成员,在子类中都变成了 private 属性,不能通过对象来访问

比如对于汽车这个对象,包括汽车发动机,悬架,转向 3 个主要的系统,我们在描述汽车的时候,如果使用私有继承的方式继承了发动机,悬架,转向 3 个类,是可以实现的,但是从语义上是不通的;使用组合的方式,在语义上是相通的,因为汽车是由这 3 个对象组合而成的。

如下是一个私有继承和组合的例子,Steering 表示转向系统,BydCar 私有继承了 Steering 类,TeslaCar 使用的组合。

#include <iostream>
#include <string>class Steering {
public:Steering() {std::cout << "Steering()" << std::endl;}~Steering() {std::cout << "~Steering()" << std::endl;}void Turn() {std::cout << "Steering() Turn()" << std::endl;}
};class BydCar : private Steering {
public:void Turn() {std::cout << "BydCar() Turn()" << std::endl;Steering::Turn();}
};class TeslaCar {
private:Steering steer;public:void Turn() {std::cout << "TeslaCar() Turn()" << std::endl;steer.Turn();}
};int main() {BydCar byd;TeslaCar tesla;byd.Turn();tesla.Turn();return 0;
}

使用组合的时候,一般组合的各个子元素都是已经实现的最终的结果,组合的元素是一个基本的元素,组合之后不能对这些基本元素进行修改,并且不能访问元素中的私有成员;使用继承的时候,基类可以是一个抽象类,派生类中也可以重写基类的函数。

设计原则中有一个是对修改关闭,对扩展开开放。这两个方面和继承与组合也有一定的对应关系,组合相当于扩展,继承可以修改,对组合开放相当于优先选用组合,对修改关闭相当于少用继承。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/713787.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于springboot+vue的纺织品企业财务管理系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

Socket网络编程(五)——TCP数据发送与接收并行

目录 主要实现需求TCP 服务端收发并行重构启动main方法重构重构分离收发消息的操作重构接收消息的操作重构发送消息TCPServer调用发送消息的逻辑监听客户端链接逻辑重构Socket、流的退出与关闭 TCP 客户端收发并行重构客户端 main函数重构客户端接收消息重构客户端发送消息重构…

Zookeeper学习1:概述、安装、应用场景、集群配置

文章目录 概述安装LinuxWindows 配置参数集群参考配置文件配置步骤流程启动 概述 Zookeeper&#xff1a; 为分布式框架组件提供协调服务的中间件 【类似&#xff1a;文件系统通知机制】 负责存储上下层应用关系的数据以及接收观察者注册监听&#xff0c;一旦观察查关心的数据发…

笔记73:ROS中的各种消息包

参考视频&#xff1a; 33.ROS 的标准消息包 std_msgs_哔哩哔哩_bilibili 34. ROS 中的几何包 geometry_msgs 和 传感器包 sensor_msgs_哔哩哔哩_bilibili 标准消息包&#xff1a;std_msgs常用消息包&#xff1a;common_msgs导航消息包&#xff1a;nav_msgs几何消息包&#xf…

实战分享:Tomcat打破双亲委派模型,实现Web应用独立与安全隔离的奥秘

目录 一、JVM 类加载机制 二、Tomcat 类加载器 2.2 findClass 介绍 3.2 loadClass 介绍 三、web应用隔离 3.1 Spring 加载问题 在开始文章内容之前&#xff0c;先来看三个问题 假如在 Tomcat 上运行了两个 Web 应用程序&#xff0c;两个 web 应用中有同名的Servlet&#xf…

C++数据结构与算法——二叉树的属性

C第二阶段——数据结构和算法&#xff0c;之前学过一点点数据结构&#xff0c;当时是基于Python来学习的&#xff0c;现在基于C查漏补缺&#xff0c;尤其是树的部分。这一部分计划一个月&#xff0c;主要利用代码随想录来学习&#xff0c;刷题使用力扣网站&#xff0c;不定时更…

AGI概念与实现

AGI AGI&#xff08;Artificial General Intelligence&#xff09;&#xff0c;中文名为“通用人工智能”或“强人工智能”&#xff0c;是指通过机器学习和数据分析等技术&#xff0c;使计算机具有类似于人类的认知和学习能力的技术. 多模态的大模型 &#xff08;Multimodal…

详细介绍如何用windows自带Hyper-V安装虚拟机(windows11和ubuntu22)

通过系统自带的hyper-v安装windows11&#xff0c;舒服又惬意&#xff0c;相比用第三方虚拟机软件速度快很多。 硬件准备 准备 系统需要符合能安装 Hyper-V 的最低要求windows版本含Hyper-V的功能 电脑空间 电脑要有足够的空间来安装你这个虚拟机。根据自己的磁盘容量情况来规…

2673. 使二叉树所有路径值相等的最小代价

给你一个整数 n 表示一棵 满二叉树 里面节点的数目&#xff0c;节点编号从 1 到 n 。根节点编号为 1 &#xff0c;树中每个非叶子节点 i 都有两个孩子&#xff0c;分别是左孩子 2 * i 和右孩子 2 * i 1 。 树中每个节点都有一个值&#xff0c;用下标从 0 开始、长度为 n 的整…

CloudCanal x Hive 构建高效的实时数仓

简述 CloudCanal 最近对于全周期数据流动进行了初步探索&#xff0c;打通了Hive 目标端的实时同步&#xff0c;为实时数仓的构建提供了支持&#xff0c;这篇文章简要做下分享。 基于临时表的增量合并方式基于 HDFS 文件写入方式临时表统一 Schema任务级的临时表 基于临时表的…

【Linux实践室】Linux初体验

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;Linux实践室、网络奇遇记 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 一. ⛳️任务描述二. ⛳️相关知识2.1 &#x1f514;Linux 目录结构介绍2.2 &#x1f514;Linux …

MySQL:一行记录如何

1、表空间文件结构 表空间由段「segment」、区「extent」、页「page」、行「row」组成&#xff0c;InnoDB存储引擎的逻辑存储结构大致如下图&#xff1a; 行 数据库表中的记录都是按「行」进行存放的&#xff0c;每行记录根据不同的行格式&#xff0c;有不同的存储结构。 页…

hippy 调试demo运行联调-mac环境准备篇

适用对于终端编译环境不熟悉的人看&#xff0c;仅mac端 hippy 调试文档官网地址 前提&#xff1a;请使用node16 联调预览效果图&#xff1a; 编译iOS Demo环境准备 未跑通&#xff0c;待补充 编译Android Demo环境准备 1、正常安装Android Studio 2、下载Android NDK&a…

Windows系统误删文件恢复

最近很多用户反馈误删文件的场景比较多.下面华仔将讲解数据恢复的原理和过程.以及一些注意事项。 建议的数据恢复软件 1.EaseUS Data Recovery Wizard(易我数据恢复)需要断网使用 2.Wondershare Recoverit(万兴数据恢复)&#xff0c; Windows系统删除文件原理&#xff1a;如果是…

HTTPS是什么,详解它的加密过程

目录 1.前言 2.两种加密解密方式 2.1对称加密 2.2非对称加密 3.HTTPS的加密过程 3.1针对明文的对称加密 3.2针对密钥的非对称加密 3.3证书的作用 1.前言 我们知道HTTP协议是超文本传输协议,它被广泛的应用在客户端服务器上,用来传输文字,图片,视频,js,html等.但是这种传…

java数据结构与算法刷题-----LeetCode572. 另一棵树的子树(经典题,树字符串化KMP)

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 文章目录 1. 暴力求解&#xff0c;深度优先2. KMP算法进行串匹配 1. 暴力求…

WinForm、Wpf自动升级 AutoUpdater.NET

Github AutoUpdater.NET 目录 一、IIS部署 更新站点 二、创建Winform 一、IIS部署 更新站点 IIS默认站点目录下创建 目录 Downloads、Updates Updates目录创建文件 UpdateLog.html、AutoUpdaterStarter.xml UpdateLog.html&#xff1a; <html><body><h1…

mysql学习--binlog与gtid主从同步

基础环境 基于centOS7-MySQL8.0.35版本 我们先准备一台主服务器两台从服务器来实现我们主从同步的诉求 Master&#xff1a;192.168.75.142 slave1:192.168.75.143 slave&#xff1a;192.168.75.145 binlog主从同步 主库配置 #我们需要在主从库中都需要添加server_id&am…

大龙谈智能内容开通视频号啦

大家好&#xff0c;大龙谈只能内容开通视频号了&#xff0c;欢迎大家扫码关注&#xff1a;

RISC-V特权架构 - 中断与异常概述

RISC-V特权架构 - 中断与异常概述 1 中断概述2 异常概述3 广义上的异常3.1 同步异常3.2 异步异常3.3 常见同步异常和异步异常 本文属于《 RISC-V指令集基础系列教程》之一&#xff0c;欢迎查看其它文章。 1 中断概述 中断&#xff08;Interrupt&#xff09;机制&#xff0c;即…