当我必须扩展类的行为而不修改它时,我经常使用设计模式visitor。它添加了类似成员的函数,而无需修改它所使用的类的核心。
或多或少以同样的方式,我需要扩展第三方类,但主要是数据,而不是行为。
在这种情况下,我经常使用与键MyClass*
匹配的std :: map,其值为MyClassExtender
。 MyClassExtender包含所有附加信息。
在这样做时,我偶然想知道是否有其他方法可以做到这一点,可能更常见或更“最佳实践”。我应该将此添加剂类称为扩展器吗? 是否有这种模式的名称......
Nota Bene:我可以简单地在一个新类中聚合MyClass *和MyClassExtender,但我需要经常给出一个MyClass *来访问MyClassExtender,所以st :: map非常方便。
答案 0 :(得分:2)
为什么不把这个类子类化?继承是扩展类的方法,无论是行为还是状态。除非您只想将类的实例与其他数据相关联,否则它根本不会扩展,并且std :: map是正确的答案。
答案 1 :(得分:1)
所以 - 在带有扩展对象的struct中创建你的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;
}
如果您的编译器不支持可变参数模板,那么解决方案仍然可行,但需要更多的手工工作才能完成。