Effective C++ 摘记(三)

2024-01-05 08:48
文章标签 c++ effective 摘记

本文主要是介绍Effective C++ 摘记(三),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


(六)、继承与面向对象设计

三十二、确定public继承塑膜出is-a关系

如果子类为public继承基类, 

class D:public B

{

.....
}

表明,子类的对象也一定属于基类,则适用于基类的事情也适用于子类。


三十三、避免遮掩继承来的名称

基类的重载函数一旦在子类被重写后,其他的同名函数无法访问。

例如:

class Base{
private:int x;
public:void mf1();vodi mf1(int x);
};
class Derived: public Base{
private:int y;
public:void mf1(double );
};  
Derived d;
d.mf1(2.0);		//父类中的mf1(), mf1(int) 在子类中被覆盖,子类中只有 mf1(double) 可见。

可以在子类中提前注明 using Base::functions 来标明函数的作用范围。



或者使用转交函数来实现 选择继承基类的部分函数。


转交函数,即在子类的同名函数中调用父类的函数,从而避免子类的函数覆盖父类的函数的现象出现。

inline转交函数的另一个作用是为那些不支持using声明式的老旧编译器开辟一条新路,将继承而得的名称汇入 derived作用域内。


三十四、区分接口继承和实现继承

接口继承(只继承接口,实现由子类自己来写)和实现继承(继承父类的接口和实现,子类的函数用父类的实现)不同,在public继承下,derived classes总是继承base class的接口。

纯虚函数( pure virtual )指定接口继承(基类不对函数进行实现 声明为 virtual xxx = 0;,子类必须对函数进行实现);

虚函数( impure virtual ) 指定接口和默认实现(基类声明函数,同时实现函数的一个缺省版本,子类如果也对函数进行实现,则使用子类的函数,否则使用缺省函数)

一般函数( non-virtaul )指定接口和强制实现(子类必须不能够再是实现函数,否则会出现覆盖<也可以采用方式进行避免>)。


三十五、考虑虚函数以外的选择

类的public成员函数调用类的私有成员函数,私有虚函数在父类被调用的时候自动多态,基本保留何时调用的权力,子类拥有修改功能的权力;

function函数指针对象使得函数指针更加灵活;

古典策略模式:

使得不同的功能通过继承HealthCalcFunc改变。

三十六、绝不定义继承的非虚 ( non-virtual ) 函数

重修继承的非虚函数导致函数的访问由指向对象的指针或引用类型决定。

如果基类的public函数 F 为non-virtual,则子类public继承之后,重新实现了F, 则使用基类指针pB(指向某子类对象D)和子类指针pD(指向相同的子类对象D)来调用函数 F 其结果不同,因为F 不是虚函数,不会进行动态绑定。


三十七、绝不定义继承的默认参数值

基类指针指向子类对象,重载的虚函数的默认参数来自于基类;(因此,不要重新定义继承的虚函数的默认参数值)

将默认参数函数声明为普通成员函数,通过 non-virtual 函数调用私有的 virtual 虚函数即可。


三十八、用复合塑膜出has-a和实现关系

has-a:对象的包含关系;

实现:对象对另一个对象进行具体特化。

在应用域,复合意味着has-a(有一个), 在实现域,复合意味着is-implemented-in-terms-of(根据某物实现出)


三十九、审慎使用private继承

私有继承表达的是实现关系 is-implemented-in-terms-of ,子类使用父类提供的接口,但是不继承;

能用复合不用私有继承;

私有继承方式:


子类中的void onTick转换为private,防止客户误以为可以调用该函数。


复合方式:

这样Widget的子类就不会修改onTick函数了,将内部类移出,换做声明可以降低耦合;

private继承的空基类的大小实际为0,一般对象大小不能为0



四十、审慎使用多重继承

使用虚基类导致速度变慢;

多重继承中使用公有继承继承接口,私有继承完成实现关系。


(七)、模板与泛型编程

四十一、隐式接口与编译多态

class是显示接口——函数签名,运行多态——虚函数;

template是隐式接口——有效表达式,编译多态——模板具体化与函数重载解析。

四十二、typename双重含义

模板声明中与class没有任何区别;

嵌套从属类型的显式指定,不能出现在基类列表和初始化列表中;

四十三、处理模板化基类名称

继承模板化基类的名称不能像继承一样使用:通过this->名字修饰、using基类<T>::名字、或者基类<T>::名字一共三种修饰方式。第三种导致虚函数功能失效。

四十四、参数无关代码抽离模板

将与模板无关的非类型参数转移到类内;

尽量降低与模板无关的类型参数的膨胀度。

四十五、运用成员函数模板接受兼容类型

成员函数使用函数模板兼容更多类型;

函数模板声明后的copy构造和编译器生成的并不同,需要单独处理。

四十六、类型转换时为模板定义非成员函数

对于模板化的类要支持双操作运算符重载,首先必须是非成员函数,另外为了能让模板具体化必须将函数定在类体内部,因此只能将之声明为友元类型。(并非模板类内的友元函数必须类内定义)。

四十七、使用traits类表现类型信息

STL五大迭代器:

1.输入迭代器:向前,一次一步,只读一次,istream_iterator

2.输出迭代器:向前,一次一步,只写一次, ostream_iterator

3.前向迭代器:向前,一次一步,可读可写多次,单向列表。

4.双向迭代器:向前向后,一次一步,可读可写多次,listsetmap

5.随机迭代器:向前向后,一次多步,可读可写多次,vectordequestring

