Effective C++:条款28:避免返回 handles 指向对象内部成员
(一)
有时候为了让一个对象尽量小,能够把数据放在另外一个辅助的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,并将“虚号码牌“的可能性减少到最低。
最新文章
- 【Win10 应用开发】语音命令与App Service集成
- TSQL order by 子句中排序列的多种写法
- HDU 2045 不容易系列之(3)—— LELE的RPG难题 (递推)
- Struts1中ActionForward的技巧介绍
- 关于Encoding.GetEncoding(";utf-8";)和Encoding.GetEncoding(";GB2312";)及Encoding.Default
- thinkphp autoload 命名空间自定义 namespace
- C语言程序设计做题笔记之C语言基础知识(下)
- Codeforces 22B Bargaining Table
- Windows 8.1下 MySQL绿色版安装配置与使用
- 挺好用的SQLSERVER数据库自动备份工具SQLBackupAndFTP(功能全面)
- SPOJ DIVCNT2 [我也不知道是什么分类了反正是数论]
- R+tmcn笔记︱tmcn包的基本内容以及李舰老师R语言大会展示内容摘录
- Python二次编码、小数据池之心照神交
- PyCharm下使用Scrapy建立爬虫项目--MyFirstSpiderObject
- HDU 4027 Can you answer these queries【线段树】
- redis介绍以及安装
- 腾讯Ocr文字识别
- 【读书笔记】Android平台的漏洞挖掘和分析
- IECapt、CutyCapt 生成网页快照
- 【Oracle】Update方法
热门文章
- Net Core-Razor
- [LeetCode] Print All Combinations of a Number as a Sum of Candidate Numbers
- faith的23堂课:培养良好的工作方法与做事风格
- SQL server语句练习
- 我在知乎上关于Laser200/310电脑的文章。
- android.graphics.Color
- Linux下同时运行不同版本的qt程序
- 关于IOCP,某些地方就是不让人彻底舒服(WSASend重叠post数据)
- 普联的路由器TL-WR842N和TL-WR845N还有 TL-WR847N哪一个更好,我是家用
- 广东省-IT公司红黑榜排名