簡體   English   中英

我需要第二個接口 class 的虛擬析構函數嗎?

[英]Do I need a virtual destructor for a second interface class?

我有名為“Base”和“Derived”的課程。

struct Base {
    Base() = default;
    virtual ~Base() = default;
    Base(const Base&) = delete;
    Base& operator=(const Base&) = delete;

    virtual void DoStuff() = 0;
};

“基地” class 需要虛擬析構函數,這是可以理解的。 我也不允許復制這個 class

struct Derived : Base {
    Derived() = default;
    ~Derived() override = default;

    void DoStuff() override { /*...*/ }
};
int main()
{
    std::shared_ptr<Base> a = std::make_shared<Derived>();
    a->DoStuff();
    return 0;
}

現在讓我們介紹其他的類,我不知道, CallableDerivedCallable

struct Callable
{
    virtual void Call() = 0;
};
struct DerivedCallable : Base, Callable
{
    DerivedCallable() = default;
    ~DerivedCallable() override = default;

    void DoStuff() override { /*...*/ }
    void Call() override { /*...*/ }
};
int main()
{
    std::shared_ptr<Base> a = std::make_shared<Derived>();
    a->DoStuff();

    {
        auto callableA = std::dynamic_pointer_cast<DerivedCallable>(a);
        if(callableA) {
            callableA->Call();
        }
    }

    std::shared_ptr<Base> b = std::make_shared<DerivedCallable>();
    b->DoStuff();
    
    {
        auto callableB = std::dynamic_pointer_cast<DerivedCallable>(b);
        if(callableB) {
            callableB->Call();
        }
    }

    return 0;
}

Derived不繼承自Callable ,因此callableA為 nullptr,因此 if 語句不會執行Call() function。

另一方面, DerivedCallable繼承自Callablestd::dynamic_pointer_cast會將 object 的引用計數增加到 2,因此當callableB離開 scope 時,object 不會被釋放,只有引用計數會減少到 1 並且然后主 function 將釋放b

Callable是否需要有一個虛擬析構函數?

如果您要通過基指針 class 刪除派生的 class object,則只需要一個虛擬析構函數。

由於您使用的是std::shared_ptr ,因此不需要任何虛擬析構函數,因為 shared_ptr 存儲了正確類型的刪除器(無論您如何轉換)。

如果您打算擁有一個DerivedCallable object 和一個Callable指針( std::unique_ptr<Callable>或其他在Callable*上調用delete的東西),那么它應該有一個虛擬析構函數。 但是,如果您只對Callable*進行非擁有引用,那么您並不嚴格需要虛擬析構函數。

在 class 已經有其他虛擬成員的情況下添加一個虛擬析構函數是非常便宜的,所以添加它就可以了,這樣你就不用擔心不小心delete -ing 錯誤了。

這取決於。 理論上, Base不需要虛擬析構函數。 當你拖着 object 時,你需要一個析構函數是虛擬的,它的動態類型與其 static 類型不同。

在你的例子中,你有一個真正指向DeriviedBase指針。如果你不使~Base()虛擬化,那么破壞 object 將表現出未定義的行為——可能是因為未能破壞 object 的Derived部分.

因此,只要您不打算通過特定基類 class 擁有指向您的 object 的(擁有的)指針。該基類的析構函數不必是虛擬的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM