Din*_*aiz 11 c++ methods class base-class
我正在尝试实现命令设计模式,但我遇到了一个概念问题.假设您有一个基类和一些子类,如下例所示:
class Command : public boost::noncopyable {
virtual ResultType operator()()=0;
//Restores the model state as it was before command's execution.
virtual void undo()=0;
//Registers this command on the command stack.
void register();
};
class SomeCommand : public Command {
virtual ResultType operator()(); // Implementation doesn't really matter here
virtual void undo(); // Same
};
Run Code Online (Sandbox Code Playgroud)
问题是,每次()在SomeCommand实例上调用操作符时,我都想通过调用Command的register方法将*this添加到堆栈中(主要用于撤消).我想避免从SomeCommand :: operator()()调用"register",但要将它命名为automaticaly(someway ;-))
我知道当你构造一个像SomeCommand这样的子类时,基类构造函数被称为automaticaly,所以我可以在那里添加一个"register"调用.在调用operator()()之前,我不想调用它.
我怎样才能做到这一点?我想我的设计有些缺陷,但我真的不知道如何使这项工作.
Dav*_*eas 28
看起来您可以从NVI(非虚拟接口)习语中受益.在那里,command对象的接口没有虚拟方法,但会调用私有扩展点:
class command {
public:
void operator()() {
do_command();
add_to_undo_stack(this);
}
void undo();
private:
virtual void do_command();
virtual void do_undo();
};
Run Code Online (Sandbox Code Playgroud)
这种方法有不同的优点,首先是您可以在基类中添加常用功能.其他优点是您的类的接口和扩展点的接口没有相互绑定,因此您可以在公共接口和虚拟扩展接口中提供不同的签名.搜索NVI,您将获得更多更好的解释.
附录:Herb Sutter 的原始文章,他介绍了这个概念(尚未命名)
用两种不同的方法拆分运算符,例如execute和executeImpl(说实话,我真的不喜欢()运算符).Make Command :: execute non-virtual,Command :: executeImpl pure virtual,然后让Command :: execute执行注册,然后调用executeImpl,如下所示:
class Command
{
public:
ResultType execute()
{
... // do registration
return executeImpl();
}
protected:
virtual ResultType executeImpl() = 0;
};
class SomeCommand
{
protected:
virtual ResultType executeImpl();
};
Run Code Online (Sandbox Code Playgroud)