《C++ 沉思录》读书笔记
2012-12-02 14:22 robturtle 阅读(346) 评论(0) 编辑 收藏 举报check list for surrogate class
- 代理类实现了被代理类的所有虚拟方法;
- 代理类存储的数据指针是指向基类的;
- 被代理类实现 copy() const (必须有const修饰符,当代理类是用const类型构造时)
- 如果希望创建代理类数组,必须有默认构造函数,同时意味着代理类所有方法中对指针操作前都要检查是否有效。
return value's type
- T foo() const;
- const T& foo() const;
- T& foo();
只有(3)返回可修改左值。而(1)和(2)是实现‘读取’语义的可选项,其中(1)更偏重于‘值语义’,(2)更偏重‘指针语义’,这意味着:
仅当调用者拥有类型T的公有的复制构造函数时(1)才有效;(2)没有这个限制,但有一个严重的缺陷,就是当引用指向的内容发生内存地址偏移时,所有的引用变量都将失效。
简而言之,(1)对调用者有更多的假设,(2)更通用但要小心处理内存操作。
出于通用性和减少创建副本开销的考虑,往往会通过(2)实现‘读取’语义。
通过变量/指针返回左/右值
对于变量,可以通过重载函数的方式分别返回左/右值:
const T& foo(const T&) const;
T& foo(T&);
对于指针,可以通过继承的方式实现动态绑定:
class Class_const { const T& foo() const; }; class Class : public Class_const { T& foo(); };
迭代器
为什么要分别定义 iterator 和 reverse_iterator?
因为 c++ 语言中的方向不对称性(directional asymmetricity),考虑下面代码:
int a[10]; int *p1 = a[10]; // valid, p1 it's an accessable pointer int *tmp = a[0]; while (tmp != p1) *tmp++ = 0; // valid int *p2 = a[-1]; // undefined behavior tmp = a[9]; while (tmp != p2) // undefined behavior *tmp-- = 0;
因为这种不对称性,使得很难实现顺序算法的反向版本,即使实现也会大大增加复杂度。因此考虑定义不同的迭代器类型的方式会相对容易些。