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

文章讨论了如何在C++中创建一个Rectangle类,通过只存储指向辅助结构体的指针来节省内存。然而,作者指出返回const修饰的对象可能导致内部值被修改,提出了使用const限制和避免返回对象内部句柄以增强封装性的解决方案。
摘要由CSDN通过智能技术生成

 创建一个矩形的类(Rectangle),为保持Rectangle对象较小,可以只在其对象中保存一个指针,用于指向辅助的结构体,定义其范围的点数据存放在辅助的结构体中:

class Point { // 表示点的类
public:
    Point(int x, int y);
    ...
    void setX(int newVal);
    void setY(int newVal);
    ...
};
struct RectData { // 矩形的点数据
    Point ulhc; // ulhc = " upper left-hand corner"
    Point lrhc; // lrhc = " lower right-hand corner"
};
class Rectangle {
    ...
    Point& upperLeft() const { return pData->ulhc; }
    Point& lowerRight() const { return pData->lrhc; }
private:
    std::shared_ptr<RectData> pData; 
}; 

Point coord1(0, 0);
Point coord2(100, 100);
const Rectangle rec(coord1, coord2); // Rec是一个const矩形,范围从
					//(0,0)到(100,100)
rec.upperLeft().setX(50); // 现在变为 (50, 0) 到 (100, 100)!

 这个设计可以编译,但它是错误的。我们设计的类返回的是一个const修饰的对象,但是我们还是可以修改内部对象的值。
我们可以为函数的返回类型添加const限制来解决这个问题:

class Rectangle {
public:
    ...
    const Point& upperLeft() const { return pData->ulhc; }
    const Point& lowerRight() const { return pData->lrhc; }
    ...
};

 即便如此,upperLeft和lowerRight仍然会返回对象内部的句柄,这在其他方面可能会造成问题。特别是,它可能导致悬空(dangling )句柄:指向不再存在的对象的句柄。

#include <iostream>
#include <string>
class Point { // 表示点的类
public:
	Point() {};
	Point(int x, int y) :_x{x},_y{y}
	{
	}
	
	void setX(int newVal) {
		_x = newVal;
	}
	void setY(int newVal) {
		_y = newVal;
	}

	std::string toString() const {
		std::string result = "(x:" + std::to_string(_x) + "," + std::to_string(_y) + ")";
		return result;
	}
private:
	int _x = 0;
	int _y = 0;
};
struct RectData { // 矩形的点数据
	Point ulhc; // ulhc = " upper left-hand corner"
	Point lrhc; // lrhc = " lower right-hand corner"
};
class Rectangle {
public:
	Rectangle(){}
	Rectangle(const Point& p1, const Point& p2) {
		RectData rectData;
		rectData.ulhc = p1;
		rectData.lrhc = p2;
		pData = std::make_shared<RectData>(rectData);
	}
	~Rectangle()
	{
		std::cout << "Rectangle析构函数执行" << std::endl;
	}
	const Point& upperLeft() const { return pData->ulhc; }
	const Point& lowerRight() const { return pData->lrhc; }
	void print() const{
		std::cout<<pData->ulhc.toString()<<std::endl;
		std::cout << pData->lrhc.toString() << std::endl;
	}
private:
	std::shared_ptr<RectData> pData;
};

Rectangle boudingBox()
{
	Point coord1(0, 0);
	Point coord2(100, 100);
	Rectangle rect(coord1, coord2);

	return rect;
}

int main()
{
	//Point coord1(0, 0);
	//Point coord2(100, 100);
	//const Rectangle rec(coord1, coord2);	
	//rec.print();
	//Point right = rec.lowerRight();
	//std::cout << "+++++++" << right.toString() << std::endl;
	rec.upperLeft().setX(50); 
	//rec.print();
	const Point *right = &(boudingBox().lowerRight());
	std::cout << "+++++++" << right->toString() << std::endl;
	return 0;
}

在这里插入图片描述
 避免返回指向对象内部的句柄(引用、指针或迭代器)。遵守这个原则将会增加了封装性,帮助const成员函数保持const行为,并可以尽量避免发生悬空句柄的创建。

  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值