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

《Effective C++中文版,第三版》读书笔记6

条款32:确定你的public继承塑模出is-a关系

简单知识点回顾(若不知道那就是扫盲了):

is-a关系:子类public继承父类。比如说Apublic继承了B。我们可以说A是B的一种特殊情况

has-a关系:指的是一种组合关系,是关联关系中的一种(一个类中有另一个类的实例),是整体和部分的关系。

更通俗点讲:其实就是这两种关系的字面意思。不用特别记忆。

真理:代码编译通过并不代表就可以正确运行

“public继承”意味着is-a

​ 适用于base classes身上的每一件事情也一定适用于derived classed身上。

是不是可以这么理解:

​ 我们在编写base classes时,应该让其更普遍一点。

条款33:避免遮掩继承而来的名字

derived classes 内的名称会遮掩base classes内的名称

为了让被遮掩的名称再见天日,可以适用using声明式或转交函数

using声明式会令继承而来的某个给定名称的所有同名函数在derived class都可见

何时使用这两种方式?

using声明式子

​ 如果你继承base class并加上重载函数,而你又希望重新定义或覆写(推翻)其中的一部分,那么就需要为那些原本被遮掩的每个名称引入一个using声明式子。

转交函数:

​ 有时候并不想继承(不能是public继承)base classes的所有函数,只想继承某一个版本的时候。就可以些一个转交函数,在函数内以"base class名称::函数名"的方式。

​ 并不是所有编译器都支持using式子,这个时候可以考虑使用转交函数

条款34:区分接口继承和实现继承

public继承由两部分组成:函数接口继承和函数实现继承

对于基类中的接口,子类往往可能有三个方面的考虑;

1.子类只希望继承基类成员函数的接口 (基类中的纯虚函数)

2.子类希望同时继承基类中的接口和实现,还希望能够覆写。(基类中的虚函数(非纯虚))

3.子类希望同时继承函数的接口和实现,并且不允许覆写任何东西。(基类中的non-virtual函数)

类的设计者常犯的两个错误:

1.基类中的所有函数都声明为non-virtual

2.基类中的所有成员函数都声明为virtual(构造函数除外)

有些时候使用非纯的虚函数定义的接口,子类可能忘记实现,子类特异性的行为可能用基类的函数不适用:

这个时候可以考虑带定义纯虚函数,这样这个纯虚函数必须在子类中实现,子类无法忘记。

写一段体会一下(完善书中的例子)

class Shape
{
public:// 纯虚函数不能将其定义写在类内:pure-specifier on function-definition// 子类若想被实例化,那么继承了Shape,它就必须实现draw1,drawvirtual void draw() const = 0;// 这个纯虚函数,在基类这里不提供定义virtual void draw1() const = 0;// 非纯虚函数的目的是为了让子类继承该函数的接口和缺省实现virtual void error(const std::string &msg){std::cout << "Shape error msg = " << msg << std::endl;}int objectID() const{std::cout << "Hello world" << std::endl;return 0;}// 基类必须有一个虚的析构函数virtual ~Shape() = default;
};// 可以在类外实现纯虚函数的
void Shape::draw() const
{std::cout << "base pure virtual draw" << std::endl;
}class Rectangle : public Shape
{
public:Rectangle() {}~Rectangle() = default;// 继承自抽象class的子类,应该定义抽象基类中的纯虚函数,不定义的话,那么这个子类也是抽象class,无法实例化。virtual void draw() const override{std::cout << "Rectangls draw" << std::endl;}virtual void draw1() const override{std::cout << "Rectangls draw1" << std::endl;}
};class Ellipse : public Shape
{
public:Ellipse() {}~Ellipse() = default;virtual void draw() const override{std::cout << "Ellipse draw" << std::endl;}virtual void draw1() const override{std::cout << "Ellipse draw1" << std::endl;}virtual void error(const std::string &msg) override{std::cout << "Ellipse error msg = "<< msg << std::endl;}
};int main(int argc, char const *argv[])
{Rectangle test;Ellipse ellipse;test.draw();// 有定义的纯虚函数,可以通过这样的方式调用test.Shape::draw();// 非纯虚函数// 个人理解的缺省实现,意思就是你要实现就实现,不实现就算了。//  Rectangle 中没有实现自己的error,所以实际调用的是Shape的errortest.error(std::string("XXXXXXXXXX"));// Ellipse中实现了自己的error, 这样调用实际上调的是它自己的errorellipse.error(std::string("XXXXXXXXXX"));// 可以这样调用基类中的函数ellipse.Shape::error(std::string("XXXXXXXXXX"));// non-virtual 意味着基类不希望这个操作因为子类的不同而不同。test.objectID();ellipse.objectID();return 0;
}

