考慮以下情況,其中一個基類規定,可以在派生類中重新實現的功能:平滑過渡
template<typename Impl>
class Base {
public:
void f(double& value, double param)
{ value = 0.0; }
};
class Implementation : public Base<Implementation> {
public:
void f(double& value, double param)
{ value = param; }
};
int main()
{
Implementation imp;
double value = 0.0;
imp.f(value, 1.0);
}
假設我想改變功能f
在簽名基類到double f(double param)
並將其用於Base
和派生類。我想在不立即破壞所有實現類的情況下執行此更改。相反,實現類的提供者應該得到棄用警告。我想出了以下情況:
template<typename Impl>
class Base {
public:
double f(double param) __attribute__ ((deprecated))
{
double v = 0.0;
static_cast<Impl*>(this)->f(v, param);
return v;
}
void f(double& value, double param)
{ value = 0.0; }
};
// class Implementation as before
int main()
{
Implementation imp;
double value = imp.f(1.0);
}
其結果是,在Base
版本的f
只應如果f
不Implementation
與新的簽名重新實現,得到所需的棄用警告調用。
很顯然,這並不能編譯,因爲在Implementation
陰影的f
定義f
在Base
:
error: no matching function for call to ‘Implementation::f(double)’
double value = imp.f(1.0);
一個解決辦法是增加using
:
class Implementation : public Base<Implementation> {
public:
using Base<Implementation>::f;
void f(double& value, double param)
{ value = param; }
};
這將迫使提供者Implementation
立即改變他的代碼,這正是應該首先避免的。另一種可能性是在新簽名中更改名稱f
。我也想避免這個,因爲f
在我的真實使用案例中有一個非常好的名字。
所以我的問題是:我可以進行簽名更改
- 使得
Implementation
提供商獲得棄用警告,但他們的代碼不會立即斷裂,即,在不改變Implementation
,並 - 而不必重命名
f
?
只是一個問題,與問題無關:爲什麼接口中的方法不是標記爲「虛擬」?如果方法不能被覆蓋,接口的用途是什麼?或者,更好的是,它爲什麼會拋出一個異常,而不是被標記爲純虛擬的(這是用C++編寫接口的首選方式)。 –
「使用」解決方案有什麼問題? –
這是具有更復雜的類相互依賴性的真實案例的簡化版本。通過使用CRTP,靜態綁定優於動態綁定。我儘可能地把它煮沸,同時保持本質。 –