条款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";

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

1
2
3
4
5
6
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类型时可以使用枚举类型:

1
2
3
4
5
6
7
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)) 要保证每个参数加上括号, 即使这样还是会有预期外的情况:

1
2
3
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之外的类型:

1
2
3
template
<
class 
T>
inline 
const 
T& max(
const 
T& a, 
const 
T& b)

return 
a > b ? a : b; }

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

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

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

条款2 尽量用<iostream>而不用<stdio.h>

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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库的类有构造函数, <stdio.h>里的函数没有, 在某些涉及静态对象初始化顺序的时候, 如果可以确定没有隐患, 用标准C库更简单实用;

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

库的包含: <iostream>

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

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

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

Effective C++ 第二版 1)const和inline 2)iostream的更多相关文章

  1. Effective Java 第二版 Enum

    /** * Effective Java 第二版 * 第30条:用enum代替int常量 */ import java.util.HashMap;import java.util.Map; publi ...

  2. Book. Effective C++ item2-尽量使用const, enum, inline替换#define

    ##常规变量 c++里面的#define后面的定义部分,是不算代码的一部分的.所以如果你使用#define: #define ASPECT_RATIO 1.653 你希望这个代号ASPECT RATI ...

  3. Effective C++ 第二版 40)分层 41)继承和模板 42)私有继承

    条款40 通过分层来体现"有一个"或"用...来实现" 使某个类的对象成为另一个类的数据成员, 实现将一个类构筑在另一个类之上, 这个过程称为 分层Layeri ...

  4. Effective C++ 第二版 10) 写operator delete

    条款10 写了operator new就要同时写operator delete 写operator new和operator delete是为了提高效率; default的operator new和o ...

  5. Effective C++ 第二版 31)局部对象引用和函数内new的指针 32)推迟变量定义

    条款31 千万不要返回局部对象的引用, 不要返回函数内部用new初始化的指针的引用 第一种情况: 返回局部对象的引用; 局部对象--仅仅是局部的, 在定义时创建, 在离开生命空间时被销毁; 所谓生命空 ...

  6. 《Effective Java第二版》总结

    第1条:考虑用静态工厂方法代替构造器 通常我们会使用 构造方法 来实例化一个对象,例如: // 对象定义 public class Student{ // 姓名 private String name ...

  7. Effective C++ 第二版 17)operator=检查自己 18)接口完整 19)成员和友元函数

    条款17 在operator=中检查给自己赋值的情况 1 2 3 class  X { ... }; X a; a = a;  // a 赋值给自己 >赋值给自己make no sense, 但 ...

  8. 《Effective Java 第二版》读书笔记

    想成为更优秀,更高效程序员,请阅读此书.总计78个条目,每个对应一个规则. 第二章 创建和销毁对象 一,考虑用静态工厂方法代替构造器 二, 遇到多个构造器参数时要考虑用builder模式 /** * ...

  9. Effective C++ 第二版 5)new和delete形式 6) 析构函数里的delete

    内存管理 1)正确得到: 正确调用内存分配和释放程序; 2)有效使用: 写特定版本的内存分配和释放程序; C中用mallco分配的内存没有用free返回, 就会产生内存泄漏, C++中则是new和de ...

随机推荐

  1. iOS 学习

    iOS 学习资料 (适合初学者) 本文资料来源于GitHub 一.视频教程(英文) Developing iOS 7 Apps for iPhone and iPad斯坦福开放教程之一, 课程主要讲解 ...

  2. ORACLE 中极易混淆的几个 NAME 的分析和总结

    我们知道,Oracle中的各种NAME会在我们的各个配置文件里常常出现,大致有下面这些: 在init.ora中有DB_NAME,INSTANCE_NAME,SERVICE_NAME 配置DG的时候,为 ...

  3. java之集合框架使用细节及常用方法

    集合类的由来:   对象用于封装特有数据,对象多了需要存储,如果对象的个数不确定.  就使用集合容器进行存储. 集合特点: 1,用于存储对象的容器. 2,集合的长度是可变的. 3,集合中不可以存储基本 ...

  4. Android小应用-----画画板

    public class MainActivity extends Activity { private ImageView iv; float startX = 0; float startY = ...

  5. unity3d 血液

    这里的人物头像和血条是在3d世界生成的,所以有真正的纵深感和遮挡关系,废话不多说,看我是怎么实现的. 第一步.先在UI Root里制作头像和血条. 这个制作步骤基本和我前面一篇文章介绍头像血条的制作步 ...

  6. VS SQL 出现%CommonDir%dte80a.olb 该解决方案

    VS SQL  出现%CommonDir%dte80a.olb  该解决方案 在网上搜索解决方法的时候.别人就说你从别的电脑复制一个到C:\Program Files\Common Files\mic ...

  7. 读书笔记—CLR via C#异常和状态管理

    前言 这本书这几年零零散散读过两三遍了,作为经典书籍,应该重复读反复读,既然我现在开始写博了,我也准备把以前觉得经典的好书重读细读一遍,并且将笔记整理到博客中,好记性不如烂笔头,同时也在写的过程中也可 ...

  8. 启用密码管理之前创建的用户连接Oracle报ORA-28002处理一则

    处理方法其实很简单.只要:     alter user <username> identified by <same password>;  这个操作后,恢复正常了 下面作个 ...

  9. sql语句 面试题

    ql语句 面试题   自动编号   学号   姓名 课程编号 课程名称 分数 1        2005001  张三  0001      数学    69 2        2005002  李四 ...

  10. Effective C++(15) 在资源管理类中提供对原始资源的访问

      问题聚焦:     资源管理类是为了对抗资源泄露.     如果一些函数需要访问原始资源,资源管理类应该怎么做呢?        关于资源管理的概念总是显得那么的高大上,其实只是抽象一点. 下面用 ...