条款27:尽量少做转型动作
C++规定的设计目标之一是,保证“类型错误”绝不可能发生。这是一个极具价值的保证。C++提供四种新式转型(常常被称为new-style或C+±style casts):
const_cast<T>(expression)
dynamic_cast<T>(expression)
reinterpret_cast<T>(expression)
static_cast<T>(expression)
- cosnt_cast通常被用来将对象的常量性转除。他也是唯一由此能力的C+±style转型操作符。
- dynamic_cast主要用来执行“安全向下转型”,也就是用来决定某对象是否归属继承体系中的某个类型。它是唯一无法由旧式语法执行的动作,也是唯一可能耗费重大运行成本的转型动作。
- reinterpret_cast意图执行低级转型,实际动作可能取决于编译器,这也就表示他不可移植。
- static_cast用来强迫隐式转换,例如将non-const对象转换为const对象,或将int转为double等等。它也可以执行上多种转换的反向过程,例如将void*指针转为non-const----这个只有const_cast才能办到。
当调用一个explicit构造函数将一个对象传递给一个函数时,会使用旧时转型。例如:
class Widget {
public:
explicit Widget(int size);
...
};
void doSomeWork(const Widget& w);
doSomeWork(Widget(15)); //以一个int加上“函数风格”的
//转型动作创建一个Widget
doSomeWork(static_cast<Widget>(15)); //以一个int加上“C++风格”的
//转型动作创建一个Widget。
请记住
- 如果可以,尽量避免转型,特别是在注重效率的代码中避免dynamic_casts。
- 如果转型是必要的,试着将它隐藏于某个函数背后。
- 宁可使用C++ -style转型,不要使用旧式转型。前者很容易辨识出来,而且也比较有着分门别类的职掌。
条款28: 避免返回handles指向对象内部成分
假设你的程序涉及矩形,为了让一个Rectangle对象尽可能小,你可能会决定不把定义矩形的这些点放在Rectangle对象内,而是放在一个辅助的struct内再让Rectangle去指它:
class Point {};
struct RectData {
Point ulhc;
Point lrhc;
};
class Rectangle {
public:
...
Point& upperLeft() const { return pData->ulhc; } //返回底层的Point对象
Point& lowerRight() const { return pData->lrhc; }
...
private:
shared_ptr<RectData> pData;
};
Point是个用户自定义类型,所以根据条款20给我们的忠告,这些函数应该返回reference,指向底层的Point对象。这样设计可通过编译,但却是错的。实际上它是自我矛盾的。一方面upperLeft和lowerRight被声明为const成员函数,目的是为了让客户查看相关坐标点,而不是去修改他。另一方面两个函数却都返回了reference指向private内部数据,调用者于是可通过这些reference更改内部数据!
我们可以通过对返回类型添加const修饰即可:
class Rectangle {
public:
...
const Point& upperLeft() const {return pData->ulhc;}
const Point& upperLeft() const {...}
};
请记住
- 避免返回handles(包括reference、指针、迭代器)指向对象内部。遵守这个条件可增加封装性,帮助const成员函数的行为像个const,并将发生“dangling handles(悬挂)”的可能性降至最低。