Effective C++——条款1和条款2(第1章)

第一章    让自己习惯C++

Accustoming Yourself to C++

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

View C++ as a federation of languages

一开始C++只是C加上一些面向对象特性,但随着这个语言逐渐成熟,它开始接受不同于C with classes的各种观念,特性和变成战略.Exception对函数的结构化带来不同的做法,templates引入新的设计思考方式,STL定义了前所未见的伸展性做法.

    最简单的方法是将C++视为一个由相关语言组成的联邦而非单一语言.C++主要有以下四个次语言:

 1.C.C++是以C为基础.区块blocks,语句statements,预处理器preprocessor,内置数据类型built-in data types,数组arrays,指针pointer等都来自C.许多时候C++对问题的解法就是较高级的C解法,但以C++内的C成分工作时,高效编程则映照出C语言的局限:没有模板,没有异常,没有重载...

2.Object-Oriented C++.这部分也就是C with classes所诉求的:classes(包括构造函数和析构函数),封装(encapsulation),继承(inheritance),多态(polymorphism),virtual 函数(动态绑定)...等等.

 3.Template C++.这是C++的泛型编程(generic programming)部分.

4.STL.STL是个templates程序库.它对容器containers,迭代器iterators,算法algorithms以及函数对象function objects的规约有极佳的紧密配合与协调.

当从某个次语言切换到另一个时,高效编程则要求改变策略.例如对内置类型而言pass-by-value通常比pass-by-reference高效,但当从C part of C++移往Object-Oriented C++,由于用户自定义构造函数和析构函数的存在,pass-by-reference-to-const 往往更好.运用Template C++时更是如此.然而一旦跨入STL,迭代器和函数对象都是在C指针之上塑造出来的,所以对于STL的迭代器和函数对象而言,C的pass-by-value再次适用.

    注意:C++高效编程守则视情况而变化,取决于使用C++的哪一部分.

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

Prefer consts,enums,and inlines to #define

这个条款或许改为"宁可以编译器替换预处理器"比较好,因为或许#define不被视为语言的一部分,那正是问题所在,当做出以下事情:

#define ASPECT_RATIO 1.653

