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

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

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。

全栈程序员社区此处内容已经被作者隐藏,请输入验证码查看内容
验证码:
请关注本站微信公众号,回复“验证码”,获取验证码。在微信里搜索“全栈程序员社区”或者“www_javaforall_cn”或者微信扫描右侧二维码都可以关注本站微信公众号。

(一)

有时候为了让一个对象尽量小,能够把数据放在另外一个辅助的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,并将“虚号码牌“的可能性减少到最低。




版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/117932.html原文链接:https://javaforall.net

(0)
上一篇 2021年12月16日 下午2:00
下一篇 2021年12月16日 下午2:00


相关推荐

  • pip安装详解

    pip安装详解pip 是 python 的包管理工具 python2 7 python3 4 以上的版本都已经集成了该工具 我们可以用 pipversion 命令确认是否安装 如果未安装 pip 的 请往下看 下载进入 https pypi org project pip 选择红框中的文件下载图 windows 下安装下载完成后解压得到我们用 CMD 进入该目录下 输入 pythonsetup pyinstall 命令进行安装码字不易废话两句 有需要 python 学习资料的或者有技术问题交流 点击 即可如果是第

    2025年6月12日
    6
  • 一张图看懂字节跳动8年创业史,太励志了吧

    点击上方“全栈程序员社区”,星标公众号 重磅干货,第一时间送达 转载自| BAT(id:batfun) 字节跳动可以说是这两年 最受关注的互联网公司之一 2020年3月12日 字节…

    2021年6月27日
    374
  • 免费PHP主机_php做一个网站

    免费PHP主机_php做一个网站转载–4个免费的国外php主机服务这几个主机都是没有广告的,并且提供了很多先进的功能,如FTP访问,支持PHP和MySQL,自定义域和免费子域名等,最主要的是支持PHP,那就可以做博客主机只用了,新手们怕买了主机不会玩的话,可以先用他们来建个网站来练练。1.000WebHost000WebHost提供了一个最可靠的和功能丰富的主机托管服务,没有广告。所有的帐户都有1500M的磁盘空间,100…

    2026年2月7日
    6
  • getproperty方法_setter什么意思

    getproperty方法_setter什么意思PropertyDescriptor获取属性的getter/setter方法

    2022年10月1日
    5
  • 360无线路由器dns服务器,路由器的首选dns服务器怎么填

    360无线路由器dns服务器,路由器的首选dns服务器怎么填满意答案mirk60422020.04.25采纳率:42%等级:7已帮助:159人1、在管理员界面中输入命令:ipconfig/all然后按enter键确认即可显示windowsip配置,在这里我们可以查看我们的dns服务器地址。2、如果你连接了路由的话也可以通过路由来查看你的dns服务器地址,在浏览器输入地址192.168.1.1弹出路由器登入对话框,通常路由器默认的账户密码均为:ad…

    2022年6月10日
    57
  • Docker可视化管理工具shipyard

    Docker可视化管理工具shipyard目录 1 前言 2 shipyard 介绍 3 shipyard 安装 1 镜像下载 2 脚本安装 shipyard1 前言 nbsp nbsp nbsp nbsp 谈及 docker 避免不了需要熟练的记住好多命令及其用法 对于熟悉 shell 技术开发人员而言 还是可以接受的 熟练之后 命令行毕竟是很方便的 便于操作及脚本化 但对于命令行过敏 非技术人员 进行 docker 部署 管理是比较头疼的 学习成本是很

    2026年3月19日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号