Переопределить виртуальный метод С++

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

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

Примечание. Я программирую с помощью 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(), например.

Ответ 1

Вам просто нужно убедиться, что методы имеют одну и ту же подпись (включая константы 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
}

Ответ 2

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

 float compute() override;

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

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

Ответ 3

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

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

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

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; в вашем классе-выводе будет выполнять работу!

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