C++ - переопределить виртуальную функцию и полиморфизм

Я думаю, что я не понимаю что-то очень базовое понятие о виртуальном поведении. Я хочу создать следующую иерархию:

    class Parser{

       virtual Parsable parse() = 0;
    }

    class SpecialParser : public Parser{

       SpecialParsable parse() override; // implemented

    }

Где явно класс SpecialParsable наследуется от Parsable.

Это возвращает мне ошибку из-за другой подписи. (SpecialParser::parse() returns SpecialParsable instead of Parsable).

Теперь Parsable явно является абстрактным классом, и я не хочу создавать его экземпляры. Я не понимаю, почему это невозможно сделать, поскольку SpecialParsable - это всего лишь конкретная реализация Parsable.

Заранее спасибо,

Они должны возвращать тот же тип.

tkausl 08.07.2019 12:14

См. эта тема, как вернуть объект. И для разных типов возврата SpecialParsable должен наследоваться от Parseable, но я думаю, это так?!

lubgr 08.07.2019 12:16
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
85
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Динамический полиморфизм в C++ основан на косвенности. Если вы вернете указатель (или ссылку), ваш пример будет скомпилирован и будет вести себя так, как ожидалось. Это называется "ковариантным возвращаемым типом":

class Parser {
   virtual Parsable* parse() = 0;
};

class SpecialParser : public Parser {
   SpecialParsable* parse() override; // implemented
};

живой пример на godbolt.org

Есть ли веская причина для этого? Я имею в виду, что если вы вызываете parse() из указателя/ссылки на базовый класс, то вы все равно не знаете «настоящего» возвращаемого типа. И если вы вызываете его напрямую из производного класса, то зачем делать его виртуальным? Или, если он виртуальный, по какой-то другой причине, то добавление static_cast к возвращаемому указателю должно быть намного проще...

sklott 08.07.2019 14:05

@sklott: ковариация позволяет использовать наиболее специализированный класс, если вы знаете класс. Из Parser вы получили только Parsable, но из SpecialParser вы можете получить доступ к дополнительным функциям из SpecialParsable или ограничиться интерфейсом Parsable.

Jarod42 08.07.2019 16:14

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