在继续派生函数之前执行基函数

时间:2011-04-14 09:05:24

标签: c++ polymorphism

我正在尝试解决一个问题,我有一些课程,我需要做一些常见的工作,然后是一堆特定问题的工作,当这个完成时,对所有这些类做一些共同的处理。

我有一个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

}

4 个答案:

答案 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. Base Common Stuff
  2. 派生特定的东西
  3. 再次基础常见的东西

答案 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...
  }
};