簡體   English   中英

基類可以知道派生類是否重寫了虛擬方法嗎?

[英]Can a base class know if a derived class has overridden a virtual method?

對於C#存在相同的問題,但不適用於C ++。

class Base
{
    void dispatch()
    {
        if (newStyleHasBeenOverridden())   //how to find this out?
            newStyle(42);
        else
            oldStyle(1, 2);
    }

    virtual void oldStyle(int, int) { throw "Implement me!"; }
    virtual void newStyle(int) { throw "Implement me!"; }
}

class Derived:public Base
{
    void newStyle(int) override
    {
        std::cout<<"Success!";
    }
}

警告 :此解決方案不是跨平台的,因為它依賴於GCC擴展和某些未定義的行為。

GCC允許語法通過說this->*&ClassName::functionNamethis的vtable中獲取指向函數的指針。 實際使用它可能不是一個好主意,但是無論如何這是一個演示:

#include <iostream>

class Base {
public:
    void foo() {
        auto base_bar_addr = reinterpret_cast<void*>(&Base::bar);
        auto this_bar_addr = reinterpret_cast<void*>(this->*&Base::bar);
        std::cout << (base_bar_addr == this_bar_addr ? "not overridden" : "overridden") << std::endl;
    }

    virtual void bar() { };
};

class Regular : public Base { };

class Overriding : public Base {
public:
    virtual void bar() { };
};

int main() {
    Regular r;
    r.foo();
    Overriding o;
    o.foo();
}

對於后代:

  • ICC允許使用該語法,但是它具有不同的含義,與僅說&Base::bar ,因此您始終會認為它沒有被覆蓋。
  • Clang和MSVC完全拒絕該代碼。

這是一個設計問題。

但是,為了回答實際問題,有兩種方法可以完成此任務而無需重新設計(但實際上,您應該重新設計它)。

一種(可怕的)選擇是調用newstyle方法,並捕獲未覆蓋的異常。

void dispatch() {
    try {
        newStyle(42);
    } catch (const char *) {
        oldStyle(1, 2);
    }
}

如果newStyle已被覆蓋,則將調用覆蓋。 否則,將拋出基本實現,該調度將捕獲,然后回退到oldStyle。 這是對異常的濫用,並且性能會很差。

另一種(稍差一些)的方法是將newStyle的基本實現轉發到oldStyle。

void dispatch() {
    newStyle(42);
}

virtual void newStyle(int) { oldStyle(1, 2); }
virtual void oldStyle(int, int) { throw "implement me"; }

這至少朝着更好的設計方向發展。 繼承的重點是允許高級代碼能夠互換使用對象,而不管其專業性如何。 如果調度員必須檢查實際的對象類型,則您違反了《里斯科夫替代原理》。 調度應該能夠以相同的方式處理所有對象,並且行為上的任何差異都應由重寫的方法本身引起(而不是存在重寫)。

使事情變得更簡單的是, Derived決策由Derived類完成。
抽象Base類基本上只是一個“接口”, Derived在其中實現所有 virtual函數。

這個問題聽起來也像是XY問題。

我以為這就是你想要的:

class Base // abstract class
{
   virtual void oldStyle(int, int) = 0; // pure virtual functions
   virtual void newStyle(int) = 0;      // needs to be implemented
};

class Derived:public Base
{
   public:
      Derived(bool useNewStyle): _useNewStyle(useNewStyle) {}
      void newStyle(int) { std::cout << "new style"; }
      void oldStyle(int, int) { std::cout << "old style"; }
      void dispatch()
      {
         if (_useNewStyle) {
            newStyle(42);
            return;
         }
         oldStyle(1, 2);
         return;
      }

   private:
      bool _useNewStyle = false;
};

Derived d(true); // use new style
d.dispatch();    // "new style"

暫無
暫無

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

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