Effective C++ (笔记) : 条款01 -- 条款04

条款01:视C++为一个语言联邦

条款02:尽量以const,enum,inline替换#define

"宁可以编译器替换预处理器",使用#define那么在编译器之前预处理器已经完成了替换,记号名称没有进入记号表(symbol
table
),所以在调试或者编译错误的时候会莫名其妙。以常量替换宏是个好主意:const double AspectRatio = 1.653替换#define
ASPECT_RATIO 1.653

如果你不想让别人获得一个指针或者引用指向你的某个整数常量,enum可以实现这个约束。

  1. -#define CALL_WITH_MAX(a,b) f((a)>(b) ? (a):(b))

这种长相的宏,看着就头疼。可使用template inline替换:

  1. template<typename T>
  2. inline void callWithMax(const T &a, const T &b){
  3. f(a > b ? a : b)
  4. }

对于单纯常量,最好以const对象或enum替换#define

对于形似函数的宏,最好使用inline函数替换#defines

条款03:尽可能使用const

const修饰左侧的对象,如果关键字const出现在星号左边,表示被指物是常量;如果出现在星号右边,表示指针自身是常量;如果出现在星号两边,表示被指物和指针两者都是常量。

STL迭代器是以指针为根据塑模出来的。所以迭代器的作用像是个T
*
指针。声明迭代器为const就像声明指针为const一样(T
* const
),表示这个迭代器不能指向不同的东西(位置),但是它指向的东西是可以改变的。如果你希望迭代器所指的东西不能改变(const T *),需要使用const_iterator。这两者是有差别的,比较如下:

  1. vector<int> vec;
  2. const vector<int>::iterator iter = vec.begin(); // T* const
  3. *iter = 10; //没问题
  4. ++iter; //错误,不能改变指针的值
  5. vector<int>::const_iterator cIter = vec.begin(); // const T*
  6. *cIter = 10; //错误,值不能改变
  7. ++cIter; //没问题

const最有威力的地方是面对函数声明时的应用。可以和返回值、参数函数自身产生关联。

  • 返回值:令函数返回一个常量值
  1. const Rational operator*(const Rational &lhs, const Rational &rhs);

可以避免if(a * b = c)的发生。

  • const成员函数

const实施于成员函数的目的,是为了确认该成员函数可作用于const对象身上。有两个原因:(1)得知那个函数可以改动对象哪个不能,这很重要。(2)这使得操作const对象成为可能。根据参数的不同属性调用不同的版本。

  1. const char & operator[](size_t position) const
  2. { ...; ...; ...; return text[position]; }
  3. char & operator[](size_t position )
  4. { ...; ...; ...; return text[position]; }
  5. void print(const TextBlock & ctb)
  6. {
  7. cout << ctb[0]; //会根据ctb的常量属性调用不同的函数
  8. }

两个成员函数如果只是常量性(函数声明参数列表后有无const)不同,可以被重载。

mutable释放掉non-static成员变量的不可改变约束,这些变量可能总是会被改变,即使在const成员函数内。因此,在const成员函数内可以改变这些值,不会引起错误。对哪些变量使用mutable是要有很好的估计的,因为它能突破很多限制。

在上面的代码中,两个版本的operator[]除了返回值和常量属性不同外别无区别,存在着冗余和代码膨胀。有两个方法做的更好:(1)提取公共部分作为工具函数。(2)转型。显然,第一种方法仍不能根本上较少代码膨胀。

  1. char & operator[](size_t position )
  2. {
  3. //转型是安全的
  4. return const_cast<char&>(static_cast<const TextBlock&>(*this)[position]);
  5. }

我们做了两次转型,第一次是用来为*this添加const(这使接下来调用operator[]时得以调用const版本,避免对自己的递归调用),第二次是从const
operator[]
的返回值中移除const

这样,我们就能使用常量版本实现非常量版本,实现‘避免代码重复’。反过来是不行的,因为不能在常量版本中改变值。

条款04:确定对象在使用前已被初始化

除了内置类型,初始化的责任落在构造函数身上。规则很简单:确保每一个构造函数都对对象的每一个成员初始化。

注意的是:区分构造函数初始化和赋值的不同。在构造函数大括号中写的是赋值,因为初始化发生在进入大括号之前。因此使用初始化列表才是真正的初始化。虽然它们的结果相同,但是效率更高(赋值版本有发生一次构造一次赋值)。

总是使用初始值列表。

在初始时列表中,有着固定的初始化顺序:基类早于派生类,类的成员变量以生命顺序初始化(即使在列表中以不同次序出现)。

时间: 2024-10-16 15:41:32

Effective C++ (笔记) : 条款01 -- 条款04的相关文章

《Effective C++ 》学习笔记——条款01

-------------------------------------- | 其实,买这本书有几个月了, | 一直想好好拜读一下, | 但一直给自己各种借口( 欠抽啊~ ) | | 下定决心,好好读一下! | 把文章的重点,加上一些自己的理解, | 写成博文,记录学习点滴也能督促下自己. -------------------------------------- ****************************  一. Accustoming Yourself to C++ ***

