Effective C++ ITEM27.尽量少做转型动作

C++ 四种转型

const_cast 通常被用来将对象的常量性转除(cast away the constness)。也是唯一有能力的C++ style转型操作符
dynamic_cast 主要用来执行“安全向下转型(safe downcasing)”也就是用来决定某对象是否归属继承体系中的某个类型。它是唯一无法由旧式语言执行的动作,也是唯一可能耗费重大运行成本的转型动作
reinterpret_cast 意图执行低级转型,实际动作(及结果)可能取决于编译器,也就是表示它不可移植。例如将一个point to int 转型为一个int。这一类的低级代码以外很少见。本书只使用一次,讨论针对原始内存(raw memory)写出一个调试用的分配器(debugging allocator)
static_cast 用来强制隐式转换(implicit conversions), 例如将non-const 对象转换为const对象(就像条款3所为), 或将int 转换为double等等。它也可以用来执行上述多种转换的反向转换,例如将void*指针转为typed指针。将point-to-base 转为pointer-to-derived。但它无法将const 转换为non-const,只有const_cast才办得到。

单一对象可能拥有一个以上地址

多继承时
#include <iostream>

using namespace std;
class Base1 {
public:
    Base1() {}
    virtual ~Base1() {};
    virtual void speakClearly() {
        cout<<"Hello World!"<<endl;
    }
    virtual Base1* clone() const {
        return new Base1(*this);
    }
protected:
    float data_Base1;
};


class Base2 {
public:
    Base2() {}
    virtual ~Base2() {}
    virtual void mumble() {
        cout<<"mumble"<<endl;
    }
    virtual Base2* clone() const {
        return new Base2(*this);
    }
protected:
    float data_Base2;
};


class Derived : public Base1, public Base2
{
public:
    Derived (/* args */);
    virtual ~Derived ();
    virtual Derived* clone() {
        return new Derived(*this);
    }
private:
    /* data */
};

Derived ::Derived (/* args */)
{
}

Derived ::~Derived ()
{
}

int main()
{
    Derived derived;
    Base1* pb1 = &derived;
    Base2* pb2 = &derived;
    cout<<"drived: "<<&derived<<"\tpb1: "<<&pb1 <<"\tpb2: "<<&pb2<<endl;
    return 0;
}

输出如下:
多继承对象地址

单继承时
#include <iostream>
#include <string>

using namespace std;

class Animals {
public:
    Animals() {};
    virtual ~Animals() {};
    virtual void Bark() {
        name = "Wu Wu Wu";
        cout << name << endl;
    }
protected:
    string name = "Animals";
};

class Dog : public Animals {
public:
    Dog() {};
    virtual ~Dog() {};
    virtual void Bark() {
        name = "Wang Wang Wang";
        cout << name << endl;
    }
};

int main() 
{
    Dog dog;
    Animals* animal = &dog;
    cout<<"animal address:"<< &animal << "\tDog Address" << &dog << endl;
    return 0;
}

输出:
单继承对象
TIPS

不要对"对象在C++中如何布局的假设"。更不应该以假设为基础做任何转型动作。例如:将对象地址转换char*指针,然后在其身上做指针算术

转型动作时调用的是"*this对象之base class 成分"的暂时副本身上的onResize

假设有代码如下:

#include <iostream>
#include <string>

using namespace std;

class Window
{
public:
    Window(/* args */);
    ~Window();
    virtual void Resize() {
        posX = 100;
        posY = 100;
        length = 100;
        width = 100;
    }
protected:
    int posX;
    int posY;
    int length;
    int width;
};

Window::Window(/* args */)
{
}

Window::~Window()
{
}

class SpecialWindow : public Window
{
public:
    SpecialWindow(/* args */);
    ~SpecialWindow();
    virtual void Resize() {
        static_cast<Window>(*this).Resize();
        title = "Hello Window";
        cout << "PosX: " << posX << "\tPosY: " << posY << "\tLength: "<< length << "\tWidth: " << width << "\ttitle: " << title << endl; 

        Window::Resize();
        cout << "PosX: " << posX << "\tPosY: " << posY << "\tLength: "<< length << "\tWidth: " << width << "\ttitle: " << title << endl; 
    }   
private:
    string title;
};

SpecialWindow::SpecialWindow(/* args */)
{
}

SpecialWindow::~SpecialWindow()
{
}

int main()
{
    SpecialWindow specialWindow;
    Window* pW = &specialWindow;
    pW->Resize();
    return 0;
}

输出如下:
副本上调用OnResize
如上代码,第一次输出的时候,Window中onResize没有执行,而SpecialWindow中的onResize却执行了。方法的执行出现了一种"伤残"的状态。
如此正常的写法应当如下:

class SpecialWinow : public Window {
public:
	virtual void OnResize() {
		Window::OnResize();
		...
	}
...
};
dynamic_cast 可能会耗用多达四次的strcmp调用
  • 深度继承和多重继承的成本将更会更高
  • 在注重效率的代码中尽量避免使用dynamic_cast
  • 连续的dynamic_cast 使用更是要避免

总结

  • 尽量避免转型动作,尤其是注重效率的代码中,尽量不要使用dynamic_cast, 如果存在设计需要转型情况,尝试使用无需转型的方法
  • 如果转型是必要的,试着将转型动作放在函数,调用方无需感知转型动作
  • 如果真的需要转型,尽量使用C++style casts
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值