
Effective C++
本专栏内容来自于《Effective C++》书中的内容,介绍了55条改善程序与设计的具体做法。在此,感谢本书的作者Scott Meyers以及译者侯捷
董哥的黑板报
90后程序员!
展开
-
Effective C++条款01:让自己习惯C++之(视C++为一个语言联邦)
一开始,C++只是在C上面加上一些面向对象特性。C++最初的名字C with Classes也反映了这个血缘关系。 但是当这个语言逐渐成熟,它变得更活跃无约束,更大胆更冒险,开始接受不同于C with class的各种观念、特性和编程战略。Exceptions(异常)对函数的结构化带来不同的做法,templates(模板)将我们带来新的设计思考方式(见条款41),STL则定义了一个前所未有的伸...原创 2020-02-01 10:30:19 · 826 阅读 · 0 评论 -
Effective C++条款02:让自己习惯C++之(尽量以const,enum,inline替换#define)
一、为什么不推荐使用#define在程序中你可能会定义下面一个宏,来表示一个数值#define ASOECT_RATIO 1.653#define的缺点①宏的名称是不会被编译器看见的,因为在程序的预处理阶段,宏会被替换为其对应的数值/表达式,因此宏对于编译器来说是不存在“名称”这一概念的。 ②因为宏没有名称这一概念,因此宏的名称是不会进入符号表中(symbol table),宏...原创 2020-02-01 11:24:42 · 903 阅读 · 0 评论 -
Effective C++条款03:让自己习惯C++之(尽可能使用const)
一、指针常量、常量指针、常量指针常量 参阅:https://blog.youkuaiyun.com/qq_41453285/article/details/91659705 如果通过const的位置判断const 二、const应用之STL迭代器STL的迭代器就是一个很好介绍const的例子①如果想希望可以通过迭代器修改值,并且改动迭代器的位置,那么可以使用iterator类型的迭...原创 2020-02-03 15:24:38 · 657 阅读 · 0 评论 -
Effective C++条款04:让自己习惯C++之(确定对象被使用前已被初始化)
一、未初始化的危害使用未初始化的值会导致不明确的行为二、内置类型的初始化对于内置的数据类型(char、int、float、double等),在使用前必须进行初始化,如果不初始化在使用时会出错,并且如果使用了未初始化的内置类型变量,有的编译会出错int a; //未初始化。危险int x = 0; //初始化const char* text = "Hello World"...原创 2020-02-04 10:03:51 · 661 阅读 · 0 评论 -
Effective C++条款05:构造/析构/赋值运算之(了解C++默默编写并调用哪些函数)
一、C++类默认定义的函数如果class没有定义构造函数、析构函数、拷贝构造函数、拷贝赋值运算符函数,那么C++内部会动创建一个默认的构造函数、析构函数、拷贝构造函数、拷贝赋值运算符函数。并且这些默认函数都是public且inline的演示说明class Empty{}; //空类Empty e1; //调用e1的默认构造函数Empty e2(e1);//调用e2的默认拷...原创 2020-02-04 10:49:56 · 662 阅读 · 0 评论 -
Effective C++条款06:构造/析构/赋值运算之(若不想使用编译器自动生成的函数,就该明确拒绝)
一、前言在前面一篇文章中(https://blog.youkuaiyun.com/qq_41453285/article/details/104165762),我们介绍了C++编译器会为我们的class生成默认的构造函数、析构函数、拷贝构造函数、拷贝赋值运算符 但是有些情况下,我们不希望使用其中的一种功能。例如:我们不希望使用class的拷贝赋值运算符(那么就不能将一个对象赋值给另一个对象),那么就需要...原创 2020-02-04 11:39:16 · 695 阅读 · 1 评论 -
Effective C++条款07:构造/析构/赋值运算之(为多态基类声明virtual析构函数)
一、从一个例子中介绍为什么要为基类使用virtual析构函数我们创建一个TimeKeeper基类和一些及其它的派生类作为不同的计时方法class TimeKeeper{public: TimeKeeper() {} ~TimeKeeper() {} //非virtual的};//都继承与TimeKeeperclass AtomicClock :public T...原创 2020-02-05 13:31:20 · 729 阅读 · 0 评论 -
Effective C++条款08:构造/析构/赋值运算之(别让异常逃离析构函数)
一、析构函数也会抛出异常C++并不禁止析构函数抛出异常,但是不建议这样演示案例class Widget{public: ~Widget() {} //假设这个析构函数可能会抛出异常};int main(){ std::vector<Widget> v; return 0;}//v在这里自动销毁假设v内有10个Widgets,那么在...原创 2020-02-05 21:42:55 · 769 阅读 · 0 评论 -
Effective C++条款09:构造/析构/赋值运算之(绝不在构造和析构过程中调用virtual函数)
待续原创 2020-02-06 17:52:28 · 483 阅读 · 0 评论 -
Effective C++条款10:构造/析构/赋值运算之(令operator=返回一个reference to *this)
一、赋值运算符的返回值关于赋值,赋值运算符在每回赋值之后应该是返回“=”操作符左边的对象演示案例下面的“x=y=z=5”的意识是先将5赋值给z然后对象z,再将z对象赋值给y然后返回对象y,再将对象y赋值给对象x,最终这个表达式的结果是xint x, y, z;x = y = z = 5;二、class内的operator=建议我们建议在重载类的operator=运算符时...原创 2020-02-06 18:04:35 · 503 阅读 · 0 评论 -
Effective C++条款11:构造/析构/赋值运算之(在operator=中处理“自我赋值”)
一、自我赋值的演示案例自我赋值会发生在很多情况下 例如定义一个类对象,将自己赋值给自己class Widget{};Widget w;w = w; //自我赋值如果下面的a是一个数字,且索引i和j相等,那么也是一个潜在的自我赋值a[i] = a[j];例如下面两个指针px和py指向于同一块内存,那么也是一个潜在的自我赋值*px = *py;二、一个自我赋值...原创 2020-02-07 10:27:00 · 608 阅读 · 0 评论 -
Effective C++条款12:构造/析构/赋值运算之(复制对象时勿忘其每一个成份)
一、引入 我们在前面文章已经介绍了,如果类没有手动声明拷贝构造函数或拷贝赋值运算符,那么编译器会为我们自动生成这两个成员,并且它们的行为是:将被拷贝的对象的所有成员做一份拷贝 二、复制对象时确保复制所有成员下面的类有两个成员变量,因此我们需要为每一份成员进行一份复制Customer::Customer(const Customer& rhs) :name(rhs....原创 2020-02-07 10:59:29 · 517 阅读 · 0 评论 -
Effective C++条款13:资源管理之(以对象管理资源)
一、资源释放失败的案例例如我们使用一个用来塑模投资行为(例如股票,债券等等)的程序库,其中各式各样的投资类型继承于一个基类Investment:class Investment {};现在建立通过一个工厂函数供应我们获得某特定的Investment对象://返回一个Investment继承体系中的动态分配对象Investment* createInvestment();如果我...原创 2020-02-08 10:31:19 · 588 阅读 · 0 评论 -
Effective C++条款14:资源管理之(在资源管理类中小心拷贝行为)
前言在前面的文章中我们介绍了智能指针类来管理资源,但是对于某些资源,它们不是动态分配的(不是堆上的),因此智能指针就是不适合这种资源的管理了,因此你可能会设计自己的资源管理类一、“不希望拷贝”演示案例假设我们使用C的API函数处理类型为Mutex的互斥器对象,其中有两个函数如下:void lock(Mutex* pm); //锁定pm所指的互斥器void unlock(Mute...原创 2020-02-08 11:09:11 · 522 阅读 · 0 评论 -
Effective C++条款15:资源管理之(在资源管理类中提供对原始资源的访问)
一、在资源管理类中提供对原始资源的访问在前面的文章中我们使用到了C++提供的智能指针以及自己封装的资源管理类,这些类中我们将资源封装在class内部。但是在很多情况下我们需要直接使用到这些资源,所以需要提供一些方法直接使用到这些内部资源,例如shared_ptr的get函数等演示说明创建一个类class Investment {};创建一个函数,会返回一个Investment指...原创 2020-02-09 11:10:01 · 499 阅读 · 0 评论 -
Effective C++条款16:资源管理之(成对使用new和delete时要采取相同形式)
一、概念如果申请(new)的对象为单一对象,那么在释放(delete)的时候就只要简单的释放即可 如果申请(new [])的对象为对象数组,那么在释放(delete [])的时候就要以[]释放之二、演示案例申请单一对象std::string* stringArray = new std::string;delete stringArray; //正确的//delet...原创 2020-02-09 11:20:27 · 551 阅读 · 0 评论 -
Effective C++条款17:资源管理之(以独立语句将newed对象置入智能指针)
一、演示案例现在我们有个函数返回处理程序的优先权,然后用另一个函数在某动态分配所得的Widget上进行某些带有优先权的处理//返回优先权int priority();//根据优先权处理对象void processWidget(std::tr1::shared_ptr<Widget> pw, int priority);如果我们使用下面的方法调用函数是错误的,因为pr...原创 2020-02-09 11:51:58 · 651 阅读 · 4 评论 -
Effective C++条款19:设计与声明之(设计class犹如设计type)
C++就像在其他OOP(面向对象编程)语言一样,当你定义一个新class,也就定义了一个新type。身为C++程序员,你的许多时间主要用来扩张你的类型系统。这意味着你并不只是class设计者,还是type设计者。重载函数和操作符、控制内存的分配和归还、定义对象的初始化和终结......全部都在你手上。因此你应该带着和“语言设计者当初设计语言内置类型时”一样的谨慎来研讨class的设计。 设计优秀...原创 2020-02-10 16:54:35 · 587 阅读 · 0 评论 -
Effective C++条款20:设计与声明之(宁以pass-by-reference-to-const替换pass-by-value)
一、传值调用会造成代码执行效率低 传值调用为什么会造成代码执行效率低?因为传值调用的时候,是传递对象的一个副本,因此是调用对象的拷贝构造函数将对象复制一份,然后传递给函数。效率比较低 下面来看一个例子:有一个基类(Person)与一个派生类(Student),并且定义一个函数(validateStudent),参数接受一个Student对象(传值调用)class Person{...原创 2020-02-11 11:10:13 · 521 阅读 · 2 评论 -
Effective C++条款21:设计与声明之(必须返回对象时,别妄想返回其reference)
前面一篇文章我们介绍了,向函数中传递对象时,应以const引用的方式传递它,但是并不是在任何情况下使用引用都是正确的,文本来介绍一些情况一、演示说明现在我们有一个用来变现有理数的class,内含一个函数用来计算两个有理数的乘积 下面代码中的operator*是正确的,也是合理的class Rational{public: Rational(int numerator = 0...原创 2020-02-12 15:44:29 · 727 阅读 · 2 评论 -
Effective C++条款22:设计与声明之(将成员变量声明为private)
一、不要把成员变量声明为private统一性如果成员变量不是public,那么客户端只能通过函数来对成员变量进行操作 通过函数来操作类这也是一个标准,很多面向对象语言都是这么设计的class AccessLevels{public: int getReadOnly()const { return readOnly; } void setReadWrite(int...原创 2020-02-12 16:06:26 · 613 阅读 · 0 评论 -
Effective C++条款24:设计与声明之(若所有参数皆需类型转换,请为此采用non-member函数)
一、看一个类型转换的错误案例现在我们有一个类,来用表现出有理数,允许整数“隐式转换”为有理数class Rational{public: //构造函数不能是explicit类型的 Rational(int numerator = 0, int denominator = 1); int numerator()const; int denominator(...原创 2020-02-14 14:35:38 · 638 阅读 · 0 评论 -
Effective C++条款25:设计与声明之(考虑写出一个不抛异常的swap函数)
待续原创 2020-02-16 15:22:09 · 793 阅读 · 0 评论 -
Effective C++条款26:实现之(尽可能延后变量定义式的出现时间)
一、变量定义的成本只要你定义一个变量,该变量带有构造函数与析构函数,那么: 当你定义这个变量时就要执行它的构造函数 变量生命周期结束后就要执行他的析构函数 二、尽量延迟变量定义的时间变量定义需要执行构造与析构函数,因此在某些情况下为了提高程序的效率,应该延迟变量定义的时间。请看下面的演示案例:演示案例下面定义一个函数,用来对密码进行加密,如果参数传入的密码过段就抛出一个...原创 2020-02-17 10:11:21 · 876 阅读 · 0 评论 -
Effective C++条款27:实现之(尽量少做转型动作)
总结如果可以,尽量避免转型,特别是在注重效率的代码中避免dynamic_cast。如果有个设计需要转型动作,试着发展无需转型的替代设计 如果转型是必须的,试着将它隐藏于某个函数背后。客户随后可以调用该函数,而不需要将转型放进它们自己的代码 宁可使用新式的转型,不要使用旧式转型。前者很容易辨别出来,而且也比较有着分门别类的职掌...原创 2020-02-23 09:16:51 · 815 阅读 · 0 评论 -
Effective C++条款28:实现之(避免返回handles指向对象内部成分)
一、概述演示案例下面是一些关于图形的类 Point是用来表示坐标中的点;RectData代表矩形的左上角与右上角;Rectangle用来管理矩形,其中有一个RectData成员变量class Point { //点public: Point(int x, int y); void setX(int newVal); void setY(int newVa...原创 2020-02-23 09:16:56 · 863 阅读 · 0 评论 -
Effective C++条款29:实现之(为“异常安全”而努力是值得的)
一、可能抛出异常的演示案例待续原创 2020-03-08 09:28:39 · 774 阅读 · 0 评论 -
Effective C++条款30:实现之(透彻了解inlining的里里外外)
一、inline的优缺点优点免除函数调用成本缺点以函数本体代替函数调用,因此目标大增大 在一台内存优先的机器上,过度使用inline会造成程序体积太大 即使拥有虚内存,inline造成的代码膨胀也会造成额外的换页行为,降低指令高速缓存装置的集中率,以及伴随效率的损失二、隐式内联、显式内联inline只是对编译器的一个申请,不是强制命令 隐式内联只现在class...原创 2020-03-08 09:40:37 · 617 阅读 · 0 评论 -
Effective C++条款32:继承与面向对象之(确定你的public继承塑模出is-a关系)
一、“is-a”的概念以C++进行面向对象编程,最重要的一个规则是:public inheritance(公开继承)意味“is-1”(是一种)的关系 如果你令class D以public形式继承class B,你便是告诉编译器: 每一个类型为D的对象同时也是一个类型为B的对象。反之不是 B对象可使用的地方,D对象一样可以使用。反之不是 演示案例下面Student类public...原创 2020-03-09 20:15:58 · 594 阅读 · 0 评论 -
Effective C++条款33:继承与面向对象之(避免遮掩继承而来的名字)
待续原创 2020-03-10 21:43:04 · 634 阅读 · 0 评论 -
Effective C++条款34:继承与面向对象之(区分接口继承和实现继承)
一、继承中接口的处理方式作为类的设计者,对于基类的成员函数可以大致做下面三种方式的处理: ①派生类只继承基类的成员函数的接口(纯虚函数),派生类自己实现纯虚函数 ②派生类继承基类函数的接口和实现(virtual函数,非纯虚函数),并且自己覆盖(override)基类虚函数的定义 ③只希望派生类继承基类的函数的接口和实现,并且不希望派生类覆盖 本文依次介绍上面这三种设计的原理。...原创 2020-03-11 22:43:55 · 665 阅读 · 0 评论 -
Effective C++条款35:继承与面向对象之(考虑virtual函数以外的其他选择)
待续原创 2020-03-12 13:40:57 · 543 阅读 · 0 评论 -
Effective C++条款36:继承与面向对象之(绝不重新定义继承而来的non-virtual函数)
一、看一个隐藏non-virtual函数的例子假设class D以public的方式继承于class B,代码如下:class B {public: void mf();};class D :public B {};int main(){ D x; B *pB = &x; pB->mf(); //调用B::mf() ...原创 2020-03-12 14:22:13 · 520 阅读 · 0 评论 -
Effective C++条款37:继承与面向对象之(绝不重新定义继承而来的缺省参数值)
待续原创 2020-03-12 20:43:19 · 607 阅读 · 0 评论 -
Effective C++条款38:继承与面向对象之(通过复合塑模出has-a或“根据某物实现出”)
一、类的复合关系复合:是类型之间的一种关系,是指在某种类型的对象内包含其他类型的对象 复合(composition)还有一些其他的同义词,例如layering(分层),containment(内含),aggregation(聚合)、embedding(内嵌) 例如:class Address {};class PhoneNumber {};//此类为复合类型class Pers...原创 2020-03-12 22:10:27 · 665 阅读 · 0 评论 -
Effective C++条款39:继承与面向对象之(明智而审慎地使用private继承)
一、先介绍一下private继承的语法某派生类private继承于基类之后: ①基类中的所有内容(不论是public、protected、private)在派生类中都是不可访问的 ②不能再将派生类对象转换为基类对象 ③基类仍然可以重写/隐藏基类的成员方法 二、private继承意味着什么关系?private继承意为implemented-terms-of(根据某物实现出):...原创 2020-03-13 10:20:40 · 656 阅读 · 0 评论 -
Effective C++条款40:继承与面向对象之(明智而审慎地使用多重继承)
一、多重继承中,接口调用的歧义性当一个类继承自两个基类时,两个基类包含有相同的名称(如函数、typedef等),那么调用时就会产生歧义性演示案例class BorrowableItem {public: void checkOut();};class ElectronicGadget {private: bool checkOut()const; //注意,...原创 2020-03-13 15:48:38 · 780 阅读 · 0 评论 -
Effective C++条款41:模板与泛型编程之(了解隐式接口和编译期多态)
待续原创 2020-03-13 20:45:55 · 698 阅读 · 0 评论 -
Effective C++条款42:模板与泛型编程之(了解typenam的双重意义)
一、意义①意义①:typename可以在template中声明类型参数 在template中声明类型参数时,template和class是等价的,两者都可以 例如://两者是等价的template<class T> class Widget;template<typename T> class Widget;二、意义②意义②:可以用来声明某种类型...原创 2020-03-13 21:56:29 · 754 阅读 · 0 评论 -
Effective C++条款43:模板与泛型编程之(学习处理模板化基类内的名称)
待续原创 2020-03-14 10:38:14 · 676 阅读 · 0 评论