我正在尝试解决一个问题,我有一些课程,我需要做一些常见的工作,然后是一堆特定问题的工作,当这个完成时,对所有这些类做一些共同的处理。
我有一个Base和Derived类,它们都有一个名为Execute的函数。当我调用此函数的派生版本时,我希望能够对Base中的所有派生类执行一些常见处理,然后继续执行Derived :: Execute和返回到Base :: Execute以完成一些常见的工作。
在C ++中这是可能的吗?如何最好地做到这一点?
这是一个想法,但它可能不是那么可行:
class Base
{
public:
virtual void Execute();
};
Base::Execute() {
// do some pre work
Derived::Execute(); //Possible????
// do some more common work...
}
class Derived : public Base
{
public:
void Execute();
};
void Derived::Execute()
{
Base::Execute();
//Do some derived specific work...
}
int main()
{
Base * b = new Derived();
b.Execute(); //Call derived, to call into base and back into derived then back into base
}
答案 0 :(得分:9)
使用基础的纯虚函数..
class Base
{
public:
void Execute();
private:
virtual void _exec() = 0;
};
Base::Execute() {
// do some common pre work
// do derived specific work
_exec();
// do some more common work...
}
class Derived : public Base
{
private:
void _exec() {
// do stuff
}
};
int main()
{
Base * b = new Derived();
b.Execute();
}
编辑:在阅读了一些问题之后稍微改变了流程.. :)上面的机制应该完全符合你现在的要求 -
即
答案 1 :(得分:4)
这在C ++中被称为NVI(非虚拟接口,来自Herb Sutter here)习惯用法,基本上说你不应该有公共虚拟功能,而是保护/私有虚拟功能。用户代码必须在基类中调用您的公共非虚函数,并将调度到受保护/私有虚方法。
从设计角度来看,基本原理是基类有两个不同的接口,一方面是用户界面,由类的公共子集决定,另一方面是可扩展性接口或类如何扩展。通过使用NVI,您可以将两个接口分离,并允许在基类中实现更好的控制。
class base {
virtual void _foo(); // interface to extensions
public:
void foo() { // interface to users
// do some ops
_foo();
}
};
答案 2 :(得分:3)
将问题从头部转向脚部。你真正想要的是派生类可插入的基类算法:
class Base {
public:
void Execute()
{
// do something
execute();
// do some more things
}
private:
virtual void execute() = 0;
};
class Derived : public Base {
public:
// whatever
private:
virtual void execute()
{
//do some fancy stuff
}
};
让派生类插入基类算法通常称为 “模板方法” 模式(与template
无关。没有公共虚拟基类接口中的函数通常称为 “非虚拟接口” 模式。
我相信谷歌可以在这两个上找到你很多。
答案 3 :(得分:1)
将Base::Execute
内部移动到两个函数中,然后使用RAII轻松实现。
class Base{
protected:
void PreExecute(){
// stuff before Derived::Execute
}
void PostExecute(){
// stuff after Derived::Execute
}
public:
virtual void Execute() = 0;
};
struct ScopedBaseExecute{
typedef void(Base::*base_func)();
ScopedBaseExecute(Base* p)
: ptr_(p)
{ ptr_->PreExecute() }
~ScopedBaseExecute()
{ ptr_->PostExecute(); }
Base* ptr_;
};
class Derived : public Base{
public:
void Execute{
ScopedBaseExecute exec(this);
// do whatever you want...
}
};