簡體   English   中英

覆蓋C ++中的非虛擬繼承

[英]Overriding non-virtual inheritance in C++

我正在使用一個公開各種純虛擬接口的外部庫。 我試圖用我自己的實現包裝它們,以便擴展它們的功能。 我要解決的問題是ChildClass實際上不是從BaseClass派生的。 我寫了一個小應用程序演示了這一點:

///
/// External Library
///
class BaseClass {
  public:
    virtual ~BaseClass() { }
    virtual int Foo(void) = 0;
};

class ChildClass
    : public BaseClass {
  public:
    virtual int Bar(void) = 0;
};

///
/// Internal code
///
class BaseClassImpl
    : public virtual BaseClass {
  public:
    virtual int Foo(void) {
        return 5;
    }
};
class ChildClassImpl
    : public virtual ChildClass
    , public virtual BaseClassImpl {
  public:
    virtual int Bar(void) {
        return 12;
    }
};

int main(int, char* []) {
    ChildClass* impl = new ChildClassImpl;
    printf("%d, %d\n", impl->Foo(), impl->Bar());
    return 0;
}

編譯器給我的輸出是這樣的:

1>main.cpp(41): error C2259: 'ChildClassImpl': cannot instantiate abstract class
1>  main.cpp(41): note: due to following members:
1>  main.cpp(41): note: 'int BaseClass::Foo(void)': is abstract
1>  main.cpp(9): note: see declaration of 'BaseClass::Foo'

現在從概念上講,我理解了這個問題。 編譯器看到ChildClassImpl從兩個不同的父級繼承自BaseClass的“鑽石問題”。 我可以使用兩種解決方案:

  1. 使ChildClass實際上從BaseClass派生( class ChildClass : public virtual BaseClass )。 這消除了編譯器錯誤並將其變成警告(main.cpp(38): warning C4250: 'ChildClassImpl': inherits 'BaseClassImpl::BaseClassImpl::Foo' via dominance)
  2. ChildClassImpl實現我自己的Foo()版本,並停止從BaseClassImpl派生。

我確實嘗試修改外部庫以添加virtual關鍵字,並且效果很好。 不幸的是,這個庫確實是不可修改的,因此這不是一個選擇。 選項2可以正常工作(這是我現在正在做的事情),但是最終卻出現了一些重復的代碼。 我不需要重新實現已經被覆蓋的功能。

我知道虛擬繼承告訴編譯器確保在繼承樹中只有一個BaseClass副本,這就是它起作用的原因。 但是,在這種情況下,我不知道這是否真的是一個限制。 外部類是純虛擬的,應僅具有一個vtable,並且每個函數只有一個版本。 傳統的菱形問題(編譯器選擇Child1::Foo還是Child1::Foo嗎?)在這里實際上並不存在,因為沒有重復的函數。

我知道在這種情況下正確的答案是“您做錯了”,但是我無法控制外部庫,我需要像使用原始Impl使用Impl 無論如何,有沒有要重寫編譯器以使其看到Foo在我的父級中已經被重寫?

無論如何,有沒有要重寫編譯器以使其看到Foo在我的父級中已經被重寫?

使用類層次結構,該語句在繼承層次結構的一個分支中不成立。

我懷疑您知道如何解決編譯器錯誤。 以防萬一你不...

virtual int Foo(void) {
    return BaseClassImpl::Foo();
}

int ChildClassImpl解決您的編譯器問題。

類名通常代表抽象。 諸如BaseChild類的通用名稱無法提供您正在處理的抽象的線索。 如果不了解那些抽象是什么,對我來說很難提出一個有意義的類層次結構。

添加到您的ChildClassImpl

virtual int foo(void) {
    return BaseClassImpl::foo();
}

這會將對ChildClass的foo(或其BaseClass的副本)的所有調用重定向到BaseClassImpl的。

暫無
暫無

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

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