posts - 9,  comments - 9,  trackbacks - 0

Effective C++ study note

From c to c plus plus

1. const inline | #define
    a. 符号列表
    b. 类成员const static
    c. define 的缺陷
    d. ifdef控制编译过程的作用

2. iostream | studio.h   
    a. 辩证看待两者:
       isotream 缺陷:效率,标准化移植性,构造函数对静态对象初始化顺序
       stdio.h缺陷:类型安全,扩展性
    b. iostream & iostream.h

3. new delete | malloc free
    a. constructor destructor
    b. match

4. use c++ comment style
    a. c++ style用于行注释以及嵌套注释相当有优势
    b. 老的编译器对预处理的时候不认识c++style注释

Memory management

5. match new delete
    a. new delete [] 如果不匹配意味着什么,这个是如何实现的?
    b. 杜绝数组的typedef

6. call delete in destructor
    a. 所有的指针成员都必须释放

7. 准备好内存不足的情况
    a. set_new_handler

8. operator new & operator delete 常规
    a. 如何重载类的new delete,需要考虑什么样的情况

9. 避免隐藏标准形式的new
    a. 如何全面支持标准new地操作,必须保持一致的调用方式。
    b. 注意new, delete调用时候是如何传参数的

10. 同时提供new,delete
    a. 需要传递这个大小的值吗?如何传递?尤其是继承的时候

Constructor destructor operator=
11. 适时提供拷贝构造以及赋值操作
    a. 深拷贝,浅拷贝,逐位拷贝,成员拷贝
    b. 类里有指针成员时候提供自己版本拷贝构造,赋值操作,选择(禁用,内存拷贝,引用计数)

12. 初始化列表与构造函数
    a. 必须置于初始化列表的情况
    b. 两者的含义。(构造函数初始化,以及赋值操作)
    c. 效率

13. 初始化列表中成员顺序和它们在类中申明的顺序
    a. 类成员是按照它们在类里被声明的顺序初始化的,如果多继承,按照基类生命顺序初始化。与初始化列表无关。

14. 基类有虚析构函数
    a. 为什么行为无法预知?
    b. 如何使用内联函数包装虚析构函数?

15. 让operator=返回*this地引用
    a. 为什么必须返回左值?
    b. 临时对象的const属性

16. 在operator=中对所有数据成员赋值
    a. 这里的所有成员包括:己类的成员, 所有基类成员。
    b. 如何处理基类的成员?
    c. 多继承下拷贝构造函数也有这样的问题。

17. 在operator=中检查给自己赋值的情况
    a. 检查的重要性:提高效率,保证正确性
    b. 如何检查 (值判断,地址判断,对象标识)
    c. 扩展,只要别名有可能出现的函数都需要注意这个问题

类与函数
18. 争取类的接口完整并且最小
   
19. 分清楚成员函数,非成员函数和友元函数
    a. 成员函数与非成员函数比较:虽然两者可以对所有参数隐式转换的。但是成员函数的this参数是不放在可转换列表里面的。
    b. 友元函数虽然也是属于非成员函数,但是它的不同就是能够访问私有变量。
    c. 设计一个函数的时候考虑顺序:成员函数->非成员函数->友元函数:只有非成员函数对最左面的参数进行类型转换,如果f需要对最左面的参数转换,让f成为非成员函数。如果f还需要访问类的非公有成员,让f成为类的友元函数。其他情况下都申明为成员函数。

20. 避免public接口出现数据成员
    a. 基于几方面的考虑(一致性,功能分离)

21. 尽可能使用const
    a. 星号作为分隔符
    b. bitwise constness & conceptual constness
    c. mutable or const_cast

22. 尽量用传引用而不是传值
    a. slicing-problem while pass value

23. 必须返回一个对象时不要试图返回一个引用
    a. for example: operator *

24. 在函数重载和设定参数缺省值间慎重选择
   
25. 避免对指针和数字类型重载

26. 潜在的二义性
    a. 二义性来源:方法二义性,函数重载参数二义性,继承带来的二义性
    b. C++语言的标准转换??
    c. 对类成员的引用所产生的二义性不考虑访问权限-〉改变一个类成员的访问权限不应该改变程序的含义

27. 如果不想使用隐式生成的函数就要显式地禁止它
    a. private申明它但是不去实现,这样链接器会帮你检查错误

28. 划分全局名字空间

类和函数:实现

29. 避免返回内部数据的句柄
    a. 指针,引用的返回。注意const版本

30. 避免这样的成员函数:返回值是指向成员非const指针或引用,但成员的访问级比这个函数要低

31. 不要返回局部对象的引用

32. 尽可能的推迟变量定义
    a. 不必要的函数调用开销

