ковариация c , вызов дочернего метода

#c #c 17 #covariant-return-types

#c #c 17 #ковариантные типы возврата

Вопрос:

Я создаю два простых класса по наследованию и добавляю виртуальную функцию и переопределение в дочернем классе.

 class Base { public:  virtual Base* getThis() { std::cout lt;lt; "called Base::getThis()n"; return this; }  virtual void func1() { std::cout lt;lt; "called Base::func1n"; } };  class Derived : public Base { public:  Derived* getThis() override { std::cout lt;lt; "called Derived::getThis()n"; return this; }  void func1() override { std::cout lt;lt; "called Derived::func1n"; }  void func2() { std::cout lt;lt; "called Derived::func2n"; } };  

С помощью ковариации c я могу это сделать:

 int main() {  Derived d{};  Base* b{ amp;d };  b-gt;getThis()-gt;func1();  return 0; }  

А теперь я хотел бы позвонить Derived::func2 .

 b-gt;getThis()-gt;func2();  

Предыдущий код выдает следующую ошибку: error: 'class Base' has no member named 'func2';

Единственное решение, которое у меня есть:

 dynamic_castlt;Derived*gt;(b-gt;getThis())-gt;func2();  

Мы должны использовать dynamic_cast или static_cast , позвонить Derived::func2 ?
Есть ли другой метод?

Комментарии:

1. С точки зрения ООП это довольно подозрительно , что, как только вы «понизили» тип указателя с Derived* до Base* , вы хотите получить доступ к элементам, специфичным для производных.

Ответ №1:

Должны ли мы использовать dynamic_cast или static_cast для вызова Derived::func2?

ДА.

Есть ли другой метод?

Объявите виртуальную Base::func2 функцию.


Чтобы прояснить вопрос о ковариации, это делает это возможным:

 Derived d{}; d-gt;getThis()-gt;func2();  

Без ковариации Derived* Derived::getThis это было бы недопустимо, и, следовательно, вышеперечисленное не сработало бы.

Ответ №2:

Ковариантные типы возвращаемых значений-это всего лишь трюк, который позволяет работать принципу подстановки Лискова при незначительном изменении типа возвращаемого значения в интерфейсе производного класса. Но суть LSP остается прежней: интерфейс базового класса-это интерфейс. Это не способ сделать так, чтобы базовый класс прозрачно предоставлял материалы, которые являются исключительно частью производного класса.

Если у вас есть указатель/ссылка на базовый класс, вызов getThis этого указателя/ссылки всегда будет возвращать a Base* . Если вы хотите получить некоторые производные элементы только для классов, вы всегда должны использовать какое-то приведение.