首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ 箴言:避免回傳物件內部構件的控制代碼

     編輯:關於C++

封裝是物件導向基石,但回傳內部構件的控制代碼(引用、指標、迭代器)會悄無聲息地摧毀封裝與 const 語義,並引發懸空控制代碼風險。

經典反例:Rectangle 類別

class Point { public: void setX(int); void setY(int); /*...*/ };
struct RectData { Point ulhc; Point lrhc; };
class Rectangle {
    shared_ptr pData;
public:
    Point& upperLeft() const { return pData->ulhc; }   // 錯誤!
    Point& lowerRight() const { return pData->lrhc; }  // 錯誤!
};

雙重破壞

  1. 封裝潰逃:private 資料透過 public 函數回傳非 const 引用實際公開
  2. const 語義失效:const Rectangle 物件仍可被修改
    const Rectangle rec(Point(0,0), Point(100,100));
    rec.upperLeft().setX(50);  // 編譯通過!邏輯上修改了 const 物件

修正:回傳 const 引用

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

允許讀取、禁止寫入。封裝放寬為受控的唯讀存取。

更深層風險:懸空控制代碼

即使回傳 const 引用,仍面臨生命週期陷阱:

const Rectangle boundingBox(const GUIObject& obj);  // 回傳暫時物件

GUIObject* pgo = ...;
const Point* pUpperLeft = &boundingBox(*pgo).upperLeft();  // 危險!
// boundingBox() 回傳暫時物件 temp
// upperLeft() 回傳 temp 內部 Point 引用
// 陳述式結束時 temp 銷毀,pUpperLeft 變懸空指標

根本原因:控制代碼存活期超過其綁定的物件。與 const、控制代碼型別無關。

標準庫例外:容器的 operator[]

vector::operator[] 回傳元素引用,生命週期綁定容器本身。此屬特例而非慣例——容器與元素同生共死,設計上刻意允許。

實戰準則

  • 預設拒絕回傳內部構件控制代碼
  • 需提供存取時:回傳 const 引用/指標,或傳回值副本(C++11 移動語義低成本)
  • 若必須回傳非 const 控制代碼,文件化生命週期契約,考慮 shared_ptr 共享擁有權
  • 私有/保護成員函數同理,勿回傳其控制代碼

核心箴言

避免回傳物件內部構件的控制代碼(引用、指標、迭代器)。這能強化封裝、確保 const 語義正確、最小化懸空控制代碼風險。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved