?在C++中,强制转换是一种需要高度重视的功能。首先回顾一下强制转换的语法,相同的强制转换通常有三种不同的方式。
C风格强制转换:
(T) expression // 将表达式转换为类型T
函数式强制转换:
T(expression) // 将表达式转换为类型T
C++还提供了四种新的强制转换形式(通常称为新风格或C++风格强制转换:
const_cast<T>(expression)
用于移除对象的常量限制。这是唯一能做到这一点的c++风格的强制转换。
dynamic_cast<T>(expression)
用于执行“安全的向下转换”,即确定对象是否属于继承层次结构中的特定类型。这是唯一不能使 用旧式风格完成的转换。它也是唯一一种可能有较大运行时开销的类型转换。
reinterpret_cast<T>(expression)
用于底层强制转换,其结果依赖于实现(即不可移植),例如将指针强制转换为int类型。这种类 型转换在底层代码之外应该很少见。
static_cast<T>(expression)
用于强制隐式转换
单向:例如,非const对象到const对象,int到double的转换等等
双向:指向类型化指针和void*指针,基类的指针和派生指针等等
?旧式强制转换仍然是合法的,但新风格更可取;唯一使用 C 式转型的时机可能是在调用 explicit 构造函数时:
class Widget {
public:
explicit Widget(int size);
...
};
void doSomeWork(const Widget& w);
doSomeWork(Widget(15)); //函数式,从int创建Widget
doSomeWork(static_cast<Widget>(15)); // C++风格,从int创建Widget
转换并不是让编译器把一个类型看作是另一个类型那么简单:
int x, y;
...
double d = static_cast<double>(x)/y; // 转换会生成些代码,因为int的底层表示与double不同
class Base { ... };
class Derived : public Base { ... };
Derived d;
Base* pb = &d; // 隐式转换:Derived* ? Base*
?有时,两个指针的值并不相同,需要使用偏移量,在运行时应用于Derived指针,以获得正确的Base指针值。
不要让编译器将*this看作是其基类部分的对象:
class Window { // 基类
public:
virtual void onResize() { ... } // onResize的基类实现
...
};
class SpecialWindow : public Window { // 派生类
public:
virtual void onResize() { // // onResize的派生类实现;
static_cast<Window>(*this).onResize(); // 将 *this 转换为 Window,
// 然后调用它的onResize,这不管用!
... // 这里做派生类的特有任务
}
...
};
要调用基类部分的函数,应该写成
class SpecialWindow : public Window {
public:
virtual void onResize() {
Window::onResize(); // 在*this上调用 Window::onResize
...
}
...
};
dynamic_cast的开销较大,深层的层次结构或使用多重继承的层次结构更加昂贵。
class Window { ... };
class SpecialWindow : public Window {
public:
void blink();// 假设只有SpecialWindow才有这个功能
...
};
typedef std::vector<std::shared_ptr<Window> > VPW;
VPW winPtrs;
...
for (VPW::iterator iter = winPtrs.begin(); iter != winPtrs.end(); ++iter) {
// 不良代码:使用了dynamic_cast
if (SpecialWindow* psw = dynamic_cast<SpecialWindow*>(iter->get()))
psw->blink();
}
应该改为:
typedef std::vector<std::tr1::shared_ptr<SpecialWindow> > VPSW;
VPSW winPtrs;
...
for (VPSW::iterator iter = winPtrs.begin(); iter != winPtrs.end(); ++iter)
(*iter)->blink();
?前面的方法不允许将指向多种派生类的指针存储在同一个容器中。还有一种方法可以通过基类接口操作多种派生类,那就是在基类中提供虚函数。在基类提供默认实现,什么都不做:
class Window {
public:
virtual void blink() {} // 什么也不做;
...
};
class SpecialWindow : public Window {
public:
virtual void blink() { ... }; //执行有意义的任务
...
};
typedef std::vector<std::shared_ptr<Window> > VPW;
VPW winPtrs; // 支持多种Windows类型的容器
for (VPW::iterator iter = winPtrs.begin();iter != winPtrs.end();++iter)
(*iter)->blink(); // 注意:无需dynamic_cast
一定要避免涉及串联(cascading)dynamic_cast的设计,即任何类似下面这样的设计:
class Window { ... };
... // 一些派生类的定义
typedef std::vector<std::tr1::shared_ptr<Window> > VPW;
VPW winPtrs;
...
for (VPW::iterator iter = winPtrs.begin(); iter != winPtrs.end(); ++iter)
{
if (SpecialWindow1* psw1 =dynamic_cast<SpecialWindow1*>(iter->get())) {...}
else if (SpecialWindow2* psw2 =dynamic_cast<SpecialWindow2*>(iter->get())) {...}
else if (SpecialWindow3* psw3 =dynamic_cast<SpecialWindow3*>(iter->get())) {...}
...
}
?这样的C++生成的代码既大又慢,而且很脆弱,因为每次Window类层次结构发生变化时,都必须检查所有这些代码以确定是否需要更新。