Виртуальная функция

У меня есть вопрос относительно виртуальной функции C++.

Производный класс (DerivedAlgo) реализует виртуальную функцию (BaseAlgo::process), но немного меняется в сигнатуре функции, используя DerivedData введите в качестве входного параметра вместо BaseData.

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

Мне просто интересно, кто-нибудь знает любое правило C++, которое может объяснить следующий код.

class BaseData{};
class DerivedData: public BaseData{};
class BaseAlgo{
public:
  virtual void process(BaseData& data) = 0;
};
class DerivedAlgo: BaseAlgo{
public:
  virtual void process(DerivedData& data){
    std::cout << "hello world!" << std::endl;
  }
};

В моем другом примере кода я определяю process(DerivedData&) а также process(BaseData&),

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

class DerivedAlgo{
public:
  virtual void process(DerivedData& data){...}
  virtual void process(BaseData& data){...}
};
BaseData baseData;
DerivedData derivedData;
derivedAlgo.process(baseData);
derivedAlgo.process(derivedData);

Я действительно ценю любой ваш вклад. Спасибо!

3 ответа

Ваш первый пример не компилируется на g++ 4.2. Для справки я сделал это:

#include <iostream>

class BaseData{};
class DerivedData: public BaseData{};
class BaseAlgo{
public:
  virtual void process(BaseData& data) = 0;
};
class DerivedAlgo: BaseAlgo{
public:
  virtual void process(DerivedData& data){
    std::cout << "hello world!" << std::endl;
  }
};

int main()
{
    DerivedAlgo da;

    return 0;
}

И получил это:

error: cannot declare variable 'da' to be of abstract type 'DerivedAlgo'
note:   because the following virtual functions are pure within 'DerivedAlgo'
note:  virtual void BaseAlgo::process(BaseData&)

Если что-то вроде моего примера скомпилировалось, то вы почти наверняка имеете глючный компилятор.

Ваш второй пример будет скомпилирован, потому что он переопределяет абстрактную функцию. Первый вызов вызовет базовую версию данных, а второй вызов вызовет производную версию процесса.

Обратите внимание, что в первом примере вы скрываете process(base) версия функции, не перекрывая ее вообще. Вы не должны изменять сигнатуру функции при переопределении виртуальных функций.

Вы уверены, что не получаете ошибку компилятора?

Когда я компилирую это (в MSVC9):

#include <cstdlib>
#include <memory>
#include <iostream>

class BaseData{};
class DerivedData: public BaseData{};
class BaseAlgo{
public:
  virtual void process(BaseData& data) = 0;
};
class DerivedAlgo: BaseAlgo{
public:
  virtual void process(DerivedData& data){
      data;
    std::cout << "hello world!" << std::endl;
  }
};

int main()
{
    DerivedAlgo da;
}

Я получаю ожидаемую ошибку:

1>.\main.cpp(21) : error C2259: 'DerivedAlgo' : cannot instantiate abstract class
1>        due to following members:
1>        'void BaseAlgo::process(BaseData &)' : is abstract
1>        .\main.cpp(9) : see declaration of 'BaseAlgo::process'

Это потому, что вы не можете переопределить виртуальные объекты с другими списками параметров:

10.3 Виртуальные функции

2/ Если виртуальная функция-член vf объявлена ​​в классе Base и в классе Derived, полученном прямо или косвенно из Base, объявляется функция-член vf с тем же именем и тем же списком параметров, что и Base:: vf, тогда Derived::vf также является виртуальным (независимо от того, объявлено оно или нет) и переопределяет97) Base::vf.

Единственный выход при объявлении переопределений в производном классе - это использование ковариантных возвращаемых типов.

Возможно, ваш компилятор не проверил ваш код полностью, если вы никогда не вызывали производный класс.

Проблема в том, что C++ не поддерживает двойную диспетчеризацию. Вам нужно использовать шаблон Visitor в вашем классе BaseAlgo.

Другие вопросы по тегам