Мой стиль кодирования включает в себя следующую идиому:
class Derived : public Base
{
public :
typedef Base super; // note that it could be hidden in
// protected/private section, instead
// Etc.
} ;
Это позволяет мне использовать «super» в качестве псевдонима для Base, например, в конструкторах:
Derived(int i, int j)
: super(i), J(j)
{
}
Или даже при вызове метода из базового класса внутри его переопределенной версии:
void Derived::foo()
{
super::foo() ;
// ... And then, do something else
}
Это может даже быть приковано цепью (я все еще должен найти использование для этого, хотя):
class DerivedDerived : public Derived
{
public :
typedef Derived super; // note that it could be hidden in
// protected/private section, instead
// Etc.
} ;
void DerivedDerived::bar()
{
super::bar() ; // will call Derived::bar
super::super::bar ; // will call Base::bar
// ... And then, do something else
}
В любом случае, я считаю использование «typedef super» очень полезным, например, когда Base либо многословен и / или шаблонизирован.
Дело в том, что super реализован в Java, а также в C # (где его называют «базовым», если я не ошибаюсь). Но C ++ не хватает этого ключевого слова.
Итак, мои вопросы:
- такое использование typedef супер распространено / редко / никогда не встречалось в коде, с которым вы работаете?
- Это использование typedef супер хорошо (то есть вы видите сильные или не очень веские причины не использовать его)?
- должно ли быть "super" хорошей вещью, должно ли оно быть несколько стандартизировано в C ++, или уже достаточно использования через typedef?
Изменить: Родди упомянул тот факт, что typedef должен быть закрытым. Это будет означать, что любой производный класс не сможет использовать его без повторного выделения. Но я думаю, что это также предотвратит цепочку super :: super (но кто за это будет плакать?).
Редактировать 2: Теперь, спустя несколько месяцев после массового использования «супер», я полностью согласен с точкой зрения Родди: «супер» должен быть частным. Я бы дважды подтвердил его ответ, но, думаю, не смогу.
источник
super
выглядитJava
и ничего плохого, но ... НоC++
поддерживает множественное наследование.MyFirstBase<MyString, MyStruct<MyData, MyValue>>
везде)template <class baz> struct Foo {...void bar() {...} ...}; struct Foo2: Foo<AnnoyinglyLongListOfArguments> { void bar2() { ... Foo::bar(); ...} };
это сработало для меня с gcc 9.1 --std = c ++ 1y (c ++ 14).Ответы:
Бьярн Страуструп упоминает в Design and Evolution of C ++, что
super
в качестве ключевого слова комитет по стандартам ISO C ++ рассматривал его впервые при стандартизации C ++.Даг Брук предложил это расширение, назвав базовый класс «унаследованным». В предложении упоминается проблема множественного наследования, и она помечает неоднозначные варианты использования. Даже Страуструп был убежден.
После обсуждения Даг Брук (да, тот же человек, который сделал предложение) написал, что предложение было выполнимо, технически обоснованно, не содержало серьезных недостатков и обрабатывало множественное наследование. С другой стороны, не хватило денег, и комитет должен решить более сложную проблему.
Майкл Тиманн опоздал, а затем показал, что суперопределение типа superdef будет работать просто отлично, используя ту же технику, о которой спрашивалось в этом посте.
Так что нет, это, вероятно, никогда не станет стандартизированным.
Если у вас нет копии, Дизайн и Эволюция вполне стоят стоимости обложки. Использованные копии можно купить за 10 долларов.
источник
typedef
технике есть большой недостаток : она не уважает СУХОЙ. Единственный выход - использовать некрасивые макросы для объявления классов. Когда вы наследуете, база может быть длинным многопараметрическим шаблоном класса или хуже. (например, мультиклассы) вам придется переписать все это во второй раз. Наконец, я вижу большую проблему с основами шаблона, которые имеют аргументы класса шаблона. В этом случае супер является шаблоном (а не экземпляром шаблона). Который не может быть определен. Даже в C ++ 11 вам нужноusing
для этого случая.Я всегда использовал «унаследованный», а не супер. (Вероятно, из-за фона Delphi), и я всегда делаю его закрытым , чтобы избежать проблемы, когда «унаследованное» ошибочно исключено из класса, но подкласс пытается его использовать.
Мой стандартный «шаблон кода» для создания новых классов включает в себя typedef, поэтому у меня есть небольшая возможность случайно пропустить его.
Я не думаю, что цепочка «супер :: супер» - это хорошая идея. Если вы делаете это, вы, вероятно, очень сильно привязаны к определенной иерархии, и изменение ее, скорее всего, плохо сломает.
источник
virtual
как показано здесь: martinbroadhurst.com/typedef-super.htmlОдна из проблем заключается в том, что если вы забудете (пере) определить super для производных классов, то любой вызов super :: что-то будет хорошо скомпилирован, но, вероятно, не вызовет нужную функцию.
Например:
(Как отметил Мартин Йорк в комментариях к этому ответу, эту проблему можно устранить, сделав typedef частным, а не общедоступным или защищенным.)
источник
super1
для Base иsuper2
в Derived? DerivedAgain может использовать оба?FWIW Microsoft добавила расширение для __super в свой компилятор.
источник
Super (или унаследованный) - это очень хорошая вещь, потому что если вам нужно вставить другой слой наследования между Base и Derived, вам нужно всего лишь изменить две вещи: 1. «class Base: foo» и 2. typedef
Если я правильно помню, комитет по стандартам C ++ рассматривал вопрос о добавлении ключевого слова для этого ... пока Майкл Тиманн не указал, что этот трюк с определением типа работает.
Что касается множественного наследования, так как он находится под контролем программиста, вы можете делать все, что захотите: может быть, super1 и super2 или что угодно.
источник
Я только что нашел альтернативное решение. У меня есть большая проблема с подходом typedef, который меня укусил сегодня:
Поэтому я нашел лучшее решение, используя очень простой шаблон.
Так что теперь вместо
у тебя есть
В этом случае
BaseAlias
не является частным, и я попытался защититься от неосторожного использования, выбрав имя типа, которое должно насторожить других разработчиков.источник
public
псевдоним является недостатком, так как вы открыты для ошибки, упомянутой в ответах Родди и Кристофера (например, вы можете (по ошибке) получитьDerived
вместоMakeAlias<Derived>
)MakeAlias
или совершенной пересылки, но для этого требуется, чтобы вы ссылались наMakeAlias<BaseAlias>
конструкторы, а не просто ссылались наC
конструкторы России напрямую.)Я не помню, чтобы видел это раньше, но на первый взгляд мне это нравится. Как отмечает Ферруччо , это не очень хорошо работает перед лицом MI, но MI - это скорее исключение, чем правило, и нет ничего, что говорило бы о том, что что-то нужно использовать везде, чтобы быть полезным.
источник
Я видел эту идиому, используемую во многих кодах, и я почти уверен, что видел ее где-то в библиотеках Boost. Тем не менее, насколько я помню, наиболее распространенное имя
base
(илиBase
) вместоsuper
.Эта идиома особенно полезна при работе с шаблонными классами. В качестве примера рассмотрим следующий класс (из реального проекта ):
Не обращайте внимания на смешные имена. Важным моментом здесь является то, что цепочка наследования использует аргументы типа для достижения полиморфизма во время компиляции. К сожалению, уровень вложенности этих шаблонов становится довольно высоким. Следовательно, сокращения важны для удобочитаемости и удобства обслуживания.
источник
Я довольно часто видел, как он используется, иногда как super_t, когда база представляет собой сложный тип шаблона (
boost::iterator_adaptor
делает это, например)источник
такое использование typedef супер распространено / редко / никогда не встречалось в коде, с которым вы работаете?
Я никогда не видел этот конкретный шаблон в коде C ++, с которым я работаю, но это не значит, что его там нет.
Это использование typedef супер хорошо (то есть вы видите сильные или не очень веские причины не использовать его)?
Это не учитывает множественное наследование (чисто, во всяком случае).
должно ли быть "super" хорошей вещью, должно ли оно быть несколько стандартизировано в C ++, или уже достаточно использования через typedef?
По вышеуказанной причине (множественное наследование) нет. Причина, по которой вы видите «super» в других перечисленных вами языках, заключается в том, что они поддерживают только одиночное наследование, поэтому не возникает путаницы в отношении того, что означает «super». Конечно, в этих языках это полезно, но на самом деле ему нет места в модели данных C ++.
Да, и к вашему сведению: C ++ / CLI поддерживает эту концепцию в форме ключевого слова "__super". Обратите внимание, что C ++ / CLI также не поддерживает множественное наследование.
источник
Еще одна причина использовать typedef для суперкласса - когда вы используете сложные шаблоны в наследовании объекта.
Например:
В классе B было бы идеально иметь typedef для A, иначе вы бы застряли, повторяя его везде, где вы хотели бы сослаться на членов A.
В этих случаях он также может работать с множественным наследованием, но у вас не будет typedef с именем «super», он будет называться «base_A_t» или что-то в этом роде.
--jeffk ++
источник
После перехода с Turbo Pascal на C ++ в тот же день я делал это, чтобы получить эквивалент для «унаследованного» ключевого слова Turbo Pascal, которое работает аналогичным образом. Однако после программирования на C ++ на несколько лет я перестал это делать. Я обнаружил, что мне это не очень нужно.
источник
Я не знаю, редко это или нет, но я, конечно, сделал то же самое.
Как уже указывалось, трудность создания этой части самого языка заключается в том, что класс использует множественное наследование.
источник
Я использую это время от времени. Просто, когда я обнаружу, что пару раз набираю тип базового класса, я заменю его на typedef, похожий на ваш.
Я думаю, что это может быть полезным. Как вы говорите, если ваш базовый класс является шаблоном, он может сохранить типизацию. Кроме того, классы шаблона могут принимать аргументы, которые действуют как политики для того, как шаблон должен работать. Вы можете изменить базовый тип без необходимости исправления всех ссылок на него, пока интерфейс базы остается совместимым.
Я думаю, что использование через typedef уже достаточно. В любом случае я не понимаю, как он будет встроен в язык, потому что множественное наследование означает, что может быть много базовых классов, поэтому вы можете определить его, как считаете нужным для класса, который, по вашему мнению, является наиболее важным базовым классом.
источник
Я пытался решить ту же самую проблему; Я выдвинул несколько идей, таких как использование шаблонов с переменными числами и расширение пакета для учета произвольного числа родителей, но я понял, что это приведет к реализации, подобной 'super0' и 'super1'. Я уничтожил это, потому что это было бы чуть более полезным, чем отсутствие его для начала.
Мое решение включает вспомогательный класс
PrimaryParent
и реализовано так:Тогда какой класс вы хотите использовать, будет объявлен так:
Чтобы избежать необходимости использовать виртуальное наследование в
PrimaryParent
onBaseClass
, конструктор, принимающий переменное число аргументов, используется для построенияBaseClass
.Причина
public
наследованияBaseClass
вPrimaryParent
состоит в том, чтобы предоставитьMyObject
полный контроль над наследованием,BaseClass
несмотря на наличие класса помощника между ними.Это означает, что каждый класс, который вы хотите иметь,
super
должен использоватьPrimaryParent
вспомогательный класс, и каждый дочерний элемент может наследовать только один класс, используяPrimaryParent
(отсюда и имя).Другим ограничением для этого метода является то, что он
MyObject
может наследовать только один класс, от которого он наследуетсяPrimaryParent
, и этот класс должен наследоваться с помощьюPrimaryParent
. Вот что я имею в виду:Прежде чем вы откажетесь от этого в качестве варианта из-за кажущегося количества ограничений и того факта, что между каждым наследованием существует класс среднего уровня, эти вещи не являются плохими.
Множественное наследование является сильным инструментом, но в большинстве случаев будет только один первичный родитель, и, если есть другие родители, они, вероятно, будут классами Mixin или классами, которые не наследуются в
PrimaryParent
любом случае. Если множественное наследование все еще необходимо (хотя во многих ситуациях было бы полезно использовать композицию для определения объекта, а не наследования), чем просто явно определитьsuper
в этом классе и не наследовать отPrimaryParent
.Идея того, чтобы определить
super
в каждом классе не очень привлекательным для меня, используяPrimaryParent
позволяетsuper
, явно основанные Наследование псевдоним, чтобы остаться в определении класса линии вместо тела класса , где данные должны идти.Это может быть только я, хотя.
Конечно, каждая ситуация различна, но учтите, что я сказал, когда решал, какой вариант использовать.
источник
Я не буду много говорить, кроме настоящего кода с комментариями, который демонстрирует, что супер не означает вызов базы!
super != base.
Короче говоря, что означает "супер" в любом случае? а что значит "база"?
Эти 2 правила применяются в классе typedefs.
Рассмотрим разработчика библиотеки и пользователя библиотеки, кто супер, а кто базовый?
Для получения дополнительной информации вот рабочий код для копирования вставьте в вашу IDE:
Еще один важный момент здесь это:
внутри
main()
мы используем полиморфные вызовы downards, которые супер звонки вверх, не очень полезные в реальной жизни, но это демонстрирует разницу.источник
Я использую ключевое слово __super. Но это специфично для Microsoft:
http://msdn.microsoft.com/en-us/library/94dw1w7x.aspx
источник
Это метод, который я использую, который использует макросы вместо typedef. Я знаю, что это не C ++ способ делать вещи, но он может быть удобен, когда цепочки итераторов объединяются посредством наследования, когда только базовый класс, самый дальний по иерархии, действует на унаследованное смещение.
Например:
Общая настройка, которую я использую, позволяет очень легко читать и копировать / вставлять между деревом наследования, которые имеют дублированный код, но должны быть переопределены, потому что тип возвращаемого значения должен соответствовать текущему классу.
Можно использовать строчные буквы,
super
чтобы воспроизвести поведение, наблюдаемое в Java, но мой стиль кодирования - использовать все прописные буквы для макросов.источник