条款35:考虑virtual函数以外的其它选择

这个条款涉及到了设计模式,这个相关内容是我的弱项,但是已经纳入了强化学习内容。后续会出设计模式的学习

条款36:绝不重新定义继承而来的non-virtual函数

原因:

1.non-virtual 不是动态绑定的,无法通过基类指针访问子类的non-virtual函数,这样只能访问到基类的vritual

2.public继承是is-a的,但是重定义non-virtual后,通过子类访问non_virtual的表现出来的行为已经和基类的non_virtual不一样了。

写一段:

#include <iostream>class Base
{
public:void non_virtual(){std::cout << "It is Base non_virtual" << std::endl;}virtual void virtual1() const = 0;virtual ~Base() = default;
};// 要想为纯虚函数添加定义,只能在类外,类内会报错。
void Base::virtual1() const
{std::cout << "It is Base virtual1" << std::endl;
}class sun1 : public Base
{
public:sun1() {}~sun1() = default;void non_virtual(){std::cout << "It is sun1 non_virtual" << std::endl;}virtual void virtual1() const{std::cout << "It is sun1 virtual1" << std::endl;}
};int main(int argc, char const *argv[])
{Base *bp1 = new sun1;bp1->non_virtual();bp1->virtual1();// 按照public is-a 的这种思维,我们通过sun11访问non_virtual()的行为应该与基类中的一致// 但是实际上访问的是sun1自己的non_virtual(),那就违反了is-a这种关系了。sun1 sun11;sun11.non_virtual();// sun11.Base::non_virtual();return 0;
}// 输出结果
// It is Base non_virtual
// It is sun1 virtual1
// It is sun1 non_virtual

条款37:绝不重新定义继承而来的缺省参数值

静态类型:
在程序中被声明时所采用的类型
动态类型:
在运行的时候才能确定其类型
静态绑定:(前期绑定 early bingding)
在声明时就已经确定了其运行期间的样子。
动态绑定:(后期绑定,late binding)
在运行的时候才决定其真实的类型。
知识点:
virtual函数是动态绑定的,但是其缺省参数是静态绑定的。
为什么C++坚持virtual函数是动态绑定,但是缺省参数值是静态绑定呢?
运行期效率。为了程序的执行速度和编译器实现上的简易度。
请记住:
绝对不要重新定义一个继承而来的缺省参数值。

写一段:

