[英]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,因為你想避免虛擬機制。 但請注意,您的代碼可能需要進行一些設計更改才能適應此模式。 但它確實提供了類型安全性並且沒有運行時開銷。 希望能幫助到你。
#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.