基础议题
#
# 基础议题
# Item 1:区别 pointers和 references
- references 必须有初值,pointer是可以没有初值的;(reference 一定得代表某个对象)
```cpp
string &rs // 错误
string s("hello");
string& rs=s; // 正确
string* ps; // 正确
```
用references 可能会比使用pointers 更高效。因为使用 reference 之前不需要测试其有效性, 如果是指针, 需要判断是否为nullptr, if(pc),
Pointers 和 references 之间的一个重要差异是,pointers 可以被重新赋值指向另一个对象,reference 却总是指向(代表)它最初获得的那个对象
先考虑用pointer, 如果真的是指向一个不变的东西, 或者pointer办不到的时候, 再考虑使用referenc
# Item 2:尽量使用C++的Cast操作符而不是C的
优先使用C++的cast操作: static_cast(), const_cast(), reinterprete_cast(), dynamic_cast();
static_cast 基本上拥有与 C 旧式转型相同的威力与意义,以及相同的限制。
const_cast 用来改变一个变量的常量性(constness)或变易性(volatileness)
dynamic_cast,用来“安全地向下转型或跨系转型动作”。也就是说可用dynamic_cast,将“指向base class objects的pointers或 references”转型为“指向 derived(或 sibling base)class objects的 pointers 或 references”,并能够通过返回值得知转型是否成功(0 or 1)
具体到函数的传参上面使用, 其实就是多态的相反的用法:
update(&csw); update(const_cast<SpecialWidget*>(&csw)); // 转移const属性; update(dynamic_cast<SpecialWidget*>(&csw)); // 从父类cast到子类;
1
2
3
reinterpret_cast转换结果几乎总是与编译平台息息相关。所以reinterpret_casts不具移植性。reinterpret_cast的最常用的地方是转换“函数指针”。
# Item 3:不以多态(polymorphically)方式处理数组
不要以多态的方式处理数组, 因为多态的时候, 导致数组里面元素的大小不一样, 在数组里面slicing会导致便偏移错误;
// sample code
class BST{ ... };
class BalancedBST : public BST{ ... };
void printBSTArray(ostream &s, const BST array[], int numElements){
for(int i=0; i<numElement; i++){
s << array[i]; // 假设BST Objects有一个operator可用
}
}
BST BSTArray[10];
PrintBSTArray(cout, BSTArray, 10); // 运行良好
BalancedBST bBSTArray[10];
printBSTArray(cout, bBSTArry, 10); // 多态方式处理, 不可以, 结果未定义
// 如果删除
void deleteArray(ostream &logstream, BST array[]){
logStream << "Deleting array at address, " << static_cast<void*>(array) << "\n";
delete [] array;
}
BalancedBST *balTreeArray = new BalancedBST[50]; // 产生一个子类数组;
deleteArray(cout, balTreeArray); // 这样通过父类指针去删除子类数组, 结果未定义;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
多态和指针算数不能够混用;
# Item 4:非必要不提供 default constructor
非必要不使用默认的default constructor(没有参数的ctor)
在一个完美的世界中,凡可以“合理地从无到有生成对象”的 classes,都应该内含 default constructors,而“必须有某些外来信息才能生成对象”的 classes,则不必拥有 default constructors。但我们的世界毕竟不是完美的世界,所以我们必须纳入其他考虑。
缺乏default constructor可能产生的问题
class Equipement{ public: Equipement(int numEque); }
1
2
3
4在产生数组的时候。无法为数组中的对象指定 constructor 自变量,所以几乎不可能产生一个由 EquipmentPiece objects 构成的数组:
Equipement bestPieces[10]; // 出错 没有办法调用default ctor Equipement *bestPieces = new EquipementPiece[10]; // 出错
1
2这些class不适用于许多 template-based container classes。对那些 templates 而言,被实例化(instantiated)的“目标类型”必须得有一个 default constructors。
virtual base class constructors 的自变量必须由欲产生的对象的派生层次最深(所谓 most derived)的 class 提供。于是,一个缺乏 default constructor的 virtual base class,要求其所有的 derived classes——不论距离多么遥远——都必须知道、了解其意义,并且提供 virtual base class 的 constructors 自变量, 这是非常难做到的, 除非:
// sample
1
添加无意义的default constructors也会影响class的效率;
使其他的member function更加复杂