つまり、拡張オブジェクトを使用して構造体に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;
}
コンパイラが可変個引数テンプレートをサポートしていない場合でも、解決策は可能ですが、完了するにはさらに多くの手作業が必要です。