类似于以下内容
class Base
{
protected:
Base()
{}
public:
virtual void initialize()
{}
template<typename D, typename... Ts>
static std::shared_ptr<D> create(Ts... args)
{
auto d = std::shared_ptr<D>(new D(args...));
d->initialize();
return d;
}
};
class Derived : public Base
{
private:
int value_;
protected:
public:
Derived(int v) : value_(v)
{}
void initialize() override
{
//Do something with value_
}
};
int main()
{
auto derived = Base::create<Derived>(42);
// etc.
return 0;
}
上面按预期工作但如果Base是库的用户通过实现Derived扩展的类库的一部分,那么没有什么能阻止库的用户通过其公共构造函数创建Derived,从而初始化won& #39;被叫。
在这样的库/库用户场景中,如何为Derived类创建强制使用Base :: create(...)之类的东西?
例如,如果将Base :: Base()设为私有而不是受保护,则代码不会被编译,因为Derived :: Derived()将无法访问它。
答案 0 :(得分:1)
如果您的目标只是确保派生类调用初始化函数使其成为纯虚拟。
我建议使用非虚拟接口(NVI)习语。
通过这种方式,库用户被强制在派生类中实现doInitialize函数。
actiongroup = gtk.ActionGroup('window-clip-actions')
accelgroup = gtk.AccelGroup()
fake_toolbar = gtk.Toolbar()
view.get_window().add_accel_group(accelgroup)
view.get_window().get_content_area().pack_start(fake_toolbar)
for shortcut, cb in (('<ctrl><shift>c', self.on_window_clip_copy),
('<ctrl><shift>v', self.on_window_clip_paste)):
action = gtk.Action(shortcut, shortcut, 'clip-action', None)
actiongroup.add_action_with_accel(action, shortcut)
action.connect("activate", cb)
action.set_accel_group(accelgroup)
action.connect_accelerator()
toolitem = action.create_tool_item()
fake_toolbar.insert(toolitem, -1)
fake_toolbar.set_visible(False)
答案 1 :(得分:1)
这个解决方案有点挑剔,但我认为它涵盖了所有基础:
class Base
{
protected:
// Token is only visible to Derived, and only constructible by Base
class token {
friend Base;
token() {};
};
// Constructing Base requires a token
Base(token)
{}
public:
// bla
template<typename D, typename... Ts>
static std::shared_ptr<D> create(Ts... args)
{
auto d = std::shared_ptr<D>(new D({}, args...));
// Token is created here ^^
// bla
}
};
class Derived : public Base
{
// bla
public:
// Derived receives and forwards the token to Base
// The implicit copy constructor is accessible
Derived(token t, int v) : Base(t), value_(v)
{}
// bla
};
因此,没有人可以写Derived d(Base::token{}, 42)
因为token
无法访问。 Derived
本身可以命名token
并传递一个,但不能创建一个:只有Base
的{{1}}函数可以。