[英]Muiltple inheritance: first base class dependent on function in the second base class
我有很多不同的子類(15+),它們都在其中定義了相同的 function centerAt
。 這些子類每個都繼承了 extern 庫中的不同類:它們的共同點是它們具有setPos
所依賴的 function setPos。
我的目標是避免代碼重復,因此我想出了一個解決方案,將 centerAt 移動到一個基礎 class ,所有子 class 都可以與來自外部庫的基類一起繼承:多個 Z5FED3411FAF832174EF1F040028B2C21
我想出了這段代碼
class InternalBase {
public:
void centerAt(int x, int y) {
// Do some math
setPos(newx, newy)
}
virtual void setPos() = 0; // Should be replaced by the setPos in ExternalBase
};
// There are 15+ different external base classes used, here only 2 are shown
class ExternalBase1 { // this is from an external library
public:
void setPos() { /* internal definition */}
};
class ExternalBase2 { // this is from an external library
public:
void setPos() { /* internal definition */}
};
class Child1 : public InternalBase, public ExternalBase1 {
public:
// A lot of different functions
};
class Child2 : public InternalBase, public ExternalBase2 {
public:
// A lot of different functions
};
int main() {
Child1 myobj;
myobj.centerAt(120, 394);
return 0;
}
不幸的是,無法構造 object:編譯器抱怨這是一個抽象的 class - 可能是因為setPos
不是從ExternalBase1
繼承的。 我該如何解決這個問題,所以Child1
從ExternalBase1
和InternalBase
繼承setPos
從而可以使用ExternalBase1
中定義的setPos
。
此問題與使用並行基礎 class 方法覆蓋純虛擬方法相同? ,但最大的問題是,因為我正在處理一個外部庫,所以無法使用給定的解決方案(使ExternalBase1
先繼承InternalBase
: class ExternalBase1: public virtual InternalBase
)。
我想避免使用模板。
使用模板是最簡單的解決方案。 模板是 C++ 的獨特功能之一,沒有理由不使用它們。
template<typename T>
class ExternalBaseMixin : public InternalBase, public T {
public:
using T::T;
void setPos(int x, int y) override
{
T::setPos(x, y);
}
};
而已。 然后,這只是一個問題:
class Child1 : public ExternalBaseMixin<ExternalBase1> {
// ...
class Child2 : public ExternalBaseMixin<ExternalBase2> {
// ...
ETC...
沒有可比的內置、非模板 C++ 功能可以完成同樣的事情。 任何非模板解決方案最終都會做與此完全相同的事情,但輸入更多,代碼更多,結果更容易出錯。 這是相當安全的,只要滿足一個要求:總是從ExternalBaseMixin
繼承。 只要發生這種情況,一切都會以正確的順序被覆蓋並組合在一起。 另外,這也保證了 inheritance 的順序: InternalBase
在外部 class 之前構建,如果這很重要的話。
您可以使用 CRTP 並使InternalBase
成為模板類型。
這會對您的代碼進行很少的更改。
template <class Derived>
class InternalBase {
public:
void centerAt(int x, int y) {
// Do some math
Derived& derived = static_cast<Derived&>(*this);
derived.setPos(x, y);
}
};
class ExternalBase1 {
public:
void setPos(int x, int y) {}
};
class Child1 : public InternalBase<Child1>, public ExternalBase1 {
};
int main() {
Child1 myobj;
myobj.centerAt(120, 394);
return 0;
}
在這里查看它的工作原理: https://godbolt.org/z/Tsej4Gcfd
快速解決您的問題的方法是在每個孩子上明確定義要使用的 setPos() function。 (我調整了一些定義不明確的代碼,我猜這是一個例子,但是 setPos 和提供的虛擬定義在簽名中不匹配):
#include <iostream>
class InternalBase {
public:
void centerAt(int x, int y) {
// Do some math
setPos(x, y);
}
virtual void setPos(int x, int y) = 0;
};
class ExternalBase1 {
public:
void setPos(int x, int y) { std::cout << "Inside ExternalBase1::setPos" << std::endl; }
};
class Child1 : public InternalBase, public ExternalBase1 {
public:
void setPos(int x, int y) { ExternalBase1::setPos(x, y); }
// A lot of different functions
};
int main() {
Child1 myobj;
myobj.centerAt(120, 394);
return 0;
}
盡管我建議,如果您有時間,嘗試從不同的方法解決構建代碼的問題(模板在這里是理想的,正如已經有人回答的那樣)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.