Выполнение базовой функции перед продолжением в производной функции - PullRequest
4 голосов
/ 14 апреля 2011

Я пытаюсь решить проблему, когда у меня есть несколько классов, в которых мне нужно выполнить некоторую общую работу, а затем выполнить кучу задач, специфичных для проблемы, и когда это закончится, выполнить еще одну обработку, общую для всех этих классов.

У меня есть класс 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 ]

9 голосов
/ 14 апреля 2011

Использовать чисто виртуальную функцию из базы ..

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. Базовые общие вещи
  2. Производные конкретные вещи
  3. Базовые общие вещи снова
4 голосов
/ 14 апреля 2011

Это называется идиома NVI (Non-Virtual Interface, от Herb Sutter here ) в C ++, и в основном говорит, что вы должны иметь не общедоступные виртуальные функции, а защищенные / приватные виртуальные функции.Пользовательский код должен будет вызывать вашу общедоступную не виртуальную функцию в базовом классе, и она будет перенаправлена ​​на защищенный / закрытый виртуальный метод.

С точки зрения разработки обоснование состоит в том, что базовый класс имеет два разныхинтерфейсы, с одной стороны пользовательский интерфейс, определяемый общедоступным подмножеством класса, а с другой стороны - интерфейс расширяемости или способ расширения класса.Используя NVI, вы развязываете оба интерфейса и предоставляете больший контроль в базовом классе.

class base {
   virtual void _foo();  // interface to extensions
public:
   void foo() {          // interface to users
      // do some ops
      _foo();
   }
};
3 голосов
/ 14 апреля 2011

Переверните задачу с головы на ноги.На самом деле вы хотите иметь алгоритм базового класса, к которому могут подключаться производные классы:

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. Отсутствие общедоступных виртуальных функций в интерфейсе базового класса часто называется «не виртуальный интерфейс» шаблон.

Я уверен, что Google может найти вас много на этих двух.

1 голос
/ 14 апреля 2011

Переместите это 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...
  }
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...