首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C++ 物件切割問題:父類變數儲存子類物件導致無法存取子類成員

     編輯:程式設計綜合問答

現象重現

class Command { public: int id; int type; };
class OnCommand : public Command { public: int OnCount; };

Command cmd;           // 父類物件
cmd = OnCommand();     // 子類物件賦值給父類變數
// cmd.OnCount;         // 編譯錯誤:Command 無 OnCount 成員

根本原因:物件切割

C++ 中值語義預設行為:將子類物件賦值給父類變數時,僅複製父類部分 (id, type),子類特有的成員 (OnCount) 被「切掉」丟棄。cmd 依然是 Command 型別的完整物件,並非 OnCommand。

為何無法轉型回子類?

  • static_cast<OnCommand&>(cmd):行為未定義,cmd 內根本沒有 OnCount 的記憶體空間。
  • dynamic_cast:需多態基類 (含虛函數),且 cmd 並非指向真正 OnCommand 物件的指標/參照,轉型失敗。

正確做法:使用指標或參照實現多態


// 1. 指標 (需管理生命週期)
Command* cmdPtr = new OnCommand();
static_cast(cmdPtr)->OnCount = 10; // 安全,前提確知實際型別
delete cmdPtr;

// 2. 智慧指標 (現代 C++ 推薦)
std::unique_ptr cmdPtr = std::make_unique();
// 需下轉時:
if (auto* derived = dynamic_cast(cmdPtr.get())) {
    derived->OnCount = 10;
}

// 3. 參照 (綁定既有物件)
OnCommand realObj;
Command& ref = realObj; // 正確:參照不切割
static_cast(ref).OnCount = 20;

設計建議

  • 基類宣告虛解構子 (virtual ~Command() = default;)。
  • 盡量使用 std::unique_ptr<Base> 傳遞多態物件。
  • 若確需值語義儲存異質物件,可用 std::variant (C++17) 或型別擦除 (std::any/Boost.TypeErasure)。

結論:值語義會導致物件切割,喪失子類資訊。多態必須透過指標/參照/智慧指標實現。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved