Тип параметра функции переопределения с типом производного класса

Я планирую создать интерфейс (скорее виртуальный базовый класс в С++) с помощью метода, который принимает аргумент собственного типа.

class Base {
public:
    virtual void seriousMethod(const Base &arg) = 0;
}

Полученный класс должен, однако, не принимать аргумент типа базового класса, а типа производного класса.

class Derived: public Base {
public:
    virtual void seriousMethod(const Derived &arg) { /* ... */ }
}

Как бы я понял это? Должен ли я формировать базовый класс (например, Base<Derived>) или есть более чистое решение?

Ответ 1

Вы не можете сделать это напрямую. Подумайте об этом случае:

Base b;
Derived d;
Base& d_ref = d;
d_ref.seriousMethod(b);  // What happens here?

В момент компиляции переменная d_ref имеет статический тип Base, поэтому в соответствии с определением Base он должен иметь возможность принимать b в качестве параметра seriousMethod.

Но во время выполнения динамический тип d_ref равен Derived, поэтому в соответствии с определением Derived он не может принимать b в качестве параметра seriousMethod. Он не может преобразовать b в Dervied, поскольку это может быть прямой объект Base (если Base не является абстрактным), или может быть какой-то другой класс, полученный из Base, который не является таким же, как Derived.

Вы правы, полагая, что единственный реальный способ сделать это - любопытно повторяющийся шаблон шаблона, т.е. шаблон Base и определение Dervied как:

class Derived : public Base<Derived> { ... }

Это устраняет проблему, проиллюстрированную выше, потому что каждый тип, полученный из Base<T>, будет иметь отдельный базовый класс и не будет связан между собой через наследование.