簡體   English   中英

覆蓋指向成員函數的指針

[英]Override pointer-to-member-function

我有這兩個類:

class A {
public:
    A() { m_ptr = NULL; }
    void (*m_ptr)();
    void a() { if (m_ptr) m_ptr(); }
};

class B : public A {
public:
    B() { m_ptr = b; }
    void b() {
        std::cout << "B::b() is called" << std::endl;
    }
};

我想像這樣使用它們:

B b;
b.a();

並獲得以下稱為B::b()

當然,這不是編譯為B::b不是void(*)()

我怎樣才能使它工作?

UPDATE。 誰問“為什么?” 和“為什么?”。
A類是一個非常基礎的類,在生產代碼中有許多后繼者。 B級是第6個繼任者,我想擴展A(最方便的地方)再召集一個方法(來自B),這個方法可以存在,也可能不在A和B的另一個后繼者中。
可以使用具有空體的虛擬方法,但它很難看,我想避免它。 抽象方法更是如此(因為現有的派生后繼代碼)。
我不想使用void(*)()類型的外部函數來放松對所有層次結構的內部數據的訪問。

您現在無法定義類,因此無法使其正常工作。

調用另一個類的非靜態成員函數需要該類的實例。 您需要在存儲函數指針時存儲對擁有成員函數的對象的引用,或者在調用A::a時傳遞對該對象的引用。

您還需要使用void (B::*)()類型聲明m_ptr ,它是指向B成員的指針,該函數不帶參數並返回void

看看這個例子:

class A {
public:
    A() { m_ptr = nullptr; }
    void a(B& b) { if (m_ptr) (b.*m_ptr)(); } // Now takes reference to B object.
    void (B::*m_ptr)();                       // Pointer to member function of B.
};

class B : public A {
public:
    B() { m_ptr = &B::b; } // Adress of qualified function.
    void b() {
        std::cout << "B::b() is called" << std::endl;
    }
};

現在我們可以這樣調用B::b

B b;
b.a(b); // Pass reference to b when calling.

以這種方式使用繼承是令人困惑的,因為它意味着您要解決的真正問題是通過基類調用派生類的成員。 這通常使用這樣的簡單虛函數來完成:

class A {
public:
    virtual ~A() {}
    void a() const { b(); } // Call b.
private:
    virtual void b() const {}
};

class B : public A {
public:
    virtual void b() const override { // C++11 override specifier (optional).
        std::cout << "B::b() is called" << std::endl;
    }
};

像這樣使用:

B b;
b.a(); // B::b is called.

好吧,可能不是本練習的目的,但如果你想讓它工作,你可以簡單地聲明static void b()

另一個選擇是聲明friend void b() ,但是然后"B::b() is called" printout會說明錯誤的事實。

我建議使用CRTP,因為你想避免虛擬機制。 但請注意,您的代碼可能需要進行一些設計更改才能適應此模式。 但它確實提供了類型安全性並且沒有運行時開銷。 希望能幫助到你。

ideone.com上的代碼

#include <iostream>
#include <type_traits>

namespace so {

class B;

template<typename T>
class A {
 public:
  template<typename U = T, typename = typename std::enable_if<std::is_same<U, B>::value>::type>
  void foo_A() {
   std::cout << "foo_A : ";
   static_cast<U *>(this)->foo_B();
  }
};

class B: public A<B> {
 public:
  void foo_B() {
   std::cout << "foo_B" << std::endl;
  }
};

class C: public A<C> {
 public:
  void foo_C() {
   std::cout << "foo_C" << std::endl;
  }
};
} // namespace so

int main() {
 so::B b_;
 so::C c_;

 b_.foo_A();
 b_.foo_B();

 //c_.foo_A(); Compile error: A<C>::foo_A() does not exist!
 c_.foo_C();

 return (0);
}

節目輸出:

foo_A : foo_B
foo_B
foo_C

暫無
暫無

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

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