2012-10-22 35 views
3

當我必須在不修改它的情況下擴展類的行爲時,我經常使用設計模式visitor。它增加了類成員函數,而不修改它所處理類的核心。設計模式,將數據添加到類(第三方)而不修改它

或多或少地以同樣的方式,我需要擴展第三方類,但主要是數據,而不是行爲。

在這種情況下,我經常使用匹配密鑰MyClass*且值爲MyClassExtender的std :: map。 MyClassExtender包含所有附加信息。

雖然這樣做,但我碰巧想知道是否還有其他方法可以做到這一點,也許更常見或更「最佳做法」,我應該將這個添加劑類稱爲擴展器嗎? 是否有這種模式的名稱...

的Nota Bene的:我可以簡單地聚集在myClass *和MyClassExtender在一個新的類,但我需要訪問MyClassExtender給予MyClass的*真常,所以ST ::地圖真的是方便易

回答

3

爲什麼你不只是子類?繼承是擴展類的方式,無論是行爲還是狀態。除非您只想將類的實例與其他數據關聯起來,在這種情況下,它根本不會擴展,而std :: map是正確的答案。

+2

*繼承是擴展類的方式,不管是行爲還是狀態。* => **否!! **繼承被過度使用*因爲它看起來很方便,但大多數時候**組合**應該被使用代替。在這種特殊情況下,這可能是一個解決方案,但是你的理由是錯誤的:繼承的決定從來都不是微不足道的。 –

+0

@Matthieu m。我希望比我想象的更多一些:-)「優先於繼承聚合」。 –

1

所以 - 用你的擴展對象在結構中創建你的MyClass對象:

struct MyClassEx { 
    MyClassExtension extension; 
    MyClass object; 
}; 

,使之成爲不同類型的更好的穩健性 - 使用模板從例如:http://ideone.com/mmfK83

解決方案下面由std::shared_ptr/std::make_shared啓發:

template <typename Type> 
struct LinkExtension; 

template <typename Type> 
struct TypeEx { 
    using Extension = typename LinkExtension<Type>::Type; 

    alignas(Type) uint8_t objectData[sizeof(Type)]; 
    alignas(Extension) uint8_t extensionData[sizeof(Extension)]; 

    Type* getObject() { return reinterpret_cast<Type*>(objectData); } 
    const Type* getObject() const { return reinterpret_cast<const Type*>(objectData); } 
    Extension* getExtension() { return reinterpret_cast<Extension*>(extensionData); } 
    const Extension* getExtension() const { return reinterpret_cast<const Extension*>(extensionData); } 

    template <class... Args> 
    TypeEx(Args&&... args) 
    { 
     new (objectData) Type(std::forward<Args>(args)...); 
     new (extensionData) Extension(); 
    } 
    ~TypeEx() 
    { 
     getObject()->~Type(); 
     getExtension()->~Extension(); 
    } 
    TypeEx(const TypeEx&) = delete; 
    TypeEx& operator = (const TypeEx&) = delete; 
}; 

和一些輔助功能:

template <typename Type, class... Args> 
Type* createObjectEx(Args&&... args) 
{ 
    TypeEx<Type>* retVal = new TypeEx<Type>(std::forward<Args>(args)...); 
    return retVal->getObject(); 
} 

template <typename Type> 
typename LinkExtension<Type>::Type& getObjectEx(Type* obj) 
{ 
    static_assert(std::is_standard_layout<TypeEx<Type>>::value, "Oops"); 
    static_assert(offsetof(TypeEx<Type>, objectData) == 0, "Oops"); 
    TypeEx<Type>* retVal = static_cast<TypeEx<Type>*>((void*)obj); 
    return *(retVal->getExtension()); 
} 

template <typename Type> 
const typename LinkExtension<Type>::Type& getObjectEx(const Type* obj) 
{ 
    static_assert(std::is_standard_layout<TypeEx<Type>>::value, "Oops"); 
    static_assert(offsetof(TypeEx<Type>, objectData) == 0, "Oops"); 
    const TypeEx<Type>* retVal = static_cast<const TypeEx<Type>*>((const void*)obj); 
    return *(retVal->getExtension()); 
} 

template <typename Type> 
void deleteObjectEx(const Type* obj) 
{ 
    const TypeEx<Type>* objectEx = static_cast<const TypeEx<Type>*>((const void*)obj); 
    delete objectEx; 
} 

以及如何將分機鏈接到課程:

class MyClass { 
public: 
    virtual ~MyClass() = default; 
}; 
struct MyClassExtension { 
    int a; 
    int b; 
}; 
template <> 
struct LinkExtension<MyClass> { 
    using Type = MyClassExtension; 
}; 

和證明它的工作原理:

void printExtension(MyClass* object); 
int main() { 
    MyClass* object = createObjectEx<MyClass>(); 
    MyClassExtension& extension = getObjectEx(object); 
    extension.a = 1; 
    extension.b = 2; 
    printExtension(object); 
    deleteObjectEx(object); 

    TypeEx<MyClass> objectEx; 
    objectEx.getExtension()->a = 3; 
    objectEx.getExtension()->b = 4; 
    printExtension(objectEx.getObject()); 
} 

void printExtension(MyClass* object) 
{ 
    MyClassExtension& extension = getObjectEx(object); 
    std::cout << extension.a << ' ' << extension.b << std::endl; 
} 

如果你的編譯器不支持可變參數模板,該解決方案仍然是可能的,但需要更多的手工作業完成。

+0

我沒有修改類的權限,它是第三方類! –

+0

@StephaneRolland什麼類負責創建MyClass對象 - 它也是第三方類 - 或者它是你的代碼? – PiotrNycz

+0

MyClass *是指向第三方派對類的指針。但我負責實現對象的實例化以及它們的生命範圍。 –