Итак, я пытаюсь создать производный класс абстрактного базового класса, но чистые виртуальные методы не могут быть объявлены с использованием класса Derived.
template<class T>
class Foo
{
public:
virtual Foo<T>* add(const Foo<T>* rhs) = 0;
};
template<class T>
class Doo : public Foo<T>
{
public:
Doo<T>* add(const Doo<T>* rhs)
{
return this;
}
};
int main()
{
Doo<double> d;
return 0;
}
Я ожидал, что объявление метода добавления в Doo
сработает, потому что Doo
является подклассом Foo
, но g++ говорит, что я не переопределяю метод добавления Foo's
. Я предполагаю, что это что-то простое с тем, как я объявляю метод добавления Doo's
.
Подписи не совпадают, поэтому вы ничего не переопределяете. Найдите ключевое слово override
, чтобы ваш компилятор помог вам диагностировать подобные ошибки.
add(const Foo<T>* rhs)
не то же самое, что
add(const Doo<T>* rhs)
Они приводят разные аргументы.
Они также возвращают разные типы. Но возвращаемые типы не имеют значения при разрешении перегрузки или при переопределении, но обычно это также признак того, что вы пропустили отметку (того, что вы хотите переопределить), поскольку как правило вы хотите, чтобы ваша переопределяющая функция возвращала тот же тип, что и то, что она переопределяет. .
Я видел, что это решит проблему, но меня беспокоит то, что любой другой класс, производный от Foo, может быть передан в этот метод. Является ли единственным решением убедиться, что унаследованные объекты не нарушают родительские требования?
@ evader110 Извините, мне не совсем понятно, о чем вы там спрашиваете.
Если бы я создал другой производный класс с именем Goo
, производным от Foo
, работал бы он, если бы я передал его в метод добавления Doo? Если да, то будет ли создание невиртуального метода в Doo единственным способом избежать такого поведения?
@ evader110 Объявляя чисто виртуальный add
метод, Foo
обещает, что все производные классы будут иметь add
метод, который принимает указатель на Foo
. Метод add
, который накладывает какие-либо дополнительные ограничения на свой параметр, не выполняет это обещание и, следовательно, не считается реализацией этого чисто виртуального метода.
Используя функцию с другой сигнатурой, вы скрываете функцию, а не переопределяете ее.
Лучший способ защитить себя от этих ошибок — использовать ключевое слово override
следующим образом (в вашем примере) каждый раз, когда вы собираетесь переопределить виртуальную функцию:
Doo<T>* add(const Doo<T>* rhs) override
И тогда компилятор выдаст ошибку, если функция фактически не переопределяет.
один берет
Foo
другойDoo
, это разные методы