33. 明智的使用内联
    a. 内联的好处
    b. 被外联的内联函数的编译器处理上:首先都要承担函数调用的代价,其次旧的编译器还可能作为static函数处理来函数的链接的二义性
    c. 慎重选择内联,重视编译器的警告
    d. 内联的关键字是针对实现定义部分的,不是针对声明的
    e. 取内联函数的地址会导致编译器为此生成一个函数体,认为破坏内联定义
    f. 类成员函数声明时候同时定义函数体,默认成内联
    g. 在新的编译器上面,内联是一个不稳定的属性,至于在代码里的是否展开不能定论这个函数是否内联
    h. 在编译器看来多态始终比内联重要。在编译期间,静态调用是可以展开的,动态的不可以
    i. 内联是否展开除了要看本身代码的复杂度外还有其他因素影响:编译器的内联开关,调用方式
    j. 在新的编译器看来不管内联的是否展开或是否外联,亦或是否综合使用,记住,代码实体只有一份
    k. 虚函数与内联的结合是一个很特殊的例子。

34. 降低文件间的编译依赖性
    a. 前向声明 & 句柄类 & 协议类

继承和面向对象设计

C++提供了多种很令人困惑的面向对象构造部件,包括公有、保护和私有基类;虚拟和非虚拟基类;虚拟和非虚拟成员函数。这些部件不仅互相之间有联系,还和C++的其它部分相互作用。所以,对于每种部件的含义、什么时候该用它们、怎样最好地和C++中非面向对象部分相结合?

经典问题:
    a. 假如需要设计一组具有共同特征的类,是该使用继承使得所有的类都派生于一个共同的基类呢,还是使用模板使得它们都从一个共同的代码框架中产生?
    b. 类A 的实现要用到类B,是让A 拥有一个类型为B 的数据成员呢,还是让A 私有继承于B?
    c. 假设想设计一个标准库中没有提供的、类型安全的同族容器类(条款49列出了标准库实际提供的容器类),是使用模板呢,还是最好为某个 "自身用普通(void*)指针来实现" 的类建立类型安全的接口?

35. 公有继承体现‘是一个’的含义

36. 区分接口继承和实现继承
    a. 纯虚函数的目的在于:使派生类仅仅是继承函数的接口
    b. 简单虚函数的目的在于:使派生类继承函数的接口和缺省实现
    c. 非虚函数的目的在于:使派生类继承函数的接口和强制实现

37. 决不要重新定义继承而来得非虚函数
    a. 非虚函数是静态绑定,虚函数是动态绑定

38. 决不要重新定义继承而来的缺省参数值
    a. 缺省参数值也是静态绑定的

39. 避免‘向下转换’继承层次
    a. 向下意味着向派生类转换
    b. 如何消除向下转换:虚函数;加强类型约束;dynamic_cast

40. 通过分层来体现‘有一个’或‘用……来实现’

41. 区分继承和模板
    a. 两者的区别在于类型T是否影响类的行为

42. 明智的使用私有继承
    a. 私有继承常用语实现而非设计
    b. 实例化模板导致代码膨胀
    c. 示例代码设计:

 1 template<class T>
 2 class Stack: private GenericStack {
 3 public:
 4  void push(T *objectPtr) { GenericStack::push(objectPtr); }
 5  T * pop() return static_cast<T*>(GenericStack::pop()); }
 6  bool empty() const return GenericStack::empty(); }
 7 }

 8
 9 class GenericStack {
10 protected:
11  GenericStack();
12  ~GenericStack();
13  void push(void *object);
14  void * pop();
15  bool empty() const;
16 private:
17  // 同上
18 }

19

 

43. 明智的使用多继承
    a. adapter 是一个很好的多继承的例子
    b. 虚继承的实现以及构造特性

44. 说你想说的,理解你说想说的
    a. 整盘的设计考虑
    b. 共同的基类意味着共同的特性; 公有继承意味着是一个, 私有继承意味着用什么来实现, 分层意味着有一个或者用……来实现
    c. 对于公有继承而言:纯虚函数意味着继承接口,简单虚函数意味着继承函数的接口加上一个缺省实现,非虚函数意味着继承数的接口加上一个强制实现(特殊性上的不变性)

杂项

45. 弄清楚C++在幕后为你所作的
    a. 缺省类成员函数:构造,拷贝构造,析构(虚待定),赋值,取址(2个)
    b. 注意:如果需要这些函数才会被生成
    c. 赋值操作必须验证合法才能通过编译器

46. 宁可编译和链接时出错,也不要运行时出错

47. 确保非局部静态对象在使用前被初始化
    a. 初始化的顺序不确定导致很难捕捉这个静态对象初始化的顺序
    b. 解决办法:singleton

48. 重视编译器警告

49. 重视标准库

posted on 2007-04-10 12:23 MicroYang 阅读(325) 评论(0)  编辑 收藏 引用

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2007年4月>
25262728293031
1234567
891011121314
15161718192021
22232425262728
293012345

常用链接

留言簿(1)

随笔档案

Friend

  • Catherine
  • 深海羚羊
  • 似雨打芭蕉,似风吹梧桐叶,带着一丝冰冷,也带着一丝清新------冰柔语丝

搜索

  •  

最新评论

阅读排行榜

评论排行榜