Подтвердить что ты не робот

С++ Родительский класс, вызывающий дочернюю виртуальную функцию

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

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;
}

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

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

4b9b3361

Ответ 2

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

Ответ 3

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

Ответ 4

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

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

  • Сделать вызов Process() в конструкторе производного класса
  • определить пустой элемент функции для процесса, как в следующем примере:
class parent
{
  public:
    void Read() { //read stuff }
    virtual void Process() { }
    parent() 
    {
        Read();
        Process();
    }
}

Ответ 5

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

class parent
{
    public:
        void initialize() {
            read();
            process();
        }
}

Ответ 6

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

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;
}

Ответ 7

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

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

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

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

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

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

Пример 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() );
     }
};