实现迭代器累加操作时候需要根据迭代器类型执行不同的操作方式,这种判断属于编译时期的判断,不应该使用if语句!

可以根据iterator_traits提供的类别标签区分迭代器类型,类别标签是空结构体类型,将标签作为函数参数,可以保证编译器能在编译时期对类型进行检查。

现在就可以把doAdvance封装起来自动完成编译期类型判断。

四十八、模板元编程

让某些事情变得容易可能,将某些工作从运行期转移到编译期;

分支——借由模板特化实现;

循环——借由递归完成;

优点:保证度量单位的正确、优化矩阵运算生成客户定制设计模式实现品;

避免了生成某些特殊类型不适合的代码。

(八)、定制newdelete

四十九、new-handler行为

set_new_handler指定内存分配失败时调用的函数。

五十、newdelete合理替换时机

改善性能,内存对齐,heap错误调试,收集heap信息。

五十一、newdelete固守常规

new含有无限循环分配内存,无法分配调用new-handler,处理0字节和超额申请;

delete处理null指针和超额申请。

五十二、写了placement new就要写placement delete

placement new在已有的缓冲区内申请对象;

不要掩盖已有的版本。

(九)、杂项

五十三、不要忽视警告

严肃对待警告信息;

不过度依赖警告信息。

五十四、熟悉TR1标准库

智能指针、Boost库。

五十五、熟悉Boost

社群、网站;

TR1组件实现品。


原文地址:http://www.cnblogs.com/fanzhidongyzby/archive/2012/11/18/2775603.html

这篇关于Effective C++ 摘记(三)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/572315

相关文章

关于C++中的虚拟继承的一些总结(虚拟继承,覆盖,派生,隐藏)

1.为什么要引入虚拟继承 虚拟继承是多重继承中特有的概念。虚拟基类是为解决多重继承而出现的。如:类D继承自类B1、B2,而类B1、B2都继承自类A,因此在类D中两次出现类A中的变量和函数。为了节省内存空间,可以将B1、B2对A的继承定义为虚拟继承,而A就成了虚拟基类。实现的代码如下: class A class B1:public virtual A; class B2:pu

C++对象布局及多态实现探索之内存布局(整理的很多链接)

本文通过观察对象的内存布局,跟踪函数调用的汇编代码。分析了C++对象内存的布局情况,虚函数的执行方式,以及虚继承,等等 文章链接:http://dev.yesky.com/254/2191254.shtml      论C/C++函数间动态内存的传递 (2005-07-30)   当你涉及到C/C++的核心编程的时候,你会无止境地与内存管理打交道。 文章链接:http://dev.yesky

C++的模板(八):子系统

平常所见的大部分模板代码,模板所传的参数类型,到了模板里面,或实例化为对象,或嵌入模板内部结构中,或在模板内又派生了子类。不管怎样,最终他们在模板内,直接或间接,都实例化成对象了。 但这不是唯一的用法。试想一下。如果在模板内限制调用参数类型的构造函数会发生什么?参数类的对象在模板内无法构造。他们只能从模板的成员函数传入。模板不保存这些对象或者只保存他们的指针。因为构造函数被分离,这些指针在模板外

C++工程编译链接错误汇总VisualStudio

目录 一些小的知识点 make工具 可以使用windows下的事件查看器崩溃的地方 dumpbin工具查看dll是32位还是64位的 _MSC_VER .cc 和.cpp 【VC++目录中的包含目录】 vs 【C/C++常规中的附加包含目录】——头文件所在目录如何怎么添加,添加了以后搜索头文件就会到这些个路径下搜索了 include<> 和 include"" WinMain 和

C/C++的编译和链接过程

目录 从源文件生成可执行文件(书中第2章) 1.Preprocessing预处理——预处理器cpp 2.Compilation编译——编译器cll ps:vs中优化选项设置 3.Assembly汇编——汇编器as ps:vs中汇编输出文件设置 4.Linking链接——链接器ld 符号 模块,库 链接过程——链接器 链接过程 1.简单链接的例子 2.链接过程 3.地址和

C++必修:模版的入门到实践

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:C++学习 贝蒂的主页:Betty’s blog 1. 泛型编程 首先让我们来思考一个问题,如何实现一个交换函数? void swap(int& x, int& y){int tmp = x;x = y;y = tmp;} 相信大家很快就能写出上面这段代码,但是如果要求这个交换函数支持字符型

C++入门01

1、.h和.cpp 源文件 (.cpp)源文件是C++程序的实际实现代码文件,其中包含了具体的函数和类的定义、实现以及其他相关的代码。主要特点如下:实现代码: 源文件中包含了函数、类的具体实现代码,用于实现程序的功能。编译单元: 源文件通常是一个编译单元,即单独编译的基本单位。每个源文件都会经过编译器的处理,生成对应的目标文件。包含头文件: 源文件可以通过#include指令引入头文件,以使

C++面试八股文:std::deque用过吗?

100编程书屋_孔夫子旧书网 某日二师兄参加XXX科技公司的C++工程师开发岗位第26面: 面试官:deque用过吗? 二师兄:说实话,很少用,基本没用过。 面试官:为什么? 二师兄:因为使用它的场景很少,大部分需要性能、且需要自动扩容的时候使用vector,需要随机插入和删除的时候可以使用list。 面试官:那你知道STL中的stack是如何实现的吗? 二师兄:默认情况下,stack使

剑指offer(C++)--孩子们的游戏(圆圈中最后剩下的数)

题目 每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去

剑指offer(C++)--扑克牌顺子

题目 LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)...他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子.....LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为1