C ++ Родительский класс, вызывающий дочернюю виртуальную функцию - PullRequest
12 голосов
/ 24 октября 2008

Я хочу, чтобы чисто виртуальный родительский класс вызывал дочернюю реализацию функции следующим образом:

class parent
{
  public:
    void Read() { //read stuff }
    virtual void Process() = 0;
    parent() 
    {
        Read();
        Process();
    }
}
class child : public parent
{
  public:
    virtual void Process() { //process stuff }
    child() : parent() { }
}

int main()
{
   child c;
}

Это должно работать, но я получаю несвязанную ошибку: / Это использует VC ++ 2k3

Или не должно сработать, я не прав?

Ответы [ 7 ]

19 голосов
/ 24 октября 2008
4 голосов
/ 24 октября 2008

В качестве альтернативы, создайте фабричный метод для создания объектов и сделайте конструкторы частными, тогда фабричный метод может инициализировать объект после построения.

2 голосов
/ 24 октября 2008

Еще на один шаг вы можете просто ввести какую-то функцию вроде

class parent
{
    public:
        void initialize() {
            read();
            process();
        }
}
2 голосов
/ 24 октября 2008

Это потому, что ваш вызов в конструкторе. Производный класс не будет действительным до тех пор, пока конструктор не завершит работу, поэтому вы, компилятор, правы в этом.

Существует два решения:

  1. Выполнить вызов Process () в конструкторе производного класса
  2. определить пустое тело функции для процесса, как в следующем примере:
class parent
{
  public:
    void Read() { //read stuff }
    virtual void Process() { }
    parent() 
    {
        Read();
        Process();
    }
}
2 голосов
/ 24 октября 2008

Будет работать в целом, но не для вызовов внутри конструктора чисто виртуального базового класса. В то время как базовый класс создан, переопределение подкласса не существует, поэтому его нельзя вызвать. Пока вы вызываете его, как только весь объект создан, он должен работать.

0 голосов
/ 24 октября 2008

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

Насколько я понимаю, существенная проблема заключается в том, что вы пытаетесь повторно использовать функциональность путем наследования. Это почти всегда плохая идея. Вопрос дизайна, так сказать:)

По сути, вы пытаетесь создать экземпляр шаблона Template Method, чтобы отделить что от , когда : сначала прочитать некоторые данные (каким-то образом), затем обработать их (каким-то образом ).

Вероятно, это будет намного лучше работать с агрегацией: передайте функцию Processing методу Template, который будет вызван в нужное время. Может быть, вы даже можете сделать то же самое для функции чтения.

Агрегирование может быть выполнено двумя способами:

  1. Использование виртуальных функций (т. Е. Связывание во время выполнения)
  2. Использование шаблонов (т. Е. Привязка времени компиляции)

Пример 1: привязка во время выполнения

class Data {};
class IReader    { public: virtual Data read()            = 0; };
class IProcessor { public: virtual void process( Data& d) = 0; };

class ReadNProcess {
public:
    ReadNProcess( IReader& reader, IProcessor processor ){
       processor.process( reader.read() );
    }
};

Пример 2: привязка времени компиляции

template< typename Reader, typename Writer > // definitely could use concepts here :)
class ReadNProcess {
public:
     ReadNProcess( Reader& r, Processor& p ) {
         p.process( r.read() );
     }
};
0 голосов
/ 24 октября 2008

Вам нужно обернуть внутри объекта, который вызывает виртуальный метод после того, как объект полностью построен:

class parent
{
  public:
    void Read() { /*read stuff*/ }
    virtual void Process() = 0;
    parent()
    {
        Read();
    }
};

class child: public parent
{
  public:
    virtual void Process() { /*process stuff*/ }
    child() : parent() { }
};

template<typename T>
class Processor
{
    public:
        Processor()
            :processorObj() // Pass on any args here
        {
            processorObj.Process();
        }
    private:
        T   processorObj;

};




int main()
{
   Processor<child> c;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...