我有一些第三方抽象基类
struct foo
{
virtual foo*job() = 0;
...
static void* make_space(size_t sizeofDerived);
};
我无法改变。类型foo
的对象(以及所有派生类)只能使用放置新建创建/构造到foo::make_space()
返回的内存中, 因为普通建筑,如
derived_from_foo z; // or
auto p = new derived_from_foo();
可能会导致不希望出现的问题(损坏内存,具体取决于编译器,正如我最终发现的那样)。所以我的问题:如何编写/设计派生类
struct bar // still abstract, since foo::job() is not provided
: foo
{
...
template<typename Derived, typename...Args>
static Derived* create(Args&&...args)
{
return ::new(foo::make_space(sizeof(Derived)))
Derived(std::forward<Args>(args)...);
}
};
因此,构造类型bar
的对象或通过bar::create()
以外的任何其他方式从bar
派生的任何类型的对象在运行时 (i) 编译或 (ii,不太理想)失败?
事实上,你可以强制执行它,但要付出代价。
考虑这个类:
class A
{
public:
class Tag
{
public:
Tag(const Tag&) = default;
Tag(Tag&&) = default;
private:
Tag() {}
friend class A;
};
A(Tag, int a, char b) : a(a), b(b) {}
int a;
char b;
template<typename T, typename ... Params>
static T* make(Params&& ... params)
{
return new T(Tag(), std::forward<Params>(params)...);
}
};
它的构造函数需要一个Tag
参数,但你不能做一个Tag
,它有一个私有构造函数。你可以从A
派生,但也不能直接创建派生类的对象:它需要将Tag
传递给它的父构造函数,而你不能创建一个。
因此,创建A
对象或派生类的唯一方法是调用A::make
。
好吧,还有办法作弊
class B : public A
{
public:
B(Tag t, double q) : A(t, 42, 'z'), q(q) {
// cheating:
B* other = new B(t, 3.14);
}
double q;
};
如果这困扰您,您仍然可以通过在运行时强制Tag
正确性,使不可重用 à lastd::unique_ptr
。移除复制 ctor,放入您在施工时设置的私人布尔标志并在搬出时清除,然后在make
内检查它。