[英]Access to protected constructor from static factory method in base class
I've got a static factory method in a base class.我在基础 class 中有一个 static 工厂方法。 Because of some reasons I want to each derived class will be instantiated by this factory method hence all these classes have protected ctors.由于某些原因,我希望每个派生的 class 都将由此工厂方法实例化,因此所有这些类都具有受保护的 ctor。
In real situation the Create function does more additional logic along with error handling.在实际情况下,Create function 执行更多附加逻辑以及错误处理。
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);
}
That code obviously doesn't compile since we don't have access to the protected ctor.该代码显然无法编译,因为我们无权访问受保护的 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() {}
| ^~~~~~~
The first solution that seems to be the most common is friend declaration in derived class.第一个似乎最常见的解决方案是派生 class 中的友元声明。 However it works I don't like it because:但是它有效,我不喜欢它,因为:
class Derived : public Base
{
protected:
Derived() {}
friend void Base::Create<Derived>(std::unique_ptr<Derived>&);
};
Thinking about more generic approach I was trying something like this:考虑更通用的方法,我正在尝试这样的事情:
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);
}
It works but looks weird to me and:它有效,但对我来说看起来很奇怪,并且:
My questions are我的问题是
In general, a far better approach here is to simply refer to simple construction helper classes, then you can refer to make_unique() too:一般来说,这里更好的方法是简单地引用简单的构造辅助类,然后你也可以引用 make_unique() :
class Base
{
protected:
struct Accessor
{
explicit Accessor() = default;
};
public:
Base(Accessor) {}
virtual ~Base() {}
template <typename T>
static void Create(std::unique_ptr<T>& pOut)
{
pOut = std::make_unique<T>(Accessor());
// ...
}
};
class Derived : public Base
{
public:
Derived(Accessor) : Base(Accessor()) {}
};
Only drawback: Derived classes have to adapt their constructor(s) accordingly.唯一的缺点:派生类必须相应地调整其构造函数。
A general point: A factory should almost always be aware of its relevant types in general, at least of partial aspects of the relevant types, provided by polymorphism (interfaces) or/and via traits.一般观点:工厂应该几乎总是知道它的相关类型,至少是相关类型的部分方面,由多态性(接口)或/和通过特征提供。 So I think, this is a bit more convenient:所以我认为,这更方便一点:
template <class T, typename std::enable_if<std::is_base_of<Base, T>::value>::type* = nullptr>
static void Create(std::unique_ptr<T>& pOut)
{
pOut = std::make_unique<T>(Accessor());
// ...
}
Further on: You might have to rethink about your general creation design here.进一步:您可能必须在这里重新考虑您的一般创作设计。 The common approach here is to return the created object, not to fill a reference.这里常用的做法是返回创建的object,而不是填写引用。 With your current approach, you have to think about exception safety (contracts..) here at least twice for instance...使用您当前的方法,您必须在这里至少考虑两次异常安全(合同......),例如......
Possible approach:可能的方法:
template <class T, typename std::enable_if<std::is_base_of<Base, T>::value>::type* = nullptr>
static std::unique_ptr<T> Create()
{
auto pOut = std::make_unique<T>(Accessor());
// ...
return pOut;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.