【effective c++】继承与面向对象设计

1.确定你的public继承塑造出is-a关系

public继承意味着is-a.适用于base classes身上的每一件事情一定也适用于derived classes身上,因为每一个derived classes对象也都是一个base class对象,反过来不成立。

2.避免隐藏继承而来的名称

c++名称查找不考虑类型,只考虑名称。

class Base
{
private:int x;
public:virtual void mf1() = 0;virtual void mf1(int){}virtual void mf2(){}void mf3(){}void mf3(double){}
};
class Derived :public Base
{
public:virtual void mf1(){}void mf3(){}void mf4(){}
};
/*
base class内所有名为mf1和mf3的函数都被derived class内的mf1和mf3函数遮掩掉
函数隐藏只与函数名称有关,与函数的参数类型、是否virtual无关,注意此处是静态绑定
若通过指针或引用来调用虚函数,此时是动态绑定,不会发生函数隐藏
*/ int main() {Derived d;int x = 1;d.mf1();//ok//d.mf1(x);//falsed.mf2();//okd.mf3();//ok//d.mf3(x);//false system("pause");return 0; }
class Base
{
private:int x;
public:virtual void mf1() = 0;virtual void mf1(int){}virtual void mf2(){}void mf3(){}void mf3(double){}
};class Derived :public Base
{
public:using Base::mf1;using Base::mf3;virtual void mf1(){}void mf3(){}void mf4(){}
};/*
如果你继承base class并且base class中有重载函数,而你又希望在派生类中重新定义其中一部分,那么你必须为那些
原本会被隐藏的每个名称引入一个using声明式,否则某些你希望继承的名称会被隐藏。using声明式会令继承而来的基类中某
给定名称之所有同名函数在derived class中都可见
*/ int main() {Derived d;int x = 1;d.mf1();//okd.mf1(x);//okd.mf2();//okd.mf3();//okd.mf3(x);//ok system("pause");return 0; }

3.区分接口继承和实现继承

  • 声明一个pure virtual函数的目的是为了让derived classes只继承函数接口

通常纯虚函数没有定义,但是可以为纯虚函数提供定义,调用它的唯一途径是调用时明确指出其class名称

class Shape
{
public:virtual void draw() const = 0{}virtual void error(const string& msg);int objectID() const;
};class Rectangle:public Shape
{
public:virtual void draw() const{}
};class Ellipse:public Shape
{
public:virtual void draw() const {}
};int main()
{//Shape *ps = new Shape;//error 抽象类不能生成实例Shape *ps1 = new Rectangle;ps1->draw();Shape *ps2 = new Ellipse;ps2->draw();ps1->Shape::draw();ps2->Shape::draw();system("pause");return 0;
}
  • 声明impure virtual函数的目的,是让derived class继承该函数的接口和缺省实现

如果有的派生类只想继承接口但忘记重新定义该虚函数,这样一来就会使用基类缺省实现,出错:将接口和缺省实现分开,派生类如果想使用缺省实现,需要去显式调用

方案一:将接口定义为纯虚函数,缺省实现定义为non-virtual函数,派生类若想使用缺省实现,需要在继承而来的纯虚函数中调用该non-virtual函数,派生类若只想继承接口,此时不会忘记重新定义该虚函数了,因为不重新定义的话就是抽象类,无法实例化

方案二:纯虚函数必须在derived class中重新定义,但基类中也可以为纯虚函数提供定义,该定义作为缺省实现。派生类若想使用缺省实现,需要在在继承而来的纯虚函数中通过基类名来显式调用上述函数定义

  • 声明non-virtual函数的目的是为了令derived class继承函数的接口及一份强制性实现

4.考虑virtual函数以外的其他选择

  • NVI手法:令用户通过public non-virtual成员函数间接调用private virtual函数
  • 由Function Pointer实现strategy模式

运用函数指针(作为类的成员变量)替换virtual函数,优点是每个对象可各自拥有自己的对应函数及可在运行期改变该函数,缺点是可能会降低类的封装性

  • 由tr1::function完成strategy模式
  • 古典的strategy模式

5.绝不重新定义继承而来的non-virtual函数(设计理念)

6.绝不重新定义继承而来的缺省参数值

虚函数是动态绑定的,而缺省参数值是静态绑定的。

class Shape
{
public:enum ShapeColor{Red,Green,Blue};virtual void draw(ShapeColor color = Red) const = 0;
};class Circle :public Shape
{
public:/*当用户以对象调用此函数,一定要指定参数值。因为静态绑定下这个函数并不从其基类继承缺省参数值。但若以指针或引用调用此函数,可以不指定参数值,因为动态绑定下这个函数会从其基类继承缺省参数值*/virtual void draw(ShapeColor color) const;
};

7.通过复合composition塑造出has-a或"根据某物实现出"

复合:某种类型的对象内含别的类型的对象,复合意味着has-a或is-implemented-in-terms-of

8.明智地使用private继承

  • 如果class之间的继承关系是private,编译器不会自动将一个derived class对象转换为一个base class对象(将派生类实参传递给基类形参,编译出错)
  • 由private base class继承而来的所有成员,在derived class中都会变成private属性,纵使它们在base class中原本是protected或public属性,即派生类对象不能调用基类方法

private继承意味着implemented-in-terms-of,private继承纯粹只是一种实现技术。

9.明智地使用多重继承

未完待续

转载于:https://www.cnblogs.com/ljygoodgoodstudydaydayup/p/5819125.html

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

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

相关文章

Android Camera HAL浅析

1、Camera成像原理介绍 Camera工作流程图 Camera的成像原理可以简单概括如下: 景物(SCENE)通过镜头(LENS)生成的光学图像投射到图像传感器(Sensor)表面上,然后转为电信号,经过A/D(模数转换)转换…

win10 下pycharm+anaconda 编译生成pyd文件

由于生产部署的问题,需要把用python写的深度学习代码编译为可被调用的文件。上网搜索了下,暂时了解到win10下pyd文件比较流行。下面是直接引用某位博主的结论,个人感觉总结的很好。其中Cython库将已有的Python代码转化为C语言的代码&#xff…

ANSYS——初学路径之路径的定义、作用以及ansys路径模块GUI的操作解释

目录 一、路径的定义 二、路径的作用 三、路径GUI相关操作面板解释 1、路径的定义

JVM(4)之 使用MAT排查堆溢出

为什么80%的码农都做不了架构师?>>> 接下来讲解如何设置以及当发生堆溢出的时候怎么排查问题。先看一小段代码:   代码中使用了一个无限循环来为list添加对象,如果采用默认的堆大小的话可能要等待好久才能出现堆溢出的错误&a…

caffe 中的一些参数介绍

转自:http://blog.csdn.net/cyh_24/article/details/51537709 solver.prototxt net: "models/bvlc_alexnet/train_val.prototxt" test_iter: 1000 # test_interval: 1000 # base_lr: 0.01 # 开始的学习率 lr_policy: "step" # 学习率的…

ANSYS——相同模型不同创建方式的同载荷同约束下的比较

目录 1、问题描述: 2、相同部分: 3、梁单元创建(BEAM) 4、实体单元创建

python 制作二进制文件数据集(bin)

为了方便进行深度学习的程序调用与实现,需要将excel的数据文件转换为二进制文件。好处就是接口统一,读写速度快,节约空间。 一、调用库 使用xlrd读入execel表格,经过处理后转换为对应的dataframe结构,再使用pickle库…

ConcurrentDictionary的ToDictionary

如果Value是引用&#xff0c;那么在使用Value.Clear()的时候。会清空Value的所有元素&#xff0c;但是不会改变Value的引用 private static void Main(){try{var concurrentDictionary new ConcurrentDictionary<string, List<int>>();concurrentDictionary.TryAd…

远程连接mysql数据库注意点记录

一、如何新建独立帐号并设置权限 这里我使用Navicat作为我的数据库管理工具&#xff0c;打开Navicat。 选择“用户”--“新建用户” 输入用户名、主机、密码&#xff0c;需要注意的是&#xff0c;主机那不是写“localhost”&#xff0c;而是写“%” 然后可以设置“服务器权限”…

【域控管理】父域的搭建

从这篇博文开始&#xff0c;所有的域控系统都是在虚拟机中创建的。 在VM里安装Windows Server 2008 R2的方法就不多说了&#xff0c;无脑式安装&#xff0c;略过不提。 进到系统桌面&#xff0c;打开本地连接&#xff0c;设置网卡的IP地址&#xff0c;如下图&#xff1a; 注意&…

ANSYS——网格划分的不同方法以及GUI模块的操作(自由网格、映射网格、扫掠、拖拉)

目录 一、GUI操作模块的解释 二、不同的网格划分方法和网格类型

tensorflow2 tensorboard可视化使用

tensorflow2自带tensorboard&#xff0c;所以不必再自行安装tensorboard。 一、使用环境 win10 x64&#xff1b; anaconda3tensorflow2&#xff08;cpu版本&#xff09; 二、使用 1.在模型训练之前插入以下代码 log_dir os.path.join(logs) #win10下的bug&#xff0c; if…

oracle字符乱码的解决方法

原因分析&#xff1a; 客户端字符集就是为了让数据库知道我们传递过去的字符是属于哪种字符集&#xff0c;以便于Oracle在存储字符时进行相应的编码映射&#xff08;查看客户端字符集通过查找注册表中的NLS_LANG键&#xff09;。在客户端查询数据库时显示字符的时候我们使用的是…

[]End of 2017OI

今年大概到此为止了&#xff0c;现在这个算是做一个简短的阶段性总结吧 今年打的第一场大概是省赛&#xff0c;当时整个人处于&#xff08;迷茫&#xff0c;不知道选物理还是选信息备战中考持续摸鱼OI颓废&#xff09;的状态&#xff0c;KMP都不会导致签到题都没有分&#xff0…

Javascript闭包——懂不懂由你,反正我是懂了

摘要&#xff1a;“如果你不能向一个六岁的孩子解释清楚&#xff0c;那么其实你自己根本就没弄懂。”好吧&#xff0c;我试着向一个27岁的朋友就是JS闭包(JavaScript closure)却彻底失败了。越来越觉得国内没有教书育人的氛围&#xff0c;为了弄懂JS的闭包&#xff0c;我使出了…

ANSYS——命令流学习(材料属性设置、建模的命令流)

目录 ANSYS基本关键字 命令流的整体结构、每个模块的标识 !文件说明段/BATCH

IOS用CGContextRef画各种图形(文字、圆、直线、弧线、矩形、扇形、椭圆、三角形、圆角矩形、贝塞尔曲线、图片)...

首先了解一下CGContextRef: An opaque type that represents a Quartz 2D drawing environment. Graphics Context是图形上下文,可以将其理解为一块画布,我们可以在上面进行绘画操作,绘制完成后,将画布放到我们的view中显示即可,view看作是一个画框. 自己学习时实现的demo&…

eclipse maven jetty插件方式启动项目

2019独角兽企业重金招聘Python工程师标准>>> 1. 2.点击run即可启动项目 参考:maven命令具体含义请自行百度.例子:maven clean的作用 / maven djetty 转载于:https://my.oschina.net/u/3146772/blog/1576710

AWS S3 Windows系统下的文件夹上传基于python

AWS S3 上传文件&#xff0c;基于cmd命令行发现无法上传文件夹&#xff0c;只能上传单个文件&#xff0c;不知道是我能力不行还是什么原因&#xff0c;如果有大佬了解的可以在下面评论下! 一、环境配置 1.win10 X64&#xff1b; 2.awscli 1.18.91 3.python&#xff08;程序…

51nod 1004 【快速幂】

思路&#xff1a; 掐住最后一位&#xff0c;快速幂一发就好了 #include<cstdio> #include <map> #include<iostream> #include<string.h> #include<algorithm> using namespace std;typedef __int64 LL;int cal(int g,int x) {int ans1;while(g…