переопределить виртуальный метод C ++ - PullRequest
12 голосов
/ 26 января 2012

У меня есть шаблон класса, в котором некоторые методы определены как виртуальные, чтобы дать возможность пользователю моего класса дать реализацию для него в своем производном классе. Обратите внимание, что в моем шаблонном классе есть некоторые не виртуальные методы, которые используют виртуальный (виртуальный класс, который должен возвращать значение, вызывается в не виртуальном классе).

Можете ли вы дать мне простой пример правильного кода, где виртуальный метод родительского класса должен возвращать значение (но его реализация предоставляется в дочернем классе), а значение, возвращаемое виртуальным методом в родительском классе, равно используется в других методах этого класса. Потому что я где-то видел (например, здесь: Безопасное переопределение виртуальных функций C ++ ), что это может вызвать некоторые проблемы, и определенный пользователем метод заметит переопределение виртуального метода родительского класса.

Примечание: я программирую с Code :: Blocks, используя компилятор g ++.

РЕДАКТИРОВАТЬ: как требуется здесь простой пример того, что я хочу:

template<typename T>
class parent {
public:
  // Public methods that user can call
  int getSomething(T t);
  void putSomething(T t, int x);

  // public method that user should implement in his code
  virtual float compute(T t) { }

  // protected or private methods and attributes used internally by putSomething ...
  float doComplexeThings(...); // this can call
};

Метод compute () должен быть реализован пользователем (дочерним классом). Однако этот метод compute () вызывается, например, методами putSomething () и doComplexeThings ().

Ответы [ 3 ]

21 голосов
/ 26 января 2012

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

class parent {
public:
  // pure virtual method must be provided in subclass
  virtual void handle_event(int something) = 0; 
};

class child : public parent {
public:
  virtual void handle_event(int something) {
    // new exciting code
  }
};

class incomplete_child : public parent {
public:
  virtual void handle_event(int something) const {
    // does not override the pure virtual method
  }
};

int main() {
  parent *p = new child();
  p->handle_event(1); // will call child::handle_event
  parent *p = new incomplete_child(); // will not compile because handle_event
                                      // was not correctly overridden
}
20 голосов
/ 26 января 2012

Если вы можете использовать функции C ++ 11 в своем компиляторе, тогда переопределения могут быть помечены как таковые специальным идентификатором override:

 float compute() override;

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

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

0 голосов
/ 21 февраля 2018

Этот вопрос задают в 2013 году. Он довольно старый, но я нашел что-то новое, чего нет в ответах.

Нам нужно понять три понятия: перегрузка , перезапись и скрытие .

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

class A {
public:
  virtual void print() {
    cout << id_ << std::endl;
  }
private:
  string id_ = "A";
};

class B : A {
public:
  using A::print;
  void print(string id) {
    std::cout << id << std::endl;
  }
};

int main(int argc, char const *argv[]) {
  /* code */
  A a;
  a.print();
  B b;
  b.print();
  b.print("B");
  return 0;
}

Добавьте используя A :: print; в вашем производном классе сделает всю работу!

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

...