![](https://img-blog.csdnimg.cn/20201014180756918.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
Effective C++
闲鱼翻不了身
这个作者很懒,什么都没留下…
展开
-
条款 41 :了解隐式接口和编译器多态
条款 41 :了解隐式接口和编译器多态面向对象编程总是以显式接口和运行期多态来解决问题。我们看下面的代码:class Widget{ public: Widget(); virtual ~Widget(); virtual std::size_t size() const; virtual void normalize(); virtual swap(Widget& other); ...};void doProcessing(Wid原创 2021-11-28 23:06:20 · 161 阅读 · 0 评论 -
条款 40 :明智而省慎地使用多重继承
条款 40 :明智而省慎地使用多重继承Use multiple inheritance judiciously.多重继承是C++的一个特色。对于多重继承,C++社群也有两种观点,一种认为多重继承是好的,另一种则认为应不要使用多重继承。我们来看一段多重继承的代码:class BorrowableItem{//图书馆允许你借某些东西 public: void checkOut();//离开时进行检查 ...};class ElectronicGadget{ pr原创 2021-11-12 18:24:30 · 680 阅读 · 0 评论 -
条款 39 :明智而省慎地使用private继承
条款 39 :明智而省慎地使用private继承Use private inheritance judiciouslyprivate继承并不意味着一种is-a关系。我们来看看代码://和条款32,这次改用private继承class Person{...};class Student:private Person{...};//private继承void eat(const Person& p);//人都会吃void study(const Student& s);//学生原创 2021-11-12 18:24:01 · 117 阅读 · 0 评论 -
条款 38 :通过复合塑模出has-a或“根据某物实现出”
条款 38 :通过复合塑模出has-a或“根据某物实现出”Model “has-a” or “is-implemented-in-trems-of” through composition.**复合(composition)是类型之间的一种关系,当某种类型对象内含有其他类型对象时就是这种关系。**它实际上意味着一种has-a关系或“根据某物实现出”。这节不想写,下次一定...原创 2021-11-12 18:23:11 · 62 阅读 · 0 评论 -
条款 37 :绝不重新定义继承而来的缺省参数值
条款 37 :绝不重新定义继承而来的缺省参数值Never redefine a function’s inherited default parameter value我们在条款36刚刚说过继承non-virtual函数是错误的。所以本条款更确切的说是:绝不重新定义继承而来的带有缺省参数值的virtual函数。理由很明确:virtual是动态绑定,而缺省参数是静态绑定动态绑定又叫后期绑定,静态绑定又叫前期绑定。我们来复习一下两者区别吧:我们先说一下静态类型和动态类型的概念:对象的所谓静态类型就是原创 2021-11-12 18:22:16 · 396 阅读 · 0 评论 -
条款 36 :绝不重新定义继承而来的non-virtual函数
条款 36 :绝不重新定义继承而来的non-virtual函数Never redefine an inherited non-virtualfunctionclass B{ public: void f(); ...};class D:public B{...};D x;//x是一个类型为D的对象//1B* pB=&x;//获得一个指针指向xpB->f();//经由该指针调用f//2D* pD=&x;//获得一个指针指向xpD->原创 2021-11-12 18:21:45 · 245 阅读 · 0 评论 -
条款35 :考虑virtual函数以外的其他选择
条款35 :考虑virtual函数以外的其他选择这节好多设计模式相关,留着以后补。原创 2021-11-12 18:21:14 · 203 阅读 · 0 评论 -
条款 34 :区分接口继承和实现继承
条款 30 :考虑virtual函数以外的其他选择Consider alternative to virtual functions假设你在写一个游戏,其中有一个反映人物血量状态的函数,不同的人物有不同的生命计算方式,所以将其声明为virtual;我们没有声明为pure virtual意味着我们该给他一份缺省实现。class Game{ public: virtual int healthValue()const;//返回人物健康指数原创 2021-11-12 18:18:51 · 73 阅读 · 0 评论 -
条款 33 :避免遮掩继承而来的名称
条款 33 :避免遮掩继承而来的名称Avoid hiding inherited names.我们先来看看什么是遮掩:int x;fun(){ double x; cin>>x;}对于上面的代码来说我们输入的是double型的x,而不是int型的。因为他被遮掩了。C++的名称遮掩规则(name-hiding rules)所做的唯一事情就是:遮掩名称。至于名称是不是相同的类型并不重要。从上面的例子也能看出来。我们来看看继承中的名称遮掩:class Bas原创 2021-10-24 14:02:59 · 139 阅读 · 0 评论 -
条款 32 :确定你的public继承塑膜出is-a关系
条款 32 :确定你的public继承塑膜出is-a关系Make sure public inheritance models "is-a"public inheritance意味着"is-a"(是一种)的关系。如果B:????,则在任何需要B的地方,D一样可以排上用场。但是需要D的地方,B不见得有用。例如所有学生都是人,人能干的事,学生一定能干,但学生有的属性不是人人都会有。void eat(const Person& p);//任何人都会吃void study(const Stu原创 2021-10-24 14:02:25 · 76 阅读 · 0 评论 -
条款 31 将文件间的编译依存关系降至最低
条款 31 : 将文件间的编译依存关系降至最低Minimize compilation dependencies between filesC++没有把“将接口从实现中分离”这件事做得很好。Class的定义不止是叙述了类接口,还包括了十足的实现细节。例如下面代码:#include"Date"#include<string>class Person{public: Person(); std::string name()const; std::strin原创 2021-10-14 19:20:25 · 103 阅读 · 0 评论 -
条款 30 :透彻了解inlining的里里外外
条款 30 :透彻了解inlining的里里外外*Understand the ins and outs of inlining关于inline 函数:可以调用他们但是又不需要蒙受调用函数招致的额外开销。inline函数背后的整体观念是,将“对函数的每一个调用”都以函数本体替换之。这样的做法可能会导致目标代码增大,所以一般而言只对常用的短小函数声明为inline。inline只是对编译器的一个申请,而不是强制命令。inline函数通常被放在头文件内。对于virtual函数申请inline原创 2021-10-13 22:42:05 · 127 阅读 · 0 评论 -
条款 29 :为“异常安全”而努力是值得的
条款 29 :为“异常安全”而努力是值得的Strive for exception-safe code.假设有一个class用来表现带背景的GUI菜单。希望其用于多线程环境,所以他得有一个互斥器作为并发控制之用。class PrettyMenu{public: ... void changeBackground(std::istream& imgSrc);//改变背景图片 ...private: Mutex mutex;//互斥器 Image*原创 2021-10-13 22:15:05 · 117 阅读 · 0 评论 -
条款 28 :避免返回handles指向对象内部成分
条款 28 :避免返回handles指向对象内部成分Avoid returning “handles” to object internals请记住避免返回handles(包括references ,pointer,iterrator)指向对象内部。遵循这个条款可以增加封装性,帮助const成员函数德行为像个const,并将发生”虚吊号码牌“(dangling handles)的可能性降至最低。...原创 2021-10-07 19:08:33 · 146 阅读 · 0 评论 -
条款 27 :尽量少做转型动作
条款 27 :尽量少做转型动作Minimize casting.转型动作破坏了类型系统。C++的转型动作相较于C,Java,C#等更加危险。我们来回顾一下C的转型动作,我们称为”旧式转型“(old-style casts):(T) expression //将expression转型为TT(expression) //将expression转型为TC++还提供了四种新式转型(C+±style casts):const_cast<T>(expression)原创 2021-10-06 21:18:30 · 114 阅读 · 0 评论 -
条款 26 :尽可能延后变量定义式的出现时间
条款 26 :尽可能延后变量定义式的出现时间** Postpone variable definitions as long as possible**只要你定义了一个变量而且其类型带有构造和析构函数,那么程序的控制流到达这个定义式的时候你就要承受构造成本。你会说你不能定义一个不用的变量,话不说这么早,我们来看下列代码://这个函数过早定义变量encryptedstd::string encryptPassword(const std::string& password){ us原创 2021-10-05 21:20:43 · 100 阅读 · 0 评论 -
条款 25 :考虑写出一个不抛出异常的swap函数
条款 25 :考虑写出一个不抛出异常的swap函数Consider support for a non-throwing swap.所谓swap(置换)两对象值,意思是将两对象的值彼此赋予对方。标准库缺省swap函数典型实现如下:namespace std{ template<typename T> void swap(T& a,T& b){ T temp(a); a=b; b=temp; }}在上述代码中只要类型T支持copying,缺省的swa原创 2021-10-05 15:51:28 · 127 阅读 · 0 评论 -
条款 24 :若所有参数皆需类型转换,请为此采用non-member函数
这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入欢迎使用Markdown编辑器你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Mar原创 2021-10-03 15:57:52 · 98 阅读 · 0 评论 -
条款 23 :宁以non-member,non-friend替换member函数
条款 23 :宁以non-member,non-friend替换member函数Perfer non-member non-friend functions to member functions.越多东西被封装,我们改变那些东西的能力也就越大。这就是我们推崇封装的原因:他使我们能够改变事物而只影响有限客户。导致较大的封装性的是non-member,non-friend函数,因为他们并不增加 能够访问class内private数据成分的函数数量。//假设我们有一个类来表示网页浏览器//这样原创 2021-10-03 15:07:57 · 102 阅读 · 0 评论 -
条款 22 :将成员变量声明为private
条款 22 :将成员变量声明为privateDeclare data members private.如果你将成员变量声明为public,每个人都可以对他读写;但如果你以函数取得或设定其值,你就可以实现“不准访问”,“只读访问”,“读写访问”等。对读写这么细微的控制往往是必要的。对protectd的成员变量,他也和public一样缺乏封装性。其实只有两种访问权限:private(提供封装)和其他(不提供封装)。1. 切记将成员变量声明为private.这 可赋予客户访问数据的一致性,可以细原创 2021-10-02 23:43:04 · 161 阅读 · 0 评论 -
条款 21 :必须返回对象时,别妄想返回其reference
MFC基本绘图函数在Windows平台上,应用程序的图形设备接口被抽象为设备上下文CDC类。在微软基类库MFC中,CDC类是定义设备上下文的基类,封装了绘图所需的成员函数。CDC类结构与GDI对象CDC类CDC类派生了CClientDC类,CMetaFileDC类,CPaintDC类和CWindowDC类。CClientDC类:显示器客户区设备上下文类。只能在窗口的客户区绘图,(0,0)是客户去左上角。CMetaFileDC类:Windows图元文件设备上下文类。CMetaFileDC封装了在原创 2021-10-02 20:16:12 · 132 阅读 · 0 评论 -
条款 20 :宁以pass-by-reference-to-const替换pass-by-value
条款 20 :宁以pass-by-reference-to-const替换pass-by-valuePerfer pass by-reference-to-const to pass-by-value缺省情况下,C++以by-value方式传递对象至函数。除非特别指定,否则参数传递的是以实际实参的副本。这些副本由对象的复制构造函数产出,这可能使得pass-by-value成为昂贵(费时)的操作。//例子class Person{public: Person(); virtual ~Pe原创 2021-09-28 17:30:28 · 122 阅读 · 0 评论 -
条款 19 :设计class犹如设计type
条款19:设计class犹如设计typeTreat class design as type design设计一个新的class就像设计了一个新的类,设计一个优秀的class必须考虑下列问题:新的对象应该如何被创建和销毁? 这影响到类的构造函数,析构函数以及内存的分配函数和释放函数。对象的初始化和对象的赋值该有什么样的差别? 这决定了构造函数和赋值操作符的行为,以及他们的差异。新的type如果被pass by value(值传递),意味着什么? 这会影响到复制构造函数的实现。什么是新typ原创 2021-09-27 15:42:24 · 91 阅读 · 0 评论 -
条款 18 : 让接口容易被使用,不易被误用
条款18:让接口容易被使用,不易被误用Make interface s easy to use correctly and hard to use incorrectly//例子不给了,记住下面结论吧。目前的水平也看不懂请记住好的接口容易被正确使用,不容易被误用。你应该在所有接口努力达到这些性质。“促进正确使用”的方法包括接口的一致性,以及与内置类型的行为兼容。“防止误用”的方法包括建立新类型,限制类型上的操作,束缚对象值,以及消除客户的资源管理责任。tr1::shared_ptr 支原创 2021-09-27 13:04:55 · 63 阅读 · 0 评论 -
条款 17:以独立语句将newd对象置入智能指针
以独立语句将newd对象置入智能指针Store newed objects in smart pointers in standalone statements为了说明标题,看下面例子//假设我们有一个程序用来揭示处理程序的优先权//另一个函数处理某些带有优先权函数的功能int priority();void proWidget(std::tr1::shared_ptr<Widget> pw,int priority);//现在考虑调用该函数proWideget(new原创 2021-09-22 12:00:34 · 70 阅读 · 0 评论 -
条款 16:成对使用new和delete时要使用相同形式
条款 16:成对使用new和delete时要使用相同形式Use the same form in corresponding uses of new and delete.当你使用new时有两件事情发生:1.内存被分配出来。2.针对该内存会有一个或多个构造函数被调用。当你使用delete时也有两件事情发生:1.针对此内存有一个或多个析构函数被调用。2.内存被释放。delete p和delete [ ] p.//delete释放一个对象,//delete []释放一组对象//一般来说一个原创 2021-09-21 22:21:41 · 73 阅读 · 0 评论 -
条款 15:在资源管理类中提供对原始资源的访问
条款 15:在资源管理类中提供对原始资源的访问Provide access to raw resources in resource-managing classes显式转换和隐式转换。//在条款13中,曾提到用智能指针保存工厂函数的调用结果std::tr1::shared_ptr<Investment> pInv(creatInvestment());//假设你希望某个函数处理Investment对象int daysHeld(const Investment* pi);//原创 2021-09-21 13:30:27 · 81 阅读 · 0 评论 -
条款 14:在资源类中小心copying行为
条款 14:在资源类中小心copying行为Think carefully about copying behavior in resource-managing classRAII(Resource Acquisition Is Initialization):资源获得时机便是初始化时机。对于非堆资源,智能指针有时候并不适用。所以有时候需要建立自己的资源管理类。//假设我们使用C的API函数处理类型为Mutex的互斥对象,//共有lock和unlock两个函数可以用。void lock原创 2021-09-20 13:04:47 · 64 阅读 · 0 评论 -
条款 13:以对象管理资源
条款 13:以对象管理资源Use objects to manage resources所谓资源就是,一旦用它,将来必须还你给系统。单纯依靠函数进行资源释放行不通//假设我们的程序库各类继承一个root类class Investment{...};//投资类型,继承体系中的root class//假设我们通过工厂产生对象Investment* creatInvestment();//多态指针//这是一个动态对象,调用者有责任 释放他//假设用f()函数履行这个责任void f()原创 2021-09-19 19:10:39 · 255 阅读 · 0 评论 -
条款 12 : 复制对象时勿忘其每一个成分
条款 12 : 复制对象时勿忘其每一个成分Copy all parts of an object我们称复制构造函数copy assignement操作符为copying函数。如果你为你的class添加一个成员变量,你必须同时修改copying函数。//假设你用一个类表示顾客//你手写的copying函数,外界调用他时会被记录下来void logCall(const std::string& fileName);//制造一个log entryclass Customer{pub原创 2021-09-17 20:23:18 · 104 阅读 · 0 评论 -
条款 11 :在operator= 中处理“自我赋值”
条款 11 :在operator= 中处理“自我赋值”**Handle assignment to self in operator= **自我复制发生在对象被赋值给 自己时,这听起来很荒谬但是请注意,这是合法的。class Widget{...};Widget w;...w=w//易于识别的自我赋值//潜在的自我赋值a[i]=a[j]//如果i=j//潜在的自我赋值*px=*py;//如若px,py指向同一个对象这些不明显的自我赋值往往是“别名”带来的结果。所谓别名就原创 2021-09-17 15:28:45 · 97 阅读 · 0 评论 -
条款 10 :令operator=返回一个reference to *this
条款10 :令operator=返回一个reference to *this**Have assignment operator return a reference to *this. **为了实现类似连等的赋值形式,赋值操作符必须返回一个reference指向操作符的左侧。//关于赋值你可以写成连续的形式int x,y,z;x=y=z=10;//上述语句采用右结合律,也就是说10先被赋值给z,更新z的值//然后将z的值赋值给y,更新y的值//最后将y的值赋值给x,更新x的值。/原创 2021-09-16 17:31:23 · 93 阅读 · 0 评论 -
条款 09 :绝不在构造和析构过程中调用virtual函数
条款 09 :绝不在构造和析构过程中调用virtual函数Never call virtual functions during construction or destructionbase calss构造期间,virtual函数不会下降到drived classes阶层//假设你有一个class继承体系用来交易,如买进,卖出的订单等//每创建一个交易对象,那么在记录中也要创建一笔适当记录//下面的做法看起来颇为合理class Transaction{//所有交易的base class原创 2021-09-16 17:13:46 · 65 阅读 · 0 评论 -
条款 08 :别让异常逃离析构函数
条款 08 :别让异常逃离析构函数Prevent exceptions from leaving destructors.C++并不禁止 析构函数吐出异常,但是并不鼓励你这样做。class Widget{public: ... ~widget(){...}//假设这里可能吐出一个异常};void doSomething(){ std::vector<Widget> v; ...//v在这里被自动销毁}例如上述代码,当vector v被销毁,他有责任销毁其内含的所原创 2021-09-14 21:19:19 · 112 阅读 · 0 评论 -
条款 07 :为多态基类声明virtual析构函数
条款 07 :为多态基类声明virtual析构函数Declare destructors virtual in polymorphic base classes.我们有许多计时方法,假设有一个TimeKeeper基类和一些派生类用来表示时间。class TimeKeeper{public: TimeKeeper(); ~TimeKeeper(); ....};class AtomicClock:public TimeKeeper{...};//原子钟class WaterCloc原创 2021-09-14 19:53:34 · 93 阅读 · 0 评论 -
条款 06 :若不想使用编译器自动生成的函数,就该明确拒绝
条款 06 :若不想使用编译器自动生成的函数,就该明确拒绝Explicitly disallow the use of complier-generated functions you do not want如何保证一个对象是独一无二的(即不能被拷贝),直观的想法就是令copy构造函数和copy assignment操作符失效。但是【条款05】说过,即使你不声明这两个函数,但是编译器会自动为你生成。一个好的想法就是,将这两个函数私有化并不去实现他。(C++标准库中也使用该方法)//保证对象唯一原创 2021-09-13 22:31:42 · 105 阅读 · 0 评论 -
条款 05 :了解C++默默编写并调用了那些函数
条款 05 :了解C++默默编写并调用了那些函数Knows what functions C++ silently writes and callsC++ 不存在真正意义上的空类。当你写了一个empty class,当C++处理过他他就不会会是empty classes.如果你没有写,C++默认产生默认的构造函数,copy构造函数,默认的copy assignment操作符,和默认的析构函数。如果你打算在一个内含reference成员的class内支持赋值操作,你必须自己定义一个copy as原创 2021-09-13 21:49:31 · 80 阅读 · 0 评论 -
条款 04:确定对象被使用前已先被初始化
条款 04:确定对象被使用前已先被初始化Make sure that objects are initialized before they’re used.关于将对象初始化,C++反复无常,在某些语境下系统保证初始化,但某些语境下却不保证。C++存在无初始值对象,其他语言却大都没有这个概念。通常情况下,你使用C part of C++而且初始化可能招致运行期成本,那么就不保证初始化。但是进入non-C part of C++,规则就会发生变化。这就可以解释C风格数组不保证其内容被初始化,但ve原创 2021-09-11 18:13:04 · 100 阅读 · 0 评论 -
条款 03 :尽可能使用const
条款 03 :尽可能使用constUse const whenever possibleconst的一件奇妙的事情是,他允许你指定一项语义约束(也就是指定一个不可改动的对象),而编译器会强制实施这项约束。const出现在星号左边,表示被指物是常量,出现在星号右边表示指针自身是常量,出现在两边则表示被指物和指都是常量。const参数:除非需要改变参数或local对象,否则将其声明为const.const 成员函数不可以改变对象内任何non-static成员变量。不涉及修改对象数据的都应该声明为原创 2021-09-11 17:10:45 · 107 阅读 · 0 评论 -
条款 02:尽量以const,enum,inline替换#define
条款 02:尽量以const,enum,inline替换#definePerfer consts,enums,and inlines to #define该条款理解为”以编译器替换预处理器为好“,因为或许#define不被视为语言的一部分。用宏的方式定义一个变量,可能导致该名称未进入记号表,导致其不可用。#define ASPECT_RATIO 1.635//应该用常量替换宏const double ASPECT_RATIO 1.635;使用常量使其一定能进入记号表,且使用常量可导原创 2021-09-11 14:32:54 · 102 阅读 · 0 评论