#include <iostream>
#include <string>// 完善例子部分
class Shape
{
public:enum ShapeColor{Red,Green,Blue};void draw1(ShapeColor color = Red) const{doDraw(color);}//为什么要定义成纯虚函数? 目的是为了让子类必须实现,不实现无法实例化。防止忘了。virtual void draw(ShapeColor color = Red) const = 0;virtual ~Shape() = default;private:virtual void doDraw(ShapeColor color) const = 0;
};class Rectangle : public Shape
{
public:Rectangle() {}~Rectangle() = default;virtual void draw(ShapeColor color = Green) const{std::cout << "Rectangle draw color = " << color << std::endl;}private:virtual void doDraw(ShapeColor color) const{std::cout << "Rectangle doDraw color = " << color << std::endl;}
};class Circle : public Shape
{
public:Circle() {}~Circle() = default;virtual void draw(ShapeColor color) const{std::cout << "Circle draw color = " << color << std::endl;}private:virtual void doDraw(ShapeColor color) const{std::cout << "Circle doDraw color = " << color << std::endl;}
};void drawFunc(Shape *sp)
{sp->draw();
}void drawFunc2(Shape *sp)
{sp->draw1();
}int main(int argc, char const *argv[])
{Rectangle rectangle, *rp = &rectangle;Circle circle, *rc = &circle;// 缺省参数是静态绑定的,所以这样定义绑定的静态参数就是自己的rectangle.draw();circle.draw(circle.Green);// 导致有问题的用法drawFunc(rp);drawFunc(rc);// 替代方法: 将带有默认参数的定义为non-virtual, 然后调用一个私有的纯虚函数不带默认参数,子类覆写这个私有的virtual就行。drawFunc2(rp);drawFunc2(rc);// 是不是可以将所有的draw()的默认参数都改成red是不是就行了?// 但是如果某一天修改了基类的draw()的默认参数,那么所有子类都要跟着改。不修改的话一样的存在“重复定义一个继承而来的缺省参数值”问题return 0;
}

条款38:通过复合塑模出has-a或‘根据某物实现出’

复合是类型之间的一种关系,当某种类型的对象内含有它种类型的对象。两种类型之间就是has-a关系

请记住:

复合的意义和public继承完全不同

在应用域,复合意味has-a.在实现域,复合意味着根据某物实现出

条款39:明智而审慎地适用private继承

两条规则:

​ 如果class之间的继承关系是private的那么编译器不会自动的将子类对象转换成父类对象。

​ 通过private继承的而来的所有成员,不管其在父类中是什么属性,在子类中都会变成private属性。

private继承意味着子类对象根据基类对象实现而得。(这点和复合类型(has-a)很想)

如果可在复合类型(has-a)和private二者之间选择,那么优先选择复合

什么情况下使用private继承?

当子类想要访问基类的protect成分,或者为了重新定义一个或多个virtual函数

基类不含任何数据。没有non-static成员变量,没有virtual函数,没有virtual base class

小知识点:

C++裁定凡是独立(非附属)对象都必须有非零大小的空间。

标题解释:在考虑所有其它方案之后,如果仍然认为private继承是最佳办法,这是才使用private

请记住:

​ private继承意味着根据某物实现出。它通常比复合的级别低。如果子类要访问基类的protect成员。或者要重新定义继承而来的virtual函数时,这么设计时合理的

private继承可以造成empty base最优化。这个对于致力于“对象尺寸最小化”的程序库开发人员而言,可能很重要。

条款40:明智而审慎地适用多继承

请记住:

多重继承比单一继承复杂。他可能导致歧义性,以及对virtual继承的需要

virtual继承会增加大小、速度、初始化(及赋值)复杂度等等成本。如果virtual base classes 不带任何数据,将是最具实用价值的情况。

多重继承的确有正当用途。 其中一个情节涉及“public继承某个interface class”和 “private继承某个协助实现class”的两相组合

相关文章:

《Effective C++中文版,第三版》读书笔记6

条款32&#xff1a;确定你的public继承塑模出is-a关系 简单知识点回顾&#xff08;若不知道那就是扫盲了&#xff09;&#xff1a; is-a关系&#xff1a;子类public继承父类。比如说Apublic继承了B。我们可以说A是B的一种特殊情况 has-a关系&#xff1a;指的是一种组合关系&…...

【Docker 】Docker 客户端,容器使用,启动容器,启动已停止运行的容器,停止一个容器,进入容器

作者简介&#xff1a; 辭七七&#xff0c;目前大一&#xff0c;正在学习C/C&#xff0c;Java&#xff0c;Python等 作者主页&#xff1a; 七七的个人主页 文章收录专栏&#xff1a; 七七的闲谈 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&#x1f…...

CTFshow 菜狗杯 web方向 全

