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

StackOverflow https://stackoverflow.com/questions/232030

  •  04-07-2019
  •  | 
  •  

Вопрос

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

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

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

Это было полезно?

Решение

Другие советы

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

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

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

Есть два решения:

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

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

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

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

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

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

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

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

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

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

    <Ол>
  • Использование виртуальных функций (т.е. привязка во время выполнения)
  • Использование шаблонов (т. е. привязка времени компиляции)
  • Пример 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() );
         }
    };
    
    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top