Effective C++ 第二版 1)const和inline 2)iostream

2014-11-23 23:21:22 · 作者: · 浏览: 4

条款1 尽量用const和inline而不用#define

>"尽量用编译器而不用预处理"
Ex. #define ASPECT_R 1.653 编译器永远不会看到ASPECT_R这个符号名, 在源码进入编译器之前, 就被预处理程序去掉, ASPECT_R 不会被加入到符号列表中; 编译报错时, 报错信息指向1.653, 让程序员无法跟踪错误;(这个问题也会出现在符号调试器中);

>Solution: 定义常量 const double ASPECT_R = 1.653; 常量定义一般是在头文件中, 许多源文件会包含它; [me: 如果只是局部使用的常量应该放在cpp中]
Note 定义指针常量时要注意, 除了指针所指的类型定义成const, 指针也经常要定义成const; Ex. const char* const kName = "Scott";

定义类的常量, 把常量限制在类中, 为了保证常量只有一份拷贝, 把它定义为静态成员:

123456 class GamePlayer {private: static const int NUM_TURNS = 5; // constant declaration (老的编译器不接受静态成员声明时初始化) int scores[NUM_TURNS]; // use of constant...};

Note 如果上面只是NU_TURNS的声明(没有 '= 5'), 必须在类实现代码中定义类的静态成员: const int GamePlayer::NUM_TURNS = 5; // mandatory definition; goes in class impl. file;

[文中可能是写反了, 头文件中有了 '= 5'就已经是定义了, 不需要在cpp中再定义;]


Note 类内只允许初始化整数类型的静态成员: int, bool, char...

Issue 必须在头文件中定义静态成员的情况: 当你的类需要用到这个类的常量时: e.g. GamePlayer::scores数组声明(编译时需要知道数组大小); [SIZE必须是静态常量或枚举数]

Solution 对于不支持头文件定义静态常量的编译器, 借用enum, 当需要int类型时可以使用枚举类型:


1234567 class GamePlayer {private: enum { NUM_TURNS = 5 }; // "the enum hack" — makes // NUM_TURNS a symbolic name for 5 int scores[NUM_TURNS]; //fine...}

#define 指令实现看起来像函数的宏, 但是不会导致函数的调用;


#define max(a,b) ((a) > (b) (a) : (b)) 要保证每个参数加上括号, 即使这样还是会有预期外的情况:

123 int a = 5, b = 0;max(++a, b); // a 的值增加了2 次max(++a, b+10); // a 的值只增加了1 次

>根据值来决定max的运行;


使用内联函数替代: inline int max(int a, int b) { return a > b a : b; }

使用模板来扩展int之外的类型:

123 templateinline const T& max(const T& a, const T& b){ return a > b a : b; }

>模板产生一套函数, 每个函数比较两个可以转换成同种类型的对象, 返回大的;


Note 在使用模板写max之类的通用函数前, 先检查标准库中是否已经存在;


const和inline减少了预处理的使用, 但是#include还不能缺少, #ifdef/#ifndef 在控制编译的过程中也很重要;


条款2 尽量用而不用

scanf/printf 轻巧, 高效, 但不是类型安全的, 没有扩展性; 需要把读写的变量和控制读写格式的信息分开(FORTRAN style);

>>和<<, 实现重载函数可以处理不同的类型; 读写语法形式相同, 不需要记住格式规定;

12345678910111213141516 int i;Rational r; //有理数cin >> i >> r;cout << i << r;class Rational {public: Rational(int numerator = 0, int denominator = 1);...private: int n, d; // 分子,分母 friend ostream& operator<<(ostream& s, const Rational& r);};ostream& operator<<(ostream& s, const Rational& r){ s << r.n << '/' << r.d; return s;}

>"opertaor<<"不是成员函数(是操作符);


相对不足:

1) 有些iostream的操作比起相应的C stream效率低;

2) 标准化过程中, iostream库在底层做了很多修改, 对要求最大可移植性的程序来说, 不同的厂商遵循标准的程度不同;


3) iostream库的类有构造函数, 里的函数没有, 在某些涉及静态对象初始化顺序的时候, 如果可以确定没有隐患, 用标准C库更简单实用;

优点: iostream库的类和函数类型安全, 可扩展性好;

库的包含:

#include 得到的是置于全局空间的iostream库元素;

#include 得到的是置于名字空间std下的iostream库元素;

全局空间获取元素可能导致名字冲突;