文章目录 菜狗杯 web签到菜狗杯 web2 c0me_t0_s1gn菜狗杯 我的眼里只有$菜狗杯 抽老婆菜狗杯 一言既出菜狗杯 驷马难追菜狗杯 TapTapTap菜狗杯 Webshell菜狗杯 化零为整菜狗杯 无一幸免菜狗杯 无一幸免_FIXED菜狗杯 传说之下&#xff08;雾&#xff09;菜狗杯 算力超群菜狗杯 算…...

深入理解sql:进阶版

目录 背景举例子查询和嵌套查询&#xff1a;联合查询&#xff08;UNION和UNION ALL&#xff09;&#xff1a;窗口函数&#xff1a;CTE&#xff08;公共表达式&#xff09;&#xff1a;索引优化&#xff1a;事务隔离级别和锁定&#xff1a;性能优化&#xff1a;存储过程和函数&a…...

day31 | 455.分发饼干、376. 摆动序列、53. 最大子序和

目录&#xff1a; 解题及思路学习 455. 分发饼干 假设你是一位很棒的家长&#xff0c;想要给你的孩子们一些小饼干。但是&#xff0c;每个孩子最多只能给一块饼干。 对每个孩子 i&#xff0c;都有一个胃口值 g[i]&#xff0c;这是能让孩子们满足胃口的饼干的最小尺寸&#…...

C# textBox 右键菜单 contextMenuStrip

需求&#xff1a; 想在上图空白处可以右键弹出菜单&#xff0c;该怎么做呢&#xff1f; 1.首先&#xff0c;拖出一个 ContextMenuStrip。 随便放哪里都行&#xff0c;如下: 2.在textBox里关联这个“右键控件”即可&#xff0c;如下&#xff1a; 最终效果如下&#xff1a; 以上…...

TCP拥塞控制详解 | 7. 超越TCP

网络传输问题本质上是对网络资源的共享和复用问题&#xff0c;因此拥塞控制是网络工程领域的核心问题之一&#xff0c;并且随着互联网和数据中心流量的爆炸式增长&#xff0c;相关算法和机制出现了很多创新&#xff0c;本系列是免费电子书《TCP Congestion Control: A Systems …...

stm32之26.spi外设

...

C++信息学奥赛1177:奇数单增序列

#include<bits/stdc.h> using namespace std; int main(){int n;cin>>n; // 输入整数 n&#xff0c;表示数组的大小int arr[n]; // 创建大小为 n 的整型数组for(int i0;i<n;i) cin>>arr[i]; // 输入数组元素for(int i0;i<n;i){ // 对数组进行冒泡排序f…...

Java的数组是啥?

1.数组是啥&#xff1f; 数组是一块连续的内存&#xff0c;用来存储相同类型的数据 &#xff08;1&#xff09;如何定义数组&#xff1f; 1.int[] array {1,2,3,4} new int[]{1,2,3,4};//这里的new是一个关键字&#xff0c;用来创建对象 2.数组就是一个对象 动态初始化 …...

我的私人笔记(安装hadoop)

1.安装hadoop01环境 注需安装最小安装和使用英文界面 2.安装群集 // 获得网关IP&#xff1a;192.168.80.2 获得子网掩码&#xff1a;255.255.255.0 // 获得网段&#xff1a;[起始IP地址]192.168.128 --- [结束IP地址]192.168.80.254 // 计划集群的ip和主机名 //192.168.80.…...

【板栗糖GIS】——360浏览器的下载图标隐藏在内部不方便,怎么修改

目录 1. 设置前的本来样子 2. 登录360的皮肤中心 3. 使用se13的经典皮肤 最近edge浏览器最近使用bilibili和notion都非常卡&#xff0c;时不时崩溃&#xff0c;不得不换浏览器使用&#xff0c;试来试去360浏览器最得我心&#xff0c;只不过广告太多&#xff0c;调教也是花了…...

SpringMVC之文件上传和下载

