zoukankan      html  css  js  c++  java
  • effective c++:dynamic_cast,避免返回handles指向对象内部

    关于dynamic_cast

    假定我们有一个基类指针bp,我们在运行时需要把它转换成他的派生类指针,这个时候需要用到dynamic_cast.

    Derived *dp = dynamic_cast<Derived*> bp

    值得注意的是dynamic_cast执行速度很慢,如果在深度继承或多重继承中使用,成本更高,所以在程序中要尽量避免使用dynamic_cast,有两种方案替代它:

    第一,在容器中存储指向派生类的指针,尽量避免以下dynamic_cast的用法

    class Window { ... };
    class SpecialWindow: public Window {
    public:
      void blink();
    ...
    };
    typedef // see Item 13 for info
    std::vector<std::tr1::shared_ptr<Window> > VPW; // on tr1::shared_ptr
    VPW winPtrs;
    ...
    for (VPW::iterator iter = winPtrs.begin(); // undesirable code:
      iter != winPtrs.end(); // uses dynamic_cast
      ++iter) {
     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(); // better code: uses
      iter != winPtrs.end(); // no dynamic_cast
      ++iter)
      (*iter)->blink();

    这种方法有个缺陷就是无法使用容器内的指针指向基类所有的派生类。

    一般来讲另一种方法更通用些,即在容器中存放基类指针,通过虚函数来选择各种派生类想要实现的功能。

    class Window {
    public:
      virtual void blink() {} // default impl is no-op;
      ... // see Item34 for why
    }; // a default impl may be
    // a bad idea
    class SpecialWindow: public Window {
    public:
      virtual void blink() { ... } // in this class, blink
      ... // does something
    };
    typedef std::vector<std::tr1::shared_ptr<Window> > VPW;
    VPW winPtrs; // container holds
    // (ptrs to) all possible
    ... // Window types
    for (VPW::iterator iter = winPtrs.begin();
      iter != winPtrs.end();
      ++iter) // note lack of
      (*iter)->blink(); // dynamic_cast

    避免返回handles(reference,指针,迭代器)指向对象内部

    class Rectangle {
    public:
      ...
      const Point& upperLeft() const { return pData->ulhc; }
      const Point& lowerRight() const { return pData->lrhc; }
      ...
    };
    struct RectData { // Point data for a Rectangle
      Point ulhc; // ulhc = “ upper left-hand corner”
      Point lrhc; // lrhc = “ lower right-hand corner”
    };
    class Rectangle {
      ...
    private:
      std::tr1::shared_ptr<RectData> pData; // see Item13 for info on
    };

    这段代码是返回一个Point对象,考虑到封装性问题,该对象是禁止修改的,但是他的问题是返回了private内容,可能在下面场合下出现问题。

    class GUIObject { ... };
    const Rectangle // returns a rectangle by
    boundingBox(const GUIObject& obj); // value; see Item3 for why
    // return type is const
    GUIObject *pgo; // make pgo point to
    ... // some GUIObject
    const Point *pUpperLeft = // get a ptr to the upper
    &(boundingBox(*pgo).upperLeft()); // left point of its
    // bounding box

    boundingBox调用获得的是一个暂时的Rectangle对象,返回一个指向内部成员的引用,在执行完最后一条语句后,这个暂时的对象被销毁,最终导致的是pUpperLeft指向的是一个被销毁的对象,造成指针悬空(dangling)。

    所以说返回一个handles代表的内部成员变量总是危险的。

  • 相关阅读:
    Hibernate 基本写法
    JavaWeb中的中文乱码问题
    AJAXJson
    Hibernate 的几个概念
    sql 中的备份集、备份设备、媒体、媒体集
    收缩数据库日志文件
    AJAXjs
    rand一定要加srand随机数种子
    CheckBit,SetBit设置二进制位的方法使用
    memset(buf,0,100)和memset(buf,'\0',100)有什么区别?
  • 原文地址:https://www.cnblogs.com/loujiayu/p/3624376.html
Copyright © 2011-2022 走看看