Вызов функции производного класса из базового класса - PullRequest
12 голосов
/ 02 февраля 2011
class base
{
  public:
  virtual void start();
  virtual void stop();

  void doSomething() { start(); .... stop(); }
}

class derived : public base
{
  public:
   void start();
   void stop();
}

Но когда я вызываю doSomething() в производном классе, он использует собственное определение Start() и Stop(), а не производные.

Я не хочу переписывать doSomething() в производном классе, потому что он будет идентичен базовому. Что я делаю не так?

Извините, если это не ясно.
Поведение Start () и Stop () в производном классе отличается (это другой компьютер), но я хочу использовать исходный базовый класс doSomething (), потому что это не изменилось. Просто нужно запустить () и остановить () с использованием нового производного кода класса.

Ответы [ 3 ]

23 голосов
/ 02 февраля 2011

Код, который вы разместили, должен работать так, как вы хотите. Вызов doSomething для экземпляра derived вызовет переопределенные функции start и stop, определенные в derived.

Впрочем, есть исключение. Если вы вызовете doSomething в конструкторе или деструкторе base (прямо или косвенно), то вызываемые версии start и stop будут определены в base. Это потому, что в этих обстоятельствах у вас еще нет действительного экземпляра derived. Он либо не полностью построен, либо частично разрушен, поэтому язык не позволяет вызывать методы, которые будут использовать частичный объект.

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

7 голосов
/ 02 февраля 2011

Обновление
На основании вашего комментария ниже о том, что вы пытаетесь заставить doSomething () вызвать версию start () и stop () класса производного, мой обновленный ответ на ваш вопрос выглядит следующим образом:

Нет ничего плохого в том, как вы определили Base и Derived. Вы, вероятно, испытываете то, что называется «нарезкой кода», когда вы вызываете «doSomething ()» для объекта, объявленный тип которого «Base» вместо «Base *» или «Base &», что приведет к тому, что объект будет преобразован в тип Base.

Плохой пример:

 Derived derived;
 Base base = derived;
 base.doSomething();  // This is Base's version of doSomething()

Хороший пример:

 Base* base = new Derived;  // NOTE: declared type is "Base*"
 base->doSomething();  // This will call Derived version
 delete base;

Примечание: вы должны использовать scoped_ptr, shared_ptr, unique_ptr или какой-либо другой класс интеллектуальных указателей вместо прямого указателя, как в моем примере; однако, чтобы не затенять проблему, я решил использовать необработанный указатель в этом примере. Для получения дополнительной информации о «нарезке» см .:

Оригинальное решение
Вы могли бы сделать что-то вроде этого:

class Base {
    public:
        Base() {}
        virtual ~Base() {}

        virtual void start() {
           startInternal();
        }

        virtual void stop() {
            stopInternal();
        }

        void doSomething() {
            startInternal();
            // ...
            stopInternal();
        }
    private:
        void startInternal() {
          // ...
        } 
        void stopInternal() {
          // ...
        }
};

class Derived : public Base {
    public:
        Derived() {}
        virtual ~Derived() {}
        virtual void start() {
            // ...
        }
        virtual void stop() {
            // ...
        }
};

Если вы сделаете это, то doSomething () будет использовать внутреннюю версию start / stop, которая не переопределяется. Вы часто найдете этот шаблон, когда конструктор / деструктор должен разделить логику с виртуальным методом.

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

1 голос
/ 26 июня 2018

Просто объявите функции запуска и остановки как чисто виртуальные в базовом классе.

virtual void stop() = 0;
virtual void start() = 0;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...