记号名称ASPECT_RATIO也许从未被编译器看见;也许在编译器开始处理源代码之前它就被预处理器移走了.于是ASPECT_RATIO可能没有进入记号表(symbol table)内.于是运用此常量但获得一个编译错误时,可能会带来困惑,因为这个错误信息也许提到1.653而不是ASPECT_RATIO.

    解决的办法是以一个常量替换上述的宏(#define):

const double AspectRatio = 1.653;

作为一个语言常量,AspectRatio可能会被编译器看到,一定会进入记号表内.此外对于浮点常量而言,使用常量可能会比使用#define导致较小量的代码,因为预处理器"盲目地将宏名称ASPECT_RATIO替换为1.653"可能导致目标码出现多份1.653,若是改用常量则不会出现这种情况.

当以常量替换#define,有两种特殊情况值得说说:

第一个是定义常量指针(constant pointers).由于常量定义式通常被放在头文件(以便被不同的源码含入),因此有必要将指针声明为const.例如若要在文件内定义一个常量的char*-base字符串,必须写 const 两次:

const char *const authorName = "Scott Meyers";

关于 const 的意义和使用(特别是当它与指针结合时),条款3有完整的讨论.string对象通常比其前辈char*-base合宜,所以上述的authorName往往定义这样更好:

const std::string authorName("Scott Meyers");

第二个值得注意的是 class 专属常量.为了将常量的作用域限制于 class 内,必须让它成为 class 的一个成员;而为确保此变量至多只有一份实体,必须让它成为一个 static 成员:

class GamePlayer {
private:
    static const int NumTurns = 5;
    int scores[NumTurns];
};

然而看到的是NumTurn的声明式而非定义式.通常C++要求对所使用的任何东西提供一个定义式,但如果它是个 class 专属常量又是 static 且为整数类型,则需要特殊处理.只要不取它们的地址,可以声明并使用它们而无须提供定义式.但如果取出某个 class 专属常量的地址,就必须提供定义式如下:

const int GamePlayer::NumTurns ;

由于 class 常量已在声明时获取初值,因此定义时不可以再设初值.

注意:

对于单纯变量,最好以 const 对象或 enums 替换#define.

对于形似函数的宏,最好改用 inline 函数替换#define.

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-28 11:16:19

Effective C++——条款1和条款2(第1章)的相关文章

Effective C++_笔记_条款08_别让异常逃离析构函数

(整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) C++并不禁止析构函数吐出异常,但它不鼓励你这样做.考虑如下代码: 1: class Widget{ 2: public: 3: ... 4: ~Widget() {...} //假设这个可能吐出一个异常 5: }; 6:  7: void doSomething() 8: { 9: vector<Widget> v ; //v在这里被自动销毁 10: ...

Effective C++_笔记_条款12_复制对象时勿忘其每一个成分

(整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 编译器会在必要时候为我们的classes创建copying函数,这些“编译器生成版”的行为:将被烤对象的所有成员变量都做一份拷贝. 如果你声明自己的copying函数,意思就是告诉编译器你并不喜欢缺省实现中的某些行为.编译器仿佛被冒犯似的,会以一种奇怪的方式回敬:当你的实现代码几乎必然出错时却不告诉你.所以自己实现copying函数时,请遵循一条规则:如果你为c

Effective C++_笔记_条款11_在operator=中处理“自我赋值”

(整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 为什么会出现自我赋值呢?不明显的自我赋值,是“别名”带来的结果:所谓“别名”就是“有一个以上的方法指涉对象”.一般而言如果某段代码操作pointers或references而它们被用来“指向多个相同类型的对象”,就需要考虑这些对象是否为同一个.实际上两个对象来自同一个继承体系,它们甚至不需要声明为相同类型就可能造成“别名”.因为一个base class的refe

Effective C++ 阅读笔记_条款27 尽量少做转型动作

Effective C++ 阅读笔记_条款27 尽量少做转型动作 1.转型的三种形式,可以分为两大类. (1)旧式转型(old-style casts) (1.1) (T) expresstion (1.2) T (expression) (2) 新式转型(c++-style casts) (2.1)const_cast<T> (expression) (2.2)dynamic_cast<T> (expression) (2.3)reinterpret_cast<T>

Effective C++_笔记_条款07_为多态基类声明virtual析构函数

(整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 这个规则只适用于polymorphic(带多态性质的)base class身上.这种base class的设计目的是为了用来“通过base class接口处理derived class对象”.假如我们在程序中设计factory(工厂)函数,让它返回base class指针,指向新生成的derived class对象,假设base class有个non-virtu

Effective C++_笔记_条款09_绝不在构造和析构过程中调用virtual函数

(整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 为方便采用书上的例子,先提出问题,在说解决方案. 1 问题 1: class Transaction{ 2: public: 3: Transaction(); 4: virtual void LogTransaction() const = 0 ; 5: ... 6: }; 7:  8: Transaction::Transaction() //Base cl

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

***************************************转载请注明出处:http://blog.csdn.net/lttree******************************************** 三.Resource Management 到了第三张了,这一章主要讲述的就是资源的管理. ①.OK,首先,什么是资源--一旦使用,就必须还给系统的东西.C++程序员最长使用的资源就是动态分配内存(因为如果你分配内存却不曾归还,会导致内存泄露),但显然内存只是你

《Effective C++》资源管理:条款16-条款17

条款16:成对使用new和delete时要采取相同形式 看下面一段代码有什么问题: string* stringArray=new string[100]; -- delete string; 程序使用了new开辟内存,然后使用delete释放内存,貌似没有什么问题.但是有某样东西完全错误:程序有不明确行为.stringArray内含有100个string对象,但是delete只是删除了一个,剩余的99个没有删除,它们的析构函数没有被调用. 当使用new(即用new动态创建一个对象),有两步.第

Effective Modern C++翻译(4)-条款3

条款3 了解decltype decltype是一个有趣的东西,给它一个变量名或是一个表达式,decltype会告诉你这个变量名或是这个表达式的类型,通常,告诉你的结果和你预测的是一样的,但是偶尔的结果也会让你挠头思考,开始找一些参考资料进行研究,或是在网上寻找答案.   我们从典型的例子开始,因为它的结果都是在我们预料之中的,和模板类型推导与auto类型推导相比(参见条款1和条款2),decltype几乎总是总是返回变量名或是表达式的类型而不会进行任何的修改 const int i = 0;

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

***************************************转载请注明出处:http://blog.csdn.net/lttree********************************************  一. Accustoming Yourself to C++ Rules 4: Make sure that objects are initialized before they're used 条款4:确定对象被使用前已先被初始化 一.原因: 关于"将对象