Effective C++笔记04:设计与声明

条款18:让接口容易被正确使用,不易被误用 1,好的接口很容易被正确使用,不容易被误用.你应该在你的所有接口中努力达成这些性质. 2,"促进正使用"的办法包括接口的一致性,以及与内置类型的行为兼容. 3,"阻止误用"的办法包括建立新类型,限制类型上的操作,束缚对象值,以及消除客户的资源管理责任. 4,shared_ptr支持定制型删除器.这可以防范DLL问题,可以用来自动解除互斥锁. 条款19:设计class犹如设计type 博客地址:http://blog.csd

条款01:View C++ as a federation of languages.

今天的C++已经是个多重范型编程语言(multiparadigm programming language),一个同时支持过程形式(procedural).面向对象形式(object-oriented).函数形式(functional).泛型形式(generic).元编程形式(metaprogramming)的语言.最简单的方法是将C++视为一个由相关次语言(sublanguage)组成的联邦而非单一语言.幸运的是,次语言总共有四个:• C.• Object-Oriented C++.包括:cl

Effective C++笔记:构造/析构/赋值运算

条款05:了解C++默默编写并调用哪些函数 默认构造函数.拷贝构造函数.拷贝赋值函数.析构函数构成了一个类的脊梁,只有良好的处理这些函数的定义才能保证类的设计良好性. 当我们没有人为的定义上面的几个函数时,编译器会给我们构造默认的. 当成员变量里有const对象或引用类型时,编译器会不能合成默认的拷贝赋值函数:当一个基类把它的拷贝赋值函数定义为private时,它的派生类也不无生成默认的拷贝赋值函数,因为它无法完成基类成份的赋值. 条款06:若不想使用编译器自动生成的函数,就该明确拒绝 将拷贝构

Effective C++笔记06:继承与面向对象设计

关于OOP 博客地址:http://blog.csdn.net/cv_ronny 转载请注明出处! 1,继承可以是单一继承或多重继承,每一个继承连接可以是public.protected或private,也可以是virtual或non-virtual. 2,成员函数的各个选项:virtual或non-virtual或pure-virtual. 3,成员函数和其他语言特性的交互影响:缺省参数值与virtual函数有什么交互影响?继承如何影响C++的名称查找规则?设计选项有如些?如果class的行为

Effective C++笔记05:实现

条款26:尽可能延后变量定义式的出现时间 博客地址:http://blog.csdn.net/cv_ronny 转载请注明出处! 有些对象,你可能过早的定义它,而在代码执行的过程中发生了导常,造成了开始定义的对象并没有被使用,而付出了构造成本来析构成本. 所以我们应该在定义对象时,尽可能的延后,甚至直到非得使用该变量前一刻为止,应该尝试延后这份定义直到能够给它初值实参为止. 这样做的好处是:不仅可以避免构造(析构)非必要对象,还可以避免无意义的default构造行为. 遇到循环怎么办?此时往往我

Effective c++(笔记) 之 杂项讨论

看到了Effective c++的最后一章,最开始的那章---内存管理还没搞清楚,准备那章搞清楚完也写篇博客,不管怎样,有好的开始就应该让它有个完美的结束,杂项讨论这章是作者将那些分到哪章都不合适的就索性放到了最后讨论,我看完后从中摘出自己认为重要的坐下笔记,如果能帮得到大家,那就更荣幸了哈! 1.当我们定义一个类时,编译器会自动给我产生哪些成员函数? 解析:我们都知道,当我们定义类时,如果我们没有定义某些成员函数的话,编译器会总会给我们自动合成,这就是编译器默默为我们完成和调用函数,这些函数主

Effective C++ 笔记一 让自己习惯C++

条款01:视C++为一个语言联邦 C++是个多重范型编程语言,一个同时支持面向过程形式.面向对象形式.函数形式.泛型形式.元编程形式的寓言. 将C++视为几个子语言: 传统C:区块.语句.预处理器.内置数据类型.数组.指针.没有模板.没有异常.没有重载. 面向对象C++:类(包括构造函数析构函数).封装.继承.多态.虚函数. Template C++:泛型编程.模板元编程. STL:容器.迭代器.算法.函数对象(仿函数). 记住: C++高效编程守则视状况而变化,取决于你使用C++的哪一部分.

【Ext.Net学习笔记】01:在ASP.NET WebForm中使用Ext.Net

Ext.NET是基于跨浏览器的ExtJS库和.NET Framework的一套支持ASP.NET AJAX的开源Web控件,包含有丰富的Ajax运用,其前身是Coolite. 下载地址:http://www.ext.net/download/示例地址:http://examples.ext.net/ 1.首先下载Ext.Net,地址:http://www.ext.net/download/ ,有两种框架选择,选择下载WebForms 当前版本是2.5.1,压缩包里面包含了不同版本,分别用在相应.