C++物件切片探秘:派生類物件如何被‘切割’?

架构师老卢發表於2024-03-22
C++物件切片探秘:派生類物件如何被‘切割’?

概述:C++中的物件切片指透過將派生類物件賦值給基類物件,導致派生部分被“切掉”,只保留基類部分。這可能發生在值傳遞、賦值等操作中。物件切片的基礎功能示例展示了派生類物件賦值給基類物件時的現象,而高階功能示例則展示了透過基類指標實現派生類物件的訪問和多型。

物件切片(Object Slicing)是指透過將派生類物件賦值給基類物件,導致派生類物件的派生部分被“切掉”,只保留基類部分的現象。這通常發生在使用值傳遞或賦值操作時。

基礎功能:

示例原始碼:

#include <iostream>
#include <string>

class Base {
public:
    Base(int baseData) : baseData_(baseData) {}
    virtual void Print() const {
        std::cout << "基類資料:" << baseData_ << std::endl;
    }
private:
    int baseData_;
};

class Derived : public Base {
public:
    Derived(int baseData, const std::string& derivedData)
        : Base(baseData), derivedData_(derivedData) {}
    void Print() const override {
        std::cout << "基類資料:" << GetBaseData() << ", 派生類資料:" << derivedData_ << std::endl;
    }
private:
    std::string derivedData_;
};

void DisplayBaseObject(const Base& obj) {
    obj.Print();
}

int main() {
    Derived derivedObject(42, "派生資料");
    
    // 物件切片發生,只保留基類部分
    Base baseObject = derivedObject;
    DisplayBaseObject(baseObject);

    return 0;
}

在這個示例中,Derived 類公有繼承自 Base 類,當派生類物件 derivedObject 被賦值給基類物件 baseObject 時,發生了物件切片。雖然 derivedObject 包含派生類的資料成員,但只有基類部分被保留。

高階功能:

示例原始碼:

#include <iostream>
#include <memory>

class Base {
public:
    virtual void Print() const {
        std::cout << "基類資料:" << baseData_ << std::endl;
    }
protected:
    int baseData_ = 0;
};

class Derived : public Base {
public:
    void Print() const override {
        std::cout << "基類資料:" << baseData_ << ", 派生類資料:" << derivedData_ << std::endl;
    }
private:
    std::string derivedData_ = "派生資料";
};

int main() {
    std::unique_ptr<Base> basePtr = std::make_unique<Derived>(); // 指向派生類物件的基類指標

    // 透過基類指標呼叫虛擬函式,實現多型
    basePtr->Print();

    return 0;
}

在這個示例中,透過使用智慧指標 std::unique_ptr,可以實現指向派生類物件的基類指標。透過基類指標呼叫虛擬函式 Print,實現了多型性。這也是物件切片的一種應用,透過基類指標可以訪問派生類的虛擬函式。

相關文章