Можем ли мы переопределить чистые виртуальные функции из унаследованного класса?

У меня есть класс интерфейса — IAnimal и 2 производных класса — Tcat и Tdog. Я хочу, чтобы и Tcat, и Tdog наследовали функцию Eat, однако я хочу, чтобы Tcat мог иметь 2 параметра, а Tdog — параметры, которые он наследует. Это возможно?

/// Pure virtual - to ensure all inherited animals have eat and sleep
class IAnimal
{
public:
    virtual ~IAnimal() {}
    virtual bool Eat(int _i_food) = 0;
    virtual bool Sleep(int _i_time) = 0;
};

class TCat : public IAnimal
{
public:
    bool Eat(int _i_food, int _i_amount); // can we override interface pure virtual from inherited class? 
    bool Sleep(int _i_time);
};

class TDog : public IAnimal
{
public:
    bool Eat(int _i_food);
    bool Sleep(int _i_time);
};

person Neysha    schedule 10.01.2017    source источник
comment
Во-первых, TCat не будет компилироваться, потому что контракт здесь заключается в том, что вы должны реализовать bool Eat(int), во-вторых, если вы определяете новую функцию, которая не соответствует сигнатуре чистой виртуальной функции базового класса, то это не переопределение, а перегрузка.   -  person EdChum    schedule 10.01.2017
comment
Погуглите принцип подстановки Лисков. Затем изучите свой код и поймите, почему то, что вы делаете, не поддерживает его.   -  person StoryTeller - Unslander Monica    schedule 10.01.2017
comment
@EdChum без явного объявления using это скрытие, а не перегрузка.   -  person Quentin    schedule 10.01.2017
comment
Переопределение Eat в TCat скрывает виртуальную функцию Eat в IAnimal.   -  person CashCow    schedule 10.01.2017
comment
обязательно используйте ключевое слово override для любых переопределяющих функций. Он сообщит вам, если вы ошиблись в подписи.   -  person Paul Rooney    schedule 10.01.2017
comment
@Quentin Квентин, да, это правда, но это не сработает, как намеревается ОП, кроме того.   -  person EdChum    schedule 10.01.2017


Ответы (4)


Нет. Подпись метода virtual изменить нельзя. Даже с параметрами по умолчанию.
Единственным исключением является ковариация, где тип возвращаемого значения может быть другим.

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

bool Eat(int _i_food, int _i_amount) override;  // error
person iammilind    schedule 10.01.2017

No

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

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

person nvoigt    schedule 10.01.2017

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

person pSoLT    schedule 10.01.2017

Ваша проблема в том, что метод Eat в TCat является не переопределением метода в его базовом классе, а перегрузкой, и он «скрывает» метод базового класса.

Смотрите этот вопрос:

Почему скрывается виртуальная функция?

person CashCow    schedule 10.01.2017