(一)

有时候为了让一个对象尽量小,能够把数据放在另外一个辅助的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. smartforms初始化

    smartforms  第一次打开的页面是和prd环境下的一样,需要跑一个程序才能编辑

  2. python处理中文字符

    1.在py文件中使用中文字符 unicode.py文件内容如下所示: # -*- coding:utf-8 -*- str_ch = '我们women' uni_ch = u'我们women' pri ...

  3. SAP ABAP exporting list to memory ...SUBMIT 程序传输屏幕参数

    SUBMIT report EXPORTING LIST TO MEMORY              AND RETURN. submit 关键字的作用就是在程序内部调用一个程序,and retur ...

  4. clearcase 中一些概念和操作

    clearcase 中一些概念和操作 视图 常用命令 ClearCase 安装和使用的一些FAQ 参考 ClearCase具体的说是做配置管理的工具,只是SCM管理工具其中的一种.是RATIONAL公 ...

  5. 为HttpStatusCodeResult加入customErrors

    asp.net mvc的action返回值为HttpStatusCodeResult时的customErrors总是不起作用 (404和exception时的500,因为他们并不是HttpStatus ...

  6. C++中的函数模板

    我们在定义函数时,可以通过定义函数模板,来简化一些功能相同而数据类型不同的函数的定义和调用过程. C++中的函数模板 对于类的声明来说,也有同样的问题.有时,有两个或多个类,其功能是相同的,仅仅是数据 ...

  7. 类型自动转换引起的误解——QString可以赋值数字1,也能直接与0比较,真是昏倒!

    看以下代码,能编译通过: void MainWindow::on_pushButton_clicked() { QString str = "test"; ) { QMessage ...

  8. [Android学习笔记]继承自ViewGroup的控件的过程学习

    ViewGroup文档 http://developer.android.com/training/index.html 继承自ViewGroup需要重写onLayout方法用来为子View设定位置信 ...

  9. C++获取文件大小常用技巧

    C++编程语言在程序开发应用中能够帮助我们轻松的完成许多功能需求.比如今天为大家介绍的C++获取文件大小的方法,就可以以多种方式轻松的实现.现在将会实现方法呈现给大家,以便大家参考. C++获取文件大 ...

  10. Android消息循环分析

    我们的经常使用的系统中,程序的工作一般是有事件驱动和消息驱动两种方式,在Android系统中,Java应用程序是靠消息驱动来工作的. 消息驱动的原理就是: 1. 有一个消息队列.能够往这个队列中投递消 ...