关于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代表的内部成员变量总是危险的。

effective c++:dynamic_cast,避免返回handles指向对象内部的更多相关文章

  1. [Effective C++ --028]避免返回handles指向对象内部成分

    假设程序涉及矩形.每个矩形由其左上角和右下角表示.为了让Rectangle对象尽可能小,可能把定义矩形的点放在一个辅助的struct内再让Rectangle去指它: class Point { // ...

  2. Effective C++:条款28:避免返回 handles 指向对象内部成员

    (一) 有时候为了让一个对象尽量小,能够把数据放在另外一个辅助的struct中,然后再让一个类去指向它.看以下的代码: class Point { public: Point(int x, int y ...

  3. Effective C++ -----条款28:避免返回handles指向对象内部成分

    避免返回handles(包括reference.指针.迭代器)指向对象内部.遵守这个条款可增加封装性,帮助const成员函数的行为像个const,并将发生“虚吊号码牌”(dangling handle ...

  4. 条款28:避免返回handles指向对象内部的成分(Avoid returning "handles" to objects internals)

    NOTE: 1.避免返回handles(包括references 指针 迭代器)指向对象内部.遵守这个条款可增加分装性,帮助const 成员函数的行为像个const,并将发生“虚吊号码牌”(dangl ...

  5. 【28】避免返回handles指向对象内部成分

    1.为什么? 很简单,你指向箱子里面的一个物品,使用这个物品.但是箱子不受你控制,箱子销毁了,里面的物品也会随之销毁.那么这种情况下,你指向的就是一堆垃圾,你还在使用这个物品,导致未定义的行为.

  6. [EffectiveC++]item28:避免返回handles指向对象内部成分

    可以先参考一个帖子:http://bbs.csdn.net/topics/390731394?page=1

  7. 读书笔记_Effective_C++_条款二十八:避免返回handlers指向对象内部成分

    举个例子: class Student { private: int ID; string name; public: string& GetName() { return name; } } ...

  8. 条款28:避免返回handles指向对象的内部成分。

    首先看看下面这个例子: class Point{ public: point(int x, int y); ... void setX(int newVal); void setY(int newVa ...

  9. 读书笔记 effective c++ Item 28 不要返回指向对象内部数据(internals)的句柄(handles)

    假设你正在操作一个Rectangle类.每个矩形可以通过左上角的点和右下角的点来表示.为了保证一个Rectangle对象尽可能小,你可能决定不把定义矩形范围的点存储在Rectangle类中,而是把它放 ...

随机推荐

  1. c# 获取字符串数组中最长的的字符串并输出最长的字符串

    求字符串数组中最大长度的字符串: 实质就是比较字符串的长度: 方案一: class Program { static void Main(string[] args) { string[] array ...

  2. 总结Allegro元件封装(焊盘)制作方法[修整]

    总结Allegro元件封装(焊盘)制作方法 在Allegro系统中,建立一个零件(Symbol)之前,必须先建立零件的管脚(Pin).元件封装大体上分两种,表贴和直插.针对不同的封装,需要制作不同的P ...

  3. github创建repo,本地导入git项目到github

    一般地,在注册好github账号之后,你需要做的事情就是在github上创建一个repo,该repo将成为你的origin(central)repo,随后你就可以将本地的项目git repo导入到这个 ...

  4. file类型允许的文件格式设置问题,“选择文件”打开缓慢

    1,file类型的input对于打开的选择框的属性是由以下两个属性控制的: ①multiple="multiple" :一次可以选择多个文件 ②accept="image ...

  5. UVa 11100 The Trip, 2007

    今天的教训:做题要用大块的时间来做,上午做一下,做题做到一半就去忙别的事,那么后面再做的时候就无限CE,WA了.因为你很难或者需要很长时间来找回当时的思路. 题意:就像套瓷娃娃一样,有n个包,大小可能 ...

  6. 内存泄露(OOM)现象及举例

    一.HeapSize OOM(堆空间内存溢出) A.eg:List.add(" ")在一个死循环中不断的调用add却没有remove. B.并发导致. 解决方法有:1.代码提速.这 ...

  7. Java程序执行过程

    首先,写好Java代码,保存到硬盘中.然后在命令行中输入: javac ClassName.java 此时,这个Java类文件将编译成字节码(.class)文件.如果用Eclipse等IDE开发工具, ...

  8. 【转】Android Interface的使用

    原文网址:http://www.3g-edu.org/Android_free/art115.htm Android应用程序采用Java语言编写,Java语法和C/C++有很大的相似性,但也有一些特别 ...

  9. php在apache中一共有三种工作方式:CGI模式、FastCGI模式、Apache 模块DLL

    php在apache中一共有三种工作方式:CGI模式.FastCGI .FastCGI是什么? FastCGI是语言无关的.可伸缩架构的CGI开放扩展,其主要行 为是将CGI解释器进程保持在内存中并因 ...

  10. 收缩Mysql的ibdata1文件大小方法

    ibdata1是mysql数据库中一个数据文件了,你会发现它来越大了,下面我来介绍收缩Mysql的ibdata1文件大小方法 如果你有使用InnoDB来存储你的Mysql表,使用默认设置应该会碰到个非 ...