Effective C++
C++点滴
Lailikes
这个作者很懒,什么都没留下…
展开
-
Effective_C++_条款四十九:了解new_handler的行为
本章开始讨论内存分配的一些用法,C/C++内存分配采用new和delete。在new申请内存时,可能会遇到的一种情况就是,内存不够了,这时候会抛出out of memory的异常。有的时候,我们希望能够调用自己定制的异常处理函数,这就是本条款要说的。在声明于<new>的一个标准程序库中,有如下的接口:1 namespace std2 {3 typedef v...转载 2019-06-13 08:36:35 · 151 阅读 · 0 评论 -
Effective_C++_条款四十八:了解模板元编程
作为模板部分的结束节,本条款谈到了模板元编程,元编程本质上就是将运行期的代价转移到编译期,它利用template编译生成C++源码,举下面阶乘例子:template <int N>struct Factorial{ enum { value = N * Factorial<N - 1>::value };};// 特化...转载 2019-06-13 08:34:14 · 170 阅读 · 0 评论 -
Effective_C++_条款四十七:请使用trait classes来表示类型信息
这一条款主要来讨论模板中迭代器的属性iterator_category,它可以通过类似于vector<int>::iterator::iterator_category的方式来取得。到这里我们有必要学习一下STL迭代器的类型,总共有五种,分别是:input_iterator:只读,只能逐个前移output_iterator:只写,只能逐个前移forward_iterat...转载 2019-06-13 08:30:02 · 232 阅读 · 0 评论 -
Effective_C++_条款四十六:需要类型转换时请为模板定义非成员函数
这个条款可以看成是条款24的续集,我们先简单回顾一下条款24,它说了为什么类似于operator *这样的重载运算符要定义成非成员函数(是为了保证混合乘法2*SomeRational或者SomeRational*2都可以通过编译,2不能同时进行隐式类型转换成某个Rational,再作this用)。所以我们一般将之定义成友元函数,像下面这样:class Rational{private...转载 2019-06-13 08:27:33 · 151 阅读 · 1 评论 -
Effective_C++_条款四十五:运用成员函数模板接受所有兼容类型
比如有一个Base类和一个Derived类,像下面这样:1 class BaseClass2 {…};3 4 class DerivedClass : public BaseClass5 {…};因为是父类与子类的关系,所以可以这样写:1 DerivedClass *d;2 BaseClass *b = static_cast< BaseClass *>d; ...转载 2019-06-13 08:21:27 · 181 阅读 · 0 评论 -
Effective_C++_条款四十四:将与参数无关的代码抽离template
标题上说“将与参数无关的代码抽离template”,这里的参数既可以指类型,也可以是非类型,我们先来看看非类型的情况。假定我们要为矩阵写一个类,这个矩阵的行列元素个数相等,是一个方阵,因而我们可以对之求逆运算。因为方阵的元素可以有多种类型,同时方阵的维数(方阵大小)也可以不同,像下面这样,我们使用了模板:template <class T, size_t n>class S...转载 2019-06-13 08:14:55 · 267 阅读 · 0 评论 -
Effective_C++_条款四十三:学习处理模板化基类的名称
背景是这样的,有两个不同的公司,然后想设计一个MessageSender,为这两个公司发送不同的消息,既支持明文发送SendClearText,也支持密文发送SendEncryptedText。一种思路是采用动态绑定的方法,定义一个BasicMessageSender,里面有两个方法,分别是发送明文和密文的虚函数,然后定义它的子类MessageSenderForCompanyA,以及Message...转载 2019-06-13 08:05:23 · 117 阅读 · 0 评论 -
Effective_C++_条款四十二:了解typename的双重意义
顾名思义,typename有双重含意。只要你用过template,那么第一重含意一定知道,那就是声明模板的时候,我们既可以这样写:template <classT>也可以这样写template <typename T>这两种写法并没有任何区别,都是标记T可以是符合隐式接口的任何类型,包括系统预定义类型,也包括用户自定义类型。typenam...转载 2019-06-13 07:56:50 · 169 阅读 · 0 评论 -
Effective_C++_条款四十一:了解隐式接口和编译期多态
从本条款开始,就进入了全书的第七部分:模板与泛型编程。模板与泛型在C++中是非常重要的部分,还记得本书第一章时,把C++视为一个联邦,它由四个州政府组成,其中一个政府就是模板与泛型了。本条款是一个介绍性质的条款,内容不难,只需要讲清楚两个概念就行了,即什么是隐式接口,什么是编译期多态。隐式接口是相对于函数签名所代码的显式接口而言的。当我们看到一个函数签名(即函数声明),比如说:str...转载 2019-06-13 07:53:51 · 157 阅读 · 0 评论 -
Effective_C++_条款四十:明智而审慎地使用多重继承
多重继承是一种比较复杂的继承关系,它意味着如果用户想要使用这个类,那么就要对它的父类也了如指掌,所以在项目中会带来可读性的问题,一般我们都会尽量选择用单继承去替代它。使用多重继承过程容易碰到的问题就是名字冲突,像下面这样:class Base1{public: void fun(){}};class Base2{private: void fun(){}}...转载 2019-06-12 08:48:30 · 146 阅读 · 0 评论 -
Effective_C++_条款三十九:明智而审慎地使用private继承
private继承的意义在于“be implemented in turns of”,这个与上一条款中说的复合模型的第二层含义是相同的,这也意味着通常我们可以在这两种设计方法之间转换,但书上还是更提倡使用复合来进行类的设计。private继承与public的继承是完全不同的,主要体现在两个地方:其一,public继承在子类中保持父类的访问权限,即父类中是public的成员函数或成员变量,在...转载 2019-06-12 08:44:41 · 198 阅读 · 0 评论 -
Effective_C++_条款三十八:通过复合塑模出has-a或者is-implemented-in-terms-of
如果说public是一种is-a的关系的话,那么复合就是has-a的关系。直观来说,复合就是在一个类中采用其他类的对象作为自身的成员变量,可以举个例子,像下面这样:class Person{private: string Name; // 复合string类型的变量 PhoneNumber HomeNumber; // 复合PhoneNumber对象 PhoneN...转载 2019-06-12 08:37:59 · 437 阅读 · 0 评论 -
Effective_C++_条款三十七:绝不重新定义继承而来的缺省参数值
先看下面的例子:enum MyColor{ RED, GREEN, BLUE,};class Shape{public: void virtual Draw(MyColor color = RED) const = 0;};class Rectangle: public Shape{public: void Draw(MyColo...转载 2019-06-12 08:21:16 · 171 阅读 · 0 评论 -
Effective_C++_条款三十六:绝不重新定义继承而来的non-virtual函数
这个条款的内容很简单,见下面的示例:class BaseClass{public: void NonVirtualFunction() { cout << "BaseClass::NonVirtualFunction" << endl; }};class DerivedClass: public BaseClass{...转载 2019-06-12 08:17:32 · 148 阅读 · 0 评论 -
Effective_C++_条款三十五:考虑virtual函数以外的其他选择
举书上的例子,考虑一个virtual函数的应用实例:class GameCharacter{private: int BaseHealth;public: virtual int GetHealthValue() const // 返回游戏人物的血量 { return BaseHealth; } int GetBaseHeal...转载 2019-06-12 08:14:23 · 188 阅读 · 0 评论 -
Effective_C++_条款三十四:区分接口继承和实现继承
这个条款书上内容说的篇幅比较多,但其实思想并不复杂。只要能理解三句话即可,第一句话是:纯虚函数只继承接口; 第二句话是:虚函数既继承接口,也提供了一份默认实现; 第三句话是:普通函数既继承接口,也强制继承实现。这里假定讨论的成员函数都是public的。这里回顾一下这三类函数,如下:class BaseClass{public: void virtual PureV...转载 2019-06-11 08:23:08 · 133 阅读 · 0 评论 -
Effective_C++_条款三十三:避免遮掩继承而来的名称
名称的遮掩可以分成变量的遮掩与函数的遮掩两类,本质都是名字的查找方式导致的,当编译器要去查找一个名字时,它一旦找到一个相符的名字,就不会再往下去找了,因此遮掩本质上是优先查找哪个名字的问题。而查找是分作用域的,虽然本条款的命名是打着“继承”的旗子来说的,但我觉得其实与继承并不是很有关系,关键是作用域。举例子说明这个问题会比较好理解。//例1:普通变量遮掩int i = 3;in...转载 2019-06-11 08:17:31 · 110 阅读 · 0 评论 -
Effective_C++_条款三十二:确定你的public继承继承塑模出is-a关系
这一条款是说的是公有继承的逻辑,如果使用继承,而且继承是公有继承的话,一定要确保子类是一种父类(is-a关系)。这种逻辑可能与生活中的常理不相符,比如企鹅是生蛋的,所有企鹅是鸟类的一种,直观来看,我们可以用公有继承描述:class Bird{public: virtual void fly(){cout << "it can fly." << endl;}...转载 2019-06-11 08:06:31 · 140 阅读 · 0 评论 -
Effective_C++_条款三十一:将文件间的编译依存关系降至最低
在说这一条款之前,先要了解一下C/C++的编译知识,假设有三个类ComplexClass, SimpleClass1和SimpleClass2,采用头文件将类的声明与类的实现分开,这样共对应于6个文件,分别是ComplexClass.h,ComplexClass.cpp,SimpleClass1.h,SimpleClass1.cpp,SimpleClass2.h,SimpleClass2.cpp。...转载 2019-06-11 08:02:24 · 178 阅读 · 0 评论 -
Effective_C++_条款三十:了解inline的里里外外
学过基本程序课的同学都知道,inline是内联的关键字,它可以建议编译器将函数的每一个调用都用函数本体替换。这是一种以空间换时间的做法。把每一次调用都用本体替换,无疑会使代码膨胀,但可以节省函数调用的成本,因为函数调用需要将之前的参数以堆栈的形式保存起来,调用结束后又要从堆栈中恢复那些参数。但注意inline只是对编译器的一个建议,编译器并不表示一定会采纳,比如当一个函数内部包含对自身的递归调...转载 2019-06-10 08:21:27 · 153 阅读 · 0 评论 -
Effective_C++_条款二十九:为“异常安全”而努力是值得的
还是举书上的例子:void PrettyMenu::changeBackground(std::istream& imgSrc){ lock(&mutex); delete bgImage; ++ imageChanges; bgImage = new Image(imgSrc); unlock(&mutex);}这段代...转载 2019-06-10 08:16:19 · 113 阅读 · 0 评论 -
Effective_C++_条款二十八:避免返回handlers指向对象内部成分
举个例子:class Student{private: int ID; string name;public: string& GetName() { return name; }};这是一个学生的类,类里面有两个成员变量,一个是学生ID,用整数表示,另一个是姓名,用string表示。有一个公有的方法GetName(...转载 2019-06-10 08:07:41 · 107 阅读 · 0 评论 -
Effective_C++_条款二十七:尽量少做转型动作
有关转型的几种做法,已经在早些的博客中写过了。这里先简单回顾一下,再讲一讲effective中对之更深入的阐述。转型可以按风格可以分成C风格转型和C++风格转型两大类,C风格转型很容易看到,因为我们会经常使用,像(T) expression以及:T (expression)最经典的例子就是处理整数除法,在C/C++程序中,整数除法的结果还是整数,有时会得不到我们想到的结果,...转载 2019-06-10 07:54:44 · 137 阅读 · 0 评论 -
Effective_C++_条款二十六:尽可能延后变量定义式的出现时间
这个条款从字面意思还是很好理解的,就是在使用这个变量前才去定义,而不是很早就定义了它,而在很后面的时候才去使用。这个条款只适用于对变量声明位置没有要求的语言,比如C++。对于像C或者一些脚本语言,语法要求变量声明放在函数开始处,这个条款就不能使用了。但其实从使用的角度而言,如果不是语法的硬性要求,还是在变量使用前再去定义变量的做法比较好。这有几点原因,最直观的就是可读性比较好,程序员在阅读代码...转载 2019-06-09 10:49:52 · 133 阅读 · 0 评论 -
Effective_C++_条款二十五: 考虑写出一个不抛出异常的swap函数
我也不知道为什么作者给这个条款起这样的名字,因为这样看上去重点是在“不抛出异常”,但事实上作者只是在全文最后一段说了一下不抛异常的原因,大部分段落是在介绍怎样写一个节省资源的swap函数。你可以试一下,只要包含了头文件iostream,就可以使用swap函数,比如:#include <iostream>int main(){ int a = 3; int...转载 2019-06-09 09:41:16 · 249 阅读 · 0 评论 -
Effective_C++_条款二十四: 若所有参数皆需类型转换,请为此采用non-member函数
还是举书上的有理数例子:class Rational{private: int numerator; int denominator;public: Rational(int n = 0, int d = 1): numerator(n), denominator(d){assert(denominator != 0);} int GetNumerato...转载 2019-06-09 09:13:40 · 139 阅读 · 0 评论 -
Effective_C++_条款二十三:宁以non-member、non-friend替换member函数
本条款还是讨论封装的问题,举书上的例子:class WebBrower{public: void ClearCach(); void ClearHistory(); void RemoveCookies();};定义了一个WebBrower的类,里面执行对浏览器的清理工作,包括清空缓存,清除历史记录和清除Cookies,现在需要将这三个函数打包成一个函数,这...转载 2019-06-09 08:32:02 · 139 阅读 · 0 评论 -
Effective_C++_条款二十二:将成员变量声明为private
这个条款从字面意思上理解很简单,很多程序都是这样做的,即使作为初学者,也知道该将成员变量声明为private,但有没有想过,为什么要这样做?为什么public成员变量不行?protected成员变量行不?举一个简单的例子:class Clothes{public: int price; string name;};假设有一个衣服的类,里面的成员变量用来描述它...转载 2019-06-09 08:22:37 · 142 阅读 · 0 评论 -
Effective_C++_条款二十一:当必须返回对象时,别妄想返回其reference
当你理解条款21后,很可能出现一种过度使用的情况:只要看到是一个非内置类型,就去使用引用传值。举个书上的例子:class Rational{private: int numerator; int denominator;public: Rational():numerator(0), denominator(1){} friend const Ratio...转载 2019-06-09 08:19:03 · 133 阅读 · 1 评论 -
Effective_C++_条款二十:宁以pass-by-reference-to-const替换pass-by-value
默认情况下,C++的函数调用是传值调用,也就是说形参拷贝实参的内容。举书上的例子:class Person{private: string name; string address;public: Person(){} virtual ~Person(){}};class Student: public Person{private: ...转载 2019-06-09 08:12:58 · 124 阅读 · 0 评论 -
Effective_C++_条款十九:设计class犹如设计type
这里初看到”class”和”type”,感觉他们是说的是同一样东西,但仔细读了一下,两者在文中还是有区别的。class侧重于自定义的类,而type侧重于系统预定义的类(像int、double、string、vector)。设计好的class,使之像设计type一样,就是说要使自己设计的类像系统预定义的类那样好用,这对设计思想提出了较高的要求。要设计高效的class,需要回答以下的问题:1....转载 2019-06-09 08:05:46 · 130 阅读 · 0 评论 -
Effective_C++_条款十八:让接口容易被正确使用,不易被误用
从本条款开始,就进入到全书的第四部分:设计与声明。程序员设计接口时应本的对用户负责的态度,“如果客户企图使用某个接口而却没有获得他所预期的行为,这个代码不应该通过编译;如果代码通过了编译,那它的作为就该是客户所想要的”。举一个书上的例子:class Date{public: Date(int month, int day, int year); …};这个类...转载 2019-06-09 07:42:09 · 136 阅读 · 0 评论 -
Effective_C++_条款十七:以独立语句将new产生的对象置入智能指针
举书上的例子:int GetPriority();void processWidget(shared_ptr<Widget> pw, int priority);如果这样调用processWidget:processWidget(new Widget(), GetPriority());注意一下两边的类型,上边是管理者shared_ptr<Widget>...转载 2019-06-05 11:15:34 · 146 阅读 · 0 评论 -
Effective_C++_条款十六:成对使用new和delete时要采取相同的形式
这个条款比较好理解,就是new有两种形式:1 int *p = new int(); // 申请一个int资源2 int *p = new int[3]; // 申请连续三块int资源而delete也有两种资源:delete p; // delete指针所指向的单一资源delete [] p; // delete指针所指向的多个连续资源块那么该各用哪一种形式呢?一个简单又好...转载 2019-06-05 11:10:10 · 117 阅读 · 0 评论 -
Effective_C++_条款十五:在资源类管理类中提供对原始资源的访问
先放上自己写的MySharedPtr类,这是仿照shared_ptr的功能来实现的(实际shared_ptr要复杂的多)。#ifndef MY_SHARED_PTR_H#define MY_SHARED_PTR_H#include <iostream>using namespace std;typedef void (*FP)(); template &l...转载 2019-06-05 11:07:53 · 146 阅读 · 0 评论 -
Effective_C++_条款十四:在资源管理类中小心copying行为
首先来看一个例子:#include <iostream>using namespace std;class Lock{public: explicit Lock(int* pm): m_p(pm) { lock(m_p); } ~Lock() { unlock(m_p); }priva...转载 2019-06-05 11:03:01 · 237 阅读 · 0 评论 -
Effective_C++_条款十三:以对象管理资源
从这个条款开始,就进入到资源管理部分了。资源管理往往是大型项目的一个难点,也是重中之重,看到一些编程规范,都是将资源管理的规范列为高优先级的重点。管理资源的最好方法其实是预防,而好的预防方法就是尽量不去使用C/C++的原生指针,这些指针像幽灵一样,一个“忘记”,就是一个隐患。当项目小的时候,这些隐患看不出来,但当研发一个拥有上万级用户的产品时,服务器对很多人同时运行含有隐患的代码,这个隐患就会...转载 2019-06-05 10:51:19 · 177 阅读 · 0 评论 -
Effective_C++_条款十二:复制对象时勿忘其每一个成分
这句话包含两部分的意思:第一部分是要考虑到所有成员变量,特别是后加入的,相应的拷贝构造函数和赋值运算符要及时更新;第二部分是在存在继承时,不要遗忘基类部分的复制。先看第一部分的意思,举个例子:class SampleClass{private: int a;public: SampleClass(const SampleClass& s):a...转载 2019-06-05 10:40:31 · 139 阅读 · 0 评论 -
Effective_C++_条款十一:在operator=中处理自我赋值
直观的operator=是这样定义的:class SampleClass{private: int a; double b; float* p;public: SampleClass& operator= (const SampleClass& s) { ...转载 2019-05-28 09:54:05 · 169 阅读 · 0 评论 -
Effective_C++_条款十:令operator=返回一个reference to *this
这个条款很简单的说,先解释一下为什么赋值后还要有返回值,这是因为我们可以这样用连等:int x, y, z;x = y = z;注意等号是右结合的,所以上述运算实际上等同于:x = (y = z);如果没有返回值,上述代码就不能通过编译。至于为什么返回的是一个引用,这并不是编译器强制的,但有三个原因让你觉得这样做是明智的:(1) 返回引用可以节省资源,不必要为...转载 2019-05-16 20:50:19 · 176 阅读 · 0 评论