我有一個基類:
class Base{
protected:
Storage* _storage;
virtual void createStorage(){
delete storage;
_storage = new Storage();
}
void exampleUseOfBaseStorage(){
_storage->baseData ; //some complex calculation
}
}
struct Storage{
int baseData;
}
每個派生類都有自己的存盤型別:
struct DerivedStorage : Storage{
int derivedData;
}
在派生類中,
class Derived{
protected:
virtual void createStorage() override{
delete storage;
_storage = new DerivedStorage();
}
}
因此 _storage 可用于所有基類成員和派生類成員。缺點是,因為對于每個派生類,我都必須將存盤型別轉換為 DerivedStorage,或者派生類使用的任何型別的存盤,每次都輸入轉換陳述句非常繁瑣。有沒有一種優雅的方法?
我的解決方案是再增加一個 DerivedStorage 型別的變數,然后在派生類的成員函式中使用它。例如:
class Derived{
protected:
DerivedStorage* _ds = nullptr;
virtual void createStorage() override{
delete storage;
_storage = new DerivedStorage();
_ds = _storage; // Use _ds in all member functions of Derived instead of _storage
}
void exampleUseOfDerivedStorage(){
_ds->derivedData ; //some complex calculation
}
}
是否有更優雅的模式可用于此用例?
uj5u.com熱心網友回復:
我會將強制轉換放入成員函式中,而不是使用資料成員。成員函式在每個派生類中可以具有相同的名稱。如果你真的不想在每個派生類中鍵入函式定義,你可以使用 CRTP 來實作它。
使用資料成員使得對特殊成員函式安全地使用零規則方法是不可能的,并且您必須在每個派生類中顯式地實作所有這些方法。
我假設顯示的代碼只是縮寫,但基類有同樣的問題。如果它使用std::unique_ptr<Storage>而不是原始指標,它可以簡單地遵循零規則,而不必費心實作任何特殊成員函式,但正如問題中所寫,特殊成員函式需要明確定義以避免復制/移動類時導致UB。(并且還會std::unique_ptr使createStorage例外安全,但目前還不是。)
uj5u.com熱心網友回復:
我認為問題應該是“你真的需要派生存盤嗎?”。大多數時候組合/聚合應該足夠了。
即使您需要從派生存盤和基礎存盤中計算資料,您仍然可以在派生類中訪問它們
合成示例
現場演示
#include<string>
#include<iostream>
#include<vector>
#include<algorithm>
struct Storage{
int baseData{};
};
struct DerivedStorage{
int derivedData{};
};
class Base{
public:
Storage _storage;
void exampleUseOfBaseStorage(){
_storage.baseData ; //some complex calculation
}
};
class Derived: Base{
public:
DerivedStorage _ds;
void exampleUseOfDerivedStorage(){
_ds.derivedData ; //some complex calculation
std::cout << "baseData: " << _storage.baseData << std::endl;
std::cout << "derivedData: " << _ds.derivedData << std::endl;
}
};
int main(){
Derived d;
d.exampleUseOfDerivedStorage();
return 0;
}
CRTP 示例
這是詳細說明user17732522關于 CRTP 使用的答案的示例。
現場演示
我將所有成員更改為公開,因為該示例沒有詳細說明何時呼叫createStorage()
#include<string>
#include<iostream>
#include<vector>
#include<algorithm>
struct Storage{
int baseData{};
};
struct DerivedStorage : Storage{
int derivedData{};
};
template<typename DS>
class Base{
public:
Storage* _storage;
virtual void createStorage(){
delete _storage;
_storage = new Storage();
}
DS* getStorage(){
return static_cast<DS*>(_storage);
}
void exampleUseOfBaseStorage(){
_storage->baseData ; //some complex calculation
}
};
class Derived: Base<DerivedStorage>{
public:
virtual void createStorage() override{
delete _storage;
_storage = new DerivedStorage();
}
void exampleUseOfDerivedStorage(){
getStorage()->derivedData ; //some complex calculation
std::cout << "derivedData: " << getStorage()->derivedData << std::endl;
}
};
int main(){
Derived d;
d.createStorage();
d.exampleUseOfDerivedStorage();
return 0;
}
uj5u.com熱心網友回復:
由于該方法Base::exampleUseOfBaseStorage受到保護,因此該方法的呼叫者僅限于派生類(和 Base)。
因此,如果每個派生類都將每個存盤作為自己的成員,他們可以將其用作Base::exampleUseOfBaseStorage.
class Base{
protected:
//(This will be called from Drived)
void exampleUseOfBaseStorage( Storage *storage );
};
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/436699.html
