C++ 转型动作 尽量避免 以及 那些意想不到的威胁

本文探讨了C++中转型的潜在风险,包括旧式转型和C++的四种转型函数。强调了static_cast可能导致的副作用,以及dynamic_cast在多重继承中的效率问题。建议尽量避免不必要的转型,使用虚函数和智能指针来减少转型需求,并提倡使用新式转型以提高代码可读性和安全性。
摘要由CSDN通过智能技术生成

看完EffectiveC++的关于转型的章节,顿时觉得周围的代码都处在悬崖边上~~




C的旧式转型inta = 10; double b = (double)a;

对于C++的四种转型函数,

const_cast去掉对象的常量性(只此一个操作符有此功能!)

dynamic_cast一般用于继承体系中某对象的归属,耗费较大

reinterpret_cast低级转型,几乎不用。

static_cast强迫隐式转换int->double, void * ->typed *


在类的expecilit构造函数中,例如:


class Widget
{
public:
 explicit: Widget(int size);
....
};

旧式转型有时也用,比如在,对于一个需要Widget对象作为参数的函数中,例如:void  f( Widget &w ); 调用时,使用旧式转型f(Widget(15))。


转型并不只是仅仅告诉编译器将该对象视为什么类型,编译器会做出一些动作来完成转型,例如:

int转化为double,在完成浮点数的乘法的时候,显然是要产生不同的目标码的。



下面的例子可能你每天都在用,那就是"基类的指针指向子类的对象",例如:

class Based { ... };

class Derived: public Based{ ... };

Derived de;

Based *pb = &de; //基类的指针指向子类的对象。


在实际。这两个指针的值可能不一样,或许是在当前对象上加了一个偏移量,这也就意味着,同一个Derived对象可能有两个地址,基类类型的指针与派生类类型的指针可能是不一样的。当然这依赖于内存布局(啊哦,不可移植性~~


一个接着一个,看似平时很习惯的东西,却一个一个的有着潜在的威胁:

class Parent
{
public:
    virtual void Func() {...}
    ...;
};
class Child : public Parent
{
public:
    virtual void Func() 
    {
        static_cast<Parent>(*this).Func(); //调用基类的版本
        ...; //子类自己的操作。
    }
};

在子类中调用父类定义的函数。这是再平常不过的事了。


可是上面的代码却很危险:

上面这段简单的代码,子类的Func函数首先调用父类的,再做子类的操作。可是,这里的static_cast得到的是一个临时副本,那么也就是说你的Func函数如果试图修改子类的成员,那么父类的部分是在临时副本上做的,也就是说,你可能会得到一个父类没有修改,子类却被修改了病态的对象。太可怕了,不是要尽量使用static_cast。要实现上述功能,直接指定作用域即可,即使用Parent::Fun()函数来调用。

PS:尽量少用转型。




对于dynamic_cast,那就更应当敬而远之了,除了执行速度很慢,尤其实在多重继承或是多层继承中,简单的类名搜索成本就很高了。

那么我们就必须知道,什么时候我们必须使用dynamic_cast呢?

现在你只有指向base”的指针或者引用,但是你需要的是对一个derived对象执行derivedclass的操作函数,你只能靠它们来处理对象。这里完全可以避免使用dynamic_cast,方法为:

1不要忘了虚函数;

2不要忘了智能指针;使用容器存放指向derived类的智能指针,这样变消除了使用base接口来处理对象的必要性,关于智能指针,参见智能指针



请记得:

在注重效率的应用中,对转型动作敬而远之吧!

如果必须转型,那么记得封装在函数里面,不要让这些恼人的代码干扰用户代码。

使用新式转型,各司其职,不易出错,比较容易在源代码中识别出来。

如果你觉得你必须使用转型,请再想想,迈出这危险的一步的代价~~~




  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值