(一)

有时候为了让一个对象尽量小,能够把数据放在另外一个辅助的struct中,然后再让一个类去指向它。看以下的代码:

class Point {
public:
Point(int x, int y);
void setX(int newVal);
void setY(int newVal);
}; struct RectData {
Point ulhc;
Point lrhc;
}; class Rectangle {
public:
Point& upperLeft() const { return pData->ulhc; }
Point& lowerRight() const { return pData->lrhc; }
private:
std::tr1::shared_ptr<RcetData> pData;
};

这种设计看上去非常beautiful。可是却是错误的,实际上它是自相矛盾的,看以下的代码:

Point coord1(0, 0);
Point coord2(100, 100);
const Rectangle rec(coord1, coord2);
rec.upperleft().setX(50);

错误的理由:(1)upperLeft()跟lowerRight()这两个函数都是const的,所以客户不能改动Rectangle;

(2)两个函数都返回reference指向private内部数据,调用者于是可通过这些reference更改内部数据。

upperLeft的调用者可以使用被返回的引用来更改成员。但rec事实上应该是不可变的(const)!

所以上面那种类的设计是错误的!!!

所以从这个样例中,我们能够得到下面的教训:

(1)成员变量的封装性会被引用破坏。

(2)假设const成员函数传出一个reference,后者所指的数据与对象自身有关联,而它又被存储于对象之外,那么这个函数的调用者能够改动那笔数据。

相同的道理,返回对象的引用、指针、迭代器都会造成这样的局面,它们都是“句柄”。返回一个代表对象内部数据的句柄,会减少对象的封装。

(二)解决的方法:

仅仅要对这两个函数的返回类型加上const就可以:

class Rectangle {
public:
const Point& upperLeft() const { return pData->ulhc; }
const Point& lowerRight() const { return pData->lrhc; }
private:
std::tr1::shared_ptr<RcetData> pData;
};

有了这种改变,客户就仅仅能读取矩形的Points,可是不能涂写它们。

(三)

上面那种解决方法尽管确保了内部对象不会被改动。可是却可能导致dangling handles(空悬的号码牌):这样的handles所指东西(的所属对象)不复存在。

这样的“不复存在的对象”最常见的来源就是函数返回值。

class GUIObject {...};
const Rectangle boundingBox(const GUIObject& obj); GUIObject* pgo;
const Point* pUpperLeft = &(boundingBox(*pgo).upperLeft());

你会发现(boundingBox(*pgo).upperLeft())这是一个point对象。可是当这一句运行完后,这个暂时对象temp会被析构。这时,pUpperLeft会指向一个空的对象。也就出现了悬空现象。

因此,这就是为什么函数假设“返回一个handle代表对象内部成分“总是危急的原因。

请记住:

(1)避免返回handles指向对象的内部。遵守这个条款可添加封装性,帮助const成员函数更加像一个const,并将“虚号码牌“的可能性减少到最低。

Effective C++:条款28:避免返回 handles 指向对象内部成员的更多相关文章

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

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

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

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

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

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

  4. effective c++:dynamic_cast,避免返回handles指向对象内部

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

  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++ 条款28

    避免返回handles指向对象内部成分 本节作者讲述的知识核心是对于一个类来说,应该避免类返回自己内部的私有数据. 例如以下: class Point{ public: Point(int x, in ...

随机推荐

  1. ANT编译Android Eclipse工程

    将Android SDK的tools/和platform-tools/目录包含在可执行文件的搜索路径中.Windows下,将其添加到PATH环境变量中 切换到Android Eclipse项目目录下, ...

  2. /etc/security/limits.conf 设置

    jrhdpt01:/root# cat /etc/security/limits.conf  * soft nofile 65535  * hard nofile 65535  * soft npro ...

  3. NET Core RC2 and .NET Core SDK Preview

    NET Core RC2 and .NET Core SDK Preview 先看一下 .NET Core(包含 ASP.NET Core)的路线图: Beta6: 2015年7月27日 Beta7: ...

  4. AS3开发必须掌握的内容

    1.事件机制 2.显示列表 3.垃圾回收 4.常用方法 5.网络通信 6.位图动画 7.渲染机制 8.API结构 9.沙箱机制 10.资源管理 11.内存管理 12.性能优化 13.资源选择 14.安 ...

  5. FFT算法的物理意义

    FFT是离散傅立叶变换的高速算法,能够将一个信号变换到频域.有些信号在时域上是非常难看出什么特征的,可是如果变换到频域之后,就非常easy看出特征了.这就是非常多信号分析採用FFT变换的原因.另外,F ...

  6. Apache htaccess 重写假设文件存在!

    假设文件 data/cache/index.html 存在.那么才重写. 否则使用默认的MVC 重写.by default.fu@foxmail.com RewriteEngine on Rewrit ...

  7. docker 创建本地镜像服务器

    1.docker pull registry //下载registry 镜像,registry 为docker 官方提供的一个镜像, 我们可以用它来创建本地的docker私有仓库. docker:/r ...

  8. poj 2409+2154+2888(Burnside定理)

    三道burnside入门题: Burnside定理主要理解置换群置换后每种不动点的个数,然后n种不动点的染色数总和/n为answer. 对于旋转,旋转i个时不动点为gcd(n,i). 传送门:poj ...

  9. dtach-linux-分离功能-小工具 - 点点滴滴 Linux | 点点滴滴 Linux

    dtach-linux-分离功能-小工具 - 点点滴滴 Linux | 点点滴滴 Linux dtach-linux-分离功能-小工具 2013年05月20日 ⁄ Linux工具 ⁄ 共 1775字 ...

  10. Swift供选链接

    函数是运行特定任务的代码自包括块. 给定一个函数名称标识, 当运行其任务时就能够用这个标识来进行"调用". Swift的统一的功能语法足够灵活来表达不论什么东西,不管是甚至没有參数 ...