我在基类中有一个静态工厂方法。由于某些原因,我希望每个派生类都将由该工厂方法实例化,因此所有这些类都具有受保护的 ctor。
在实际情况下,Create 函数会执行更多附加逻辑以及错误处理。
class Base
{
public:
virtual ~Base() {}
template <typename T>
static void Create(std::unique_ptr<T>& pOut)
{
pOut = std::unique_ptr<T>(new T);
// ...
}
protected:
Base() {}
};
class Derived : public Base
{
protected:
Derived() {}
};
int main()
{
std::unique_ptr<Derived> ptr;
Derived::Create(ptr);
}
该代码显然无法编译,因为我们无权访问受保护的 ctor。
prog.cc: In instantiation of 'static void Base::Create(std::unique_ptr<_Tp>&) [with T = Derived]':
prog.cc:33:24: required from here
prog.cc:17:35: error: 'Derived::Derived()' is protected within this context
17 | pOut = std::unique_ptr<T>(new T);
| ^~~~~
prog.cc:26:5: note: declared protected here
26 | Derived() {}
| ^~~~~~~
第一个似乎最常见的解决方案是派生类中的友元声明。但是它有效,我不喜欢它,因为:
- 我必须在每个派生类中添加这样的声明
- 这是一个朋友
class Derived : public Base
{
protected:
Derived() {}
friend void Base::Create<Derived>(std::unique_ptr<Derived>&);
};
考虑更通用的方法,我正在尝试这样的事情:
template <typename T>
static void Create(std::unique_ptr<T>& pOut)
{
static_assert(std::is_base_of_v<Base, T>, "T should be Base-family class.");
class CreateHelper : public T
{
public:
static void InternalCreate(std::unique_ptr<T>& pOut)
{
pOut = std::unique_ptr<CreateHelper>(new CreateHelper);
// ...
}
};
CreateHelper::InternalCreate(pOut);
}
它有效,但对我来说看起来很奇怪,并且:
- 真正的指针类型是 CreateHelper 但是在这个函数之外我们看不到
- 这种方法需要 Base-familiy 应该是多态的,因为我们使用指向基类的指针(似乎应该始终满足这个条件,但仍然值得一提)
我的问题是
- 您如何看待最后一种方法?
- 它被认为是一个糟糕的设计吗?