Пример не виртуального множественного наследования - PullRequest
5 голосов
/ 24 марта 2020

Существует ли реальный пример использования не виртуального множественного наследования? Я хотел бы иметь один в основном по причинам, связанным с didacti c. Шлепание по классам с именами A, B, C и D, где B и C наследуются от A, а D наследуется от B, а C прекрасно для объяснения вопроса «Есть ли / должен ли D объект иметь один или два A подобъекта?», но не имеет значения, почему у нас даже есть оба варианта. Многие примеры заботятся о том, почему мы хотим виртуальное наследование, но почему бы нам не хотеть виртуальное наследование?

Я знаю, что такое виртуальные базовые классы и как express эти вещи в коде. Я знаю о наследовании бриллиантов, и примеров множественного наследования с виртуальным базовым классом предостаточно.

Лучшее, что я мог найти, - это транспортные средства. Базовый класс - Vehicle, который наследуется Car и Boat. Среди прочего, Vehicle имеет occupants() и max_speed(). Таким образом, Amphibian, который наследует от Car и Boat, наследует разные max_speed() на суше и воде - и это имеет смысл - но также отличается occupants() - и это не имеет смысла. Таким образом, Vehicle подобъекты на самом деле не являются независимыми; это еще одна проблема, которую может быть интересно решить, но это , а не вопрос.

Есть ли пример, который имеет смысл в качестве модели реального мира, где две подгруппы объекты действительно независимы?

Ответы [ 2 ]

5 голосов
/ 24 марта 2020

Вы думаете, как OOP программист, пытаясь создавать абстрактные модели вещей. Многократное наследование C ++, как и многие другие вещи в C ++, - это инструмент , который имеет особый эффект. Относится ли это к какой-либо модели OOP, не имеет значения, если использовать утилиту самого инструмента. Иными словами, вам не нужна «модель реального мира», чтобы оправдать не виртуальное наследование; вам просто нужен реальный сценарий использования .

Поскольку производный класс наследует членов базового класса, наследование часто используется в C ++ как средство сбора набора общих функций. вместе, иногда с минимальным взаимодействием с производным классом и введением этой функциональности непосредственно в производный класс.

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

Самый простой пример, который я могу вспомнить в C ++, - это enable_shared_from_this, который позволяет объекту, время жизни которого в настоящее время управляется shared_ptr для фактического получения shared_ptr для этого объекта только из указателя / ссылки на этот объект. При этом используется CRTP для добавления различных членов и интерфейсов, необходимых для обеспечения возможности shared_from_this в производном классе. А так как наследование является publi c, оно также позволяет различным функциям shared_ptr, которые "позволяют shared_from_this" обнаруживать, что в конкретном типе есть элемент shared_from_this, и правильно его инициализировать.

enable_shared_from_this не нуждается в виртуальном наследовании и, вероятно, с ним не очень хорошо будет работать.

Теперь представьте, что у меня есть какой-то другой класс CRTP, который внедряет некоторые другие функции в объект. Эта функциональность не имеет ничего общего с shared_ptr, но использует CRTP и наследование.

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

Виртуальное наследование не является бесплатным. Это фундаментально меняет кучу вещей о том, как тип относится к своим базовым классам. Если вы наследуете от такого типа, ваши конструкторы должны инициализировать любые виртуальные базовые классы напрямую . Компоновка такого типа очень странная и вряд ли будет стандартизирована. И разные другие вещи. C ++ старается не заставлять программистов платить за функциональность, которой они не пользуются, поэтому, если вам не нужны специальные свойства виртуального наследования, вам не следует его использовать.

0 голосов
/ 30 марта 2020

По той же причине, что в C ++ есть не виртуальные методы - потому что реализация проще и эффективнее, если вы используете не виртуальное наследование, поэтому вам нужно явно запросить виртуальное наследование, если вы этого хотите. Поскольку вам это не нужно, если ваши классы никогда не используют множественное наследование, это значение по умолчанию.

...