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

2024-03-28 11:18

本文主要是介绍条款28:避免返回handles指向对象内部成分,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

首先说明,在第三版中,这一条款有两处明显的错误:

第一是在124页下面:这立刻带给我们两个教训:第一,成员变量的封装性最多只等于“返回其引用”的函数的访问级别。本例中虽然ulhc和urhc都被声明为private。

这里明显是错了:c++primer里说过,如果类以struct开头,里面的默认标号就是public;而且,如果不是public,pData->ulhc是不能实现的。这里改为:虽然 ulhc 和 lrhc 被它们的 Rectangle 认为是 private(私有)的

第二是125页下面:这意味着当初声明upperLeft和upperLeft为const不再是个谎言。

这里应该是upperLeft和lowerRight,不过不影响阅读。


言归正传,先看一个例子:

//点类
class Point
{
public:Point(int xVal, int yVal):x(xVal),y(yVal){}~Point(){}void setX(int newX){ x = newX;}//返回X坐标,以后测试用int getX()const{return x;}void setY(int newY){ y = newY;}
private:int x;int y;
};//矩形数据结构
struct RectData
{RectData(const Point& p1, const Point& p2):ulhc(p1),lrhc(p2){}Point ulhc;//坐上Point lrhc;//右下
};//矩形类
class Rectangle
{
public:Rectangle(RectData data):pData(new RectData(data)){}const Point& upperLeft()const{return pData->ulhc;}const Point& lowerRight()const{return pData->lrhc;}
//private:std::tr1::shared_ptr<RectData> pData;
};
虽然我们声明upperLeft()和lowerRight()都是const函数,但是我们可以通过它来修改矩形的点:
int main()
{Point coord1(0,0);Point coord2(100,100);RectData data(coord1,coord1);const Rectangle rec(data);rec.upperLeft().setX(50);return 0;
}

通过这个例子可以看出:

1.变量的封装性最多等于“返回其引用”的函数的访问级别:这里upperLeft函数是返回的都是Point类型的引用,所以即使矩形的数据pData被声明为private,但是还是可以访问里面的内容。

2.如果函数成员返回一个指向数据的引用,那么且这个数据被储存在对象之外,那么即使这个函数被声明为const,我们也可以通过这个函数修改它。在这里,Rectangle类的数据成员只是一个指向RectData的智能指针,而指针实际指向的数据,却是在RectData中储存的。upperLeft虽然声明为const,但这只意味着他不修改指针(的指向),至于指针指向的内容,当然是可以修改的了。

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

在这个例子中,只要对它们的返回类型加上const就可以了:

	const Point& upperLeft()const{return pData->ulhc;}const Point& lowerRight()const{return pData->lrhc;}

即使这样,由于upperLeft()函数返回了代表对象内部的句柄,它也会产生其他方面的问题,比如:悬空句柄——这个句柄所指的东西并不存在。举一个例子:

//一个GUI对象
class GUIObject
{
public:GUIObject(Rectangle r){}//返回一个指定大小的矩形框const Rectangle getRec()const {Point coord1(50,50);Point coord2(200,200);RectData data(coord1,coord2);const Rectangle rec(data);return rec;}};//返回obj的外框
const Rectangle boundingBox(const GUIObject& obj)
{return obj.getRec();
}

下面测试:

	Point coord1(10,10);Point coord2(100,100);RectData data(coord1,coord2);const Rectangle rec(data);GUIObject obj(rec);	//一个GUI对象指针GUIObject* pgo = &obj;//获取它的左上角点const Point* pUpperLeft = &(boundingBox(*pgo).upperLeft());cout<<pUpperLeft->getX();return 0;

boundingBox返回一个新的Rectangle对象。然后调用upperLeft函数返回它的左上角。但是,当这条语句结束以后,boundingBox的返回值就会被销毁了,导致它的Points被析构,所以pUpperLeft 就成了一个悬空句柄(不代表任何实际存在的对象)。由此可见,返回一个指向对象内部成分的句柄,是一项危险的事情,因为对象可能在任何时候被析构,此后,这个句柄就成了悬空句柄了。


总而言之,避免返回指向对象内部的句柄。首先,这样会提高类的封装性;其次,这样可以避免悬空句柄的出现。

这篇关于条款28:避免返回handles指向对象内部成分的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/855460

相关文章

Java中的内部类和常用类用法解读

《Java中的内部类和常用类用法解读》:本文主要介绍Java中的内部类和常用类用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录内部类和常用类内部类成员内部类静态内部类局部内部类匿名内部类常用类Object类包装类String类StringBuffer和Stri

C++类和对象之初始化列表的使用方式

《C++类和对象之初始化列表的使用方式》:本文主要介绍C++类和对象之初始化列表的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C++初始化列表详解:性能优化与正确实践什么是初始化列表?初始化列表的三大核心作用1. 性能优化:避免不必要的赋值操作2. 强

Java对象转换的实现方式汇总

《Java对象转换的实现方式汇总》:本文主要介绍Java对象转换的多种实现方式,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录Java对象转换的多种实现方式1. 手动映射(Manual Mapping)2. Builder模式3. 工具类辅助映

Vue3组件中getCurrentInstance()获取App实例,但是返回null的解决方案

《Vue3组件中getCurrentInstance()获取App实例,但是返回null的解决方案》:本文主要介绍Vue3组件中getCurrentInstance()获取App实例,但是返回nu... 目录vue3组件中getCurrentInstajavascriptnce()获取App实例,但是返回n

Python中判断对象是否为空的方法

《Python中判断对象是否为空的方法》在Python开发中,判断对象是否为“空”是高频操作,但看似简单的需求却暗藏玄机,从None到空容器,从零值到自定义对象的“假值”状态,不同场景下的“空”需要精... 目录一、python中的“空”值体系二、精准判定方法对比三、常见误区解析四、进阶处理技巧五、性能优化

前端下载文件时如何后端返回的文件流一些常见方法

《前端下载文件时如何后端返回的文件流一些常见方法》:本文主要介绍前端下载文件时如何后端返回的文件流一些常见方法,包括使用Blob和URL.createObjectURL创建下载链接,以及处理带有C... 目录1. 使用 Blob 和 URL.createObjectURL 创建下载链接例子:使用 Blob

Python获取C++中返回的char*字段的两种思路

《Python获取C++中返回的char*字段的两种思路》有时候需要获取C++函数中返回来的不定长的char*字符串,本文小编为大家找到了两种解决问题的思路,感兴趣的小伙伴可以跟随小编一起学习一下... 有时候需要获取C++函数中返回来的不定长的char*字符串,目前我找到两种解决问题的思路,具体实现如下:

Java Optional避免空指针异常的实现

《JavaOptional避免空指针异常的实现》空指针异常一直是困扰开发者的常见问题之一,本文主要介绍了JavaOptional避免空指针异常的实现,帮助开发者编写更健壮、可读性更高的代码,减少因... 目录一、Optional 概述二、Optional 的创建三、Optional 的常用方法四、Optio

使用Sentinel自定义返回和实现区分来源方式

《使用Sentinel自定义返回和实现区分来源方式》:本文主要介绍使用Sentinel自定义返回和实现区分来源方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Sentinel自定义返回和实现区分来源1. 自定义错误返回2. 实现区分来源总结Sentinel自定

在java中如何将inputStream对象转换为File对象(不生成本地文件)

《在java中如何将inputStream对象转换为File对象(不生成本地文件)》:本文主要介绍在java中如何将inputStream对象转换为File对象(不生成本地文件),具有很好的参考价... 目录需求说明问题解决总结需求说明在后端中通过POI生成Excel文件流,将输出流(outputStre