Задача на перегрузку функций в C++, которая может оказаться сложнее, чем выглядит

Предположим, у нас есть два класса:

class Parent {
  public:
  virtual void print() { 
    std::cout << "Родительский класс" << std::endl; 
  }
};

class Derived : public Parent {
  public:
  virtual void print(int x) { 
    std::cout << "Производный класс" << std::endl;
  }     
};

Что выведут два следующих куска кода и почему?

int main() {
  Derived *derived = new Derived;
  derived -> print();
  return 0;
}  

int main() {
  Parent *derived = new Derived;
  derived -> print();
  return 0;
}

Решение

Не все так просто, как кажется на первый взгляд. Если для вас эта задача показалась легкой, то проверьте свои навыки в C++, прочитав решение.

  • В первом случае программа завершится с ошибкой.
  • Во втором случае выведется «Родительский класс».

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

error: no matching function for call to 'Derived::print()'

Почему же во втором случае мы не получаем ошибку, хотя также используем объект Derived для вызова print()?

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

Источник: Banterly