条款27:尽量少做转型动作

 在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对象,intdouble的转换等等
 双向:指向类型化指针和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类层次结构发生变化时,都必须检查所有这些代码以确定是否需要更新。

  • 11
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值