文章目录 前言一、文件下载二、文件上传总结 前言 实现下载文件和上传文件的功能。 一、文件下载 使用ResponseEntity实现下载文件的功能 RequestMapping("/testDown") public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOEx…...

简单了解OSI网络模型

目录 一、协议是什么&#xff1f; 二、OSI七层模型 三、TCP/IP五层模型 一、协议是什么&#xff1f; 协议顾名思义就是通过大家伙一起协商讨论达成的统一规则和标准。网络协议就是规定用户数据信息如何在网络上传播以及实现某种网络技术所要遵循的统一标准和规则。 二、OSI…...

服务网格实施周期缩短 50%,丽迅物流基于阿里云 ACK 和 ASM 的云原生应用管理实践

作者&#xff1a;王夕宁、 刘强、 华相 公司介绍 丽迅物流是百丽旗下专注于时尚产业、为企业提供专业物流及供应链解决方案的服务商。其产品服务主要包括城市落地配、仓配一体、干线运输及定制化解决方案。通过自研智能化物流管理平台&#xff0c;全面助力企业合作集约化发展…...

bpmnjs Properties-panel拓展(属性设置篇)

最近有思考工作流相关的事情&#xff0c;绘制bpmn图的工具认可度比较高的就是bpmn.js了&#xff0c;是一个基于node.js的流程图绘制框架。初始的框架只实现了基本的可视化&#xff0c;想在xml进行客制化操作的话需要拓展&#xff0c;简单记录下几个需求的实现过程。 修改基础 …...

Debian系统上通过NFS挂载远程服务器硬盘

步骤 1&#xff1a;配置远程服务器 在拥有硬盘内容的远程服务器上&#xff0c;进行以下配置&#xff1a; 安装NFS服务器软件&#xff1a; sudo apt-get update sudo apt-get install nfs-kernel-server编辑NFS服务器配置文件 /etc/exports&#xff0c;添加需要共享的目录及其权…...

【Linux】以太网协议以及MTU

以太网协议 数据链路层的功能以太网的数据格式MTUMTU对IP协议的影响MTU对UDP协议的影响MTU对TCP协议的影响 数据链路层的功能 数据链路层的主要功能是&#xff1a;控制链路。包括数据链路的建立、链路的维护和释放。MAC寻址也是它的功能&#xff0c;寻址是指计算机网卡的MAC地…...

UE5打完包后,启动程序不能全屏

最近看到ue5的打包程序后不能默认自动全屏&#xff0c;效果如下&#xff0c;发现并不是全屏的&#xff0c;而且就算点击放大也不是全屏 解决办法&#xff1a;设置如下之后在打包就可以了 但是会一直打印错误的日志&#xff0c;不过这个不影响使用...

财务部发布《企业数据资源相关会计处理暂行规定》

导读 财务部为规范企业数据资源相关会计处理&#xff0c;强化相关会计信息披露&#xff0c;根据《中华人民共和国会计法》和相关企业会计准则&#xff0c;制定了《企业数据资源相关会计处理暂行规定》。 加gzh“大数据食铁兽”&#xff0c;回复“20230828”获取材料完整版 来…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南

文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

在Ubuntu24上采用Wine打开SourceInsight

1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...

基于SpringBoot在线拍卖系统的设计和实现

摘 要 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统&#xff0c;主要的模块包括管理员&#xff1b;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...

并发编程 - go版

1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程&#xff0c;系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

提升移动端网页调试效率:WebDebugX 与常见工具组合实践

在日常移动端开发中&#xff0c;网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时&#xff0c;开发者迫切需要一套高效、可靠且跨平台的调试方案。过去&#xff0c;我们或多或少使用过 Chrome DevTools、Remote Debug…...

零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程

STM32F1 本教程使用零知标准板&#xff08;STM32F103RBT6&#xff09;通过I2C驱动ICM20948九轴传感器&#xff0c;实现姿态解算&#xff0c;并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化&#xff0c;适合嵌入式及物联网开发者。在基础驱动上新增…...