Mein Codierungsstil umfasst die folgende Redewendung:
class Derived : public Base
{
public :
typedef Base super; // note that it could be hidden in
// protected/private section, instead
// Etc.
} ;
Dies ermöglicht es mir, "super" als Alias für Base zu verwenden, beispielsweise in Konstruktoren:
Derived(int i, int j)
: super(i), J(j)
{
}
Oder sogar beim Aufrufen der Methode aus der Basisklasse in ihrer überschriebenen Version:
void Derived::foo()
{
super::foo() ;
// ... And then, do something else
}
Es kann sogar verkettet werden (ich muss jedoch noch die Verwendung dafür finden):
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
}
Wie auch immer, ich finde die Verwendung von "typedef super" sehr nützlich, zum Beispiel wenn Base entweder ausführlich und / oder mit Vorlagen versehen ist.
Tatsache ist, dass Super sowohl in Java als auch in C # implementiert ist (wo es "base" heißt, sofern ich mich nicht irre). In C ++ fehlt dieses Schlüsselwort.
Also meine Fragen:
- Ist diese Verwendung von typedef in dem Code, mit dem Sie arbeiten, sehr häufig / selten / nie zu sehen?
- ist diese Verwendung von typedef super Ok (dh sehen Sie starke oder nicht so starke Gründe, es nicht zu verwenden)?
- sollte "super" eine gute Sache sein, sollte es in C ++ etwas standardisiert sein, oder reicht diese Verwendung durch ein typedef bereits aus?
Edit: Roddy erwähnte die Tatsache, dass das typedef privat sein sollte. Dies würde bedeuten, dass eine abgeleitete Klasse sie nicht verwenden kann, ohne sie erneut zu deklarieren. Aber ich denke, es würde auch die Super :: Super-Verkettung verhindern (aber wer wird dafür weinen?).
Edit 2: Nun, einige Monate nachdem ich "super" massiv benutzt habe, stimme ich Roddys Standpunkt voll und ganz zu: "super" sollte privat sein. Ich würde seine Antwort zweimal positiv bewerten, aber ich denke, ich kann nicht.
quelle
super
sieht es so ausJava
und es ist nichts Schlimmes, aber ...C++
unterstützt aber Mehrfachvererbung.MyFirstBase<MyString, MyStruct<MyData, MyValue>>
überall zu schreiben )template <class baz> struct Foo {...void bar() {...} ...}; struct Foo2: Foo<AnnoyinglyLongListOfArguments> { void bar2() { ... Foo::bar(); ...} };
Das hat bei mir mit gcc 9.1 funktioniert --std = c ++ 1y (c ++ 14).Antworten:
Bjarne Stroustrup erwähnt in Design und Evolution von C ++, dass
super
das ISO C ++ - Normungskomitee das erste Mal, als C ++ standardisiert wurde , als Schlüsselwort in Betracht gezogen wurde.Dag Bruck schlug diese Erweiterung vor und nannte die Basisklasse "geerbt". Der Vorschlag erwähnte das Problem der Mehrfachvererbung und hätte mehrdeutige Verwendungen gekennzeichnet. Auch Stroustrup war überzeugt.
Nach der Diskussion schrieb Dag Bruck (ja, dieselbe Person, die den Vorschlag gemacht hat), dass der Vorschlag umsetzbar, technisch einwandfrei und frei von größeren Mängeln sei und mehrere Vererbungen handhabte. Auf der anderen Seite gab es nicht genug Geld, und das Komitee sollte sich mit einem heiklen Problem befassen.
Michael Tiemann kam spät an und zeigte dann, dass ein typisierter Super mit der gleichen Technik, nach der in diesem Beitrag gefragt wurde, gut funktionieren würde.
Also, nein, das wird wahrscheinlich nie standardisiert.
Wenn Sie keine Kopie haben, ist Design and Evolution den Deckungspreis wert. Gebrauchte Exemplare sind für etwa 10 US-Dollar erhältlich.
quelle
typedef
Technik: Sie respektiert DRY nicht. Der einzige Weg wäre, hässliche Makros zu verwenden, um Klassen zu deklarieren. Wenn Sie erben, kann die Basis eine lange Vorlagenklasse mit mehreren Parametern oder noch schlimmer sein. (zB mehrere Klassen) Sie müssten das alles ein zweites Mal umschreiben. Schließlich sehe ich ein großes Problem mit Vorlagenbasen, die Argumente für Vorlagenklassen enthalten. In diesem Fall ist der Super eine Vorlage (und keine Instanziierung einer Vorlage). Welches kann nicht typisiert werden. Auch in C ++ 11 benötigen Sieusing
für diesen Fall.Ich habe immer "geerbt" anstatt super verwendet. (Wahrscheinlich aufgrund eines Delphi-Hintergrunds), und ich mache es immer privat , um das Problem zu vermeiden, wenn das 'geerbte' fälschlicherweise in einer Klasse weggelassen wird, aber eine Unterklasse versucht, es zu verwenden.
Meine Standard-Codevorlage zum Erstellen neuer Klassen enthält das typedef, sodass ich kaum Gelegenheit habe, es versehentlich wegzulassen.
Ich denke nicht, dass der verkettete "super :: super" -Vorschlag eine gute Idee ist. Wenn Sie das tun, sind Sie wahrscheinlich sehr stark an eine bestimmte Hierarchie gebunden, und wenn Sie sie ändern, wird das wahrscheinlich schlecht.
quelle
virtual
wie hier gezeigt deklarierenEin Problem dabei ist, dass, wenn Sie vergessen, Super für abgeleitete Klassen (neu) zu definieren, jeder Aufruf von Super :: Something gut kompiliert wird, aber wahrscheinlich nicht die gewünschte Funktion aufruft.
Beispielsweise:
(Wie Martin York in den Kommentaren zu dieser Antwort hervorhob, kann dieses Problem behoben werden, indem das typedef eher privat als öffentlich oder geschützt gemacht wird.)
quelle
super1
für Base undsuper2
in Derived verwenden? Der DerivedAgain kann beides verwenden?FWIW Microsoft hat in seinem Compiler eine Erweiterung für __super hinzugefügt .
quelle
Super (oder geerbt) ist eine sehr gute Sache, denn wenn Sie eine weitere Vererbungsebene zwischen Base und Derived einfügen müssen, müssen Sie nur zwei Dinge ändern: 1. die "Klasse Base: foo" und 2. die typedef
Wenn ich mich richtig erinnere, erwog das C ++ - Standardkomitee, ein Schlüsselwort dafür hinzuzufügen ... bis Michael Tiemann darauf hinwies, dass dieser typedef-Trick funktioniert.
Was die Mehrfachvererbung betrifft, können Sie, da sie vom Programmierer gesteuert wird, tun, was Sie wollen: vielleicht super1 und super2 oder was auch immer.
quelle
Ich habe gerade eine alternative Problemumgehung gefunden. Ich habe ein großes Problem mit dem typedef-Ansatz, das mich heute gebissen hat:
Also habe ich eine bessere Lösung mit einer sehr einfachen Vorlage gefunden.
Also jetzt statt
du hast
In diesem Fall
BaseAlias
ist es nicht privat und ich habe versucht, mich vor unachtsamer Verwendung zu schützen, indem ich einen Typnamen ausgewählt habe, der andere Entwickler alarmieren soll.quelle
public
Alias ist ein Nachteil, da Sie offen für den Fehler sind, der in Roddys und Kristopher's Antworten erwähnt wird (z. B. können Sie (aus Versehen) vonDerived
statt ableitenMakeAlias<Derived>
)MakeAlias
oder perfekte Weiterleitung kompensiert werden. Sie müssen jedoch auf dieMakeAlias<BaseAlias>
Konstruktoren verweisen, anstatt nurC
direkt auf die Konstruktoren zu verweisen .)Ich erinnere mich nicht, dass ich das vorher gesehen habe, aber auf den ersten Blick gefällt es mir. Wie Ferruccio bemerkt, funktioniert es angesichts von MI nicht gut, aber MI ist eher die Ausnahme als die Regel und es gibt nichts, was besagt, dass etwas überall verwendbar sein muss, um nützlich zu sein.
quelle
Ich habe diese Redewendung in vielen Codes gesehen und bin mir ziemlich sicher, dass ich sie sogar irgendwo in Boosts Bibliotheken gesehen habe. Soweit ich mich erinnere, ist der gebräuchlichste Name jedoch
base
(oderBase
) anstelle vonsuper
.Diese Redewendung ist besonders nützlich, wenn Sie mit Vorlagenklassen arbeiten. Betrachten Sie als Beispiel die folgende Klasse (aus einem realen Projekt ):
Kümmere dich nicht um die lustigen Namen. Der wichtige Punkt hierbei ist, dass die Vererbungskette Typargumente verwendet, um einen Polymorphismus zur Kompilierungszeit zu erzielen. Leider wird die Verschachtelungsebene dieser Vorlagen ziemlich hoch. Abkürzungen sind daher entscheidend für die Lesbarkeit und Wartbarkeit.
quelle
Ich habe es ziemlich oft gesehen, manchmal als super_t, wenn die Basis ein komplexer Vorlagentyp ist (
boost::iterator_adaptor
tut dies zum Beispiel)quelle
Ist diese Verwendung von typedef in dem Code, mit dem Sie arbeiten, sehr häufig / selten / nie zu sehen?
Ich habe dieses spezielle Muster in dem C ++ - Code, mit dem ich arbeite, noch nie gesehen, aber das bedeutet nicht, dass es nicht da draußen ist.
ist diese Verwendung von typedef super Ok (dh sehen Sie starke oder nicht so starke Gründe, es nicht zu verwenden)?
Mehrfachvererbung ist nicht möglich (jedenfalls sauber).
sollte "super" eine gute Sache sein, sollte es in C ++ etwas standardisiert sein, oder reicht diese Verwendung durch ein typedef bereits aus?
Aus dem oben genannten Grund (Mehrfachvererbung), Nr. Der Grund, warum Sie "super" in den anderen von Ihnen aufgelisteten Sprachen sehen, ist, dass sie nur die Einzelvererbung unterstützen, sodass keine Verwirrung darüber besteht, worauf sich "super" bezieht. Zugegeben, in diesen Sprachen ist es nützlich, aber es hat keinen Platz im C ++ - Datenmodell.
Oh, und zu Ihrer Information: C ++ / CLI unterstützt dieses Konzept in Form des Schlüsselworts "__super". Beachten Sie jedoch, dass C ++ / CLI auch keine Mehrfachvererbung unterstützt.
quelle
Ein weiterer Grund für die Verwendung eines typedef für die Oberklasse besteht darin, dass Sie komplexe Vorlagen für die Vererbung des Objekts verwenden.
Zum Beispiel:
In Klasse B wäre es ideal, ein typedef für A zu haben, sonst würden Sie es nicht wiederholen können, wo immer Sie auf die Mitglieder von A verweisen möchten.
In diesen Fällen kann es auch mit Mehrfachvererbung funktionieren, aber Sie hätten kein typedef mit dem Namen 'super', es würde 'base_A_t' oder so ähnlich heißen.
--jeffk ++
quelle
Nachdem ich früher von Turbo Pascal nach C ++ migriert war, habe ich dies getan, um ein Äquivalent für das "geerbte" Schlüsselwort von Turbo Pascal zu erhalten, das auf die gleiche Weise funktioniert. Nachdem ich einige Jahre in C ++ programmiert hatte, hörte ich damit auf. Ich fand, ich brauchte es einfach nicht sehr.
quelle
Ich weiß nicht, ob es selten ist oder nicht, aber ich habe auf jeden Fall das Gleiche getan.
Wie bereits erwähnt, besteht die Schwierigkeit, diesen Teil der Sprache selbst zu erstellen, darin, dass eine Klasse die Mehrfachvererbung verwendet.
quelle
Ich benutze dies von Zeit zu Zeit. Wenn ich den Basisklassentyp ein paar Mal abtippe, werde ich ihn durch einen Typedef ersetzen, der Ihrem ähnlich ist.
Ich denke, es kann eine gute Verwendung sein. Wie Sie sagen, wenn Ihre Basisklasse eine Vorlage ist, kann sie die Eingabe sparen. Vorlagenklassen können auch Argumente annehmen, die als Richtlinien für die Funktionsweise der Vorlage dienen. Sie können den Basistyp ändern, ohne alle Ihre Verweise darauf korrigieren zu müssen, solange die Schnittstelle der Basis kompatibel bleibt.
Ich denke die Verwendung durch das typedef ist schon genug. Ich kann sowieso nicht sehen, wie es in die Sprache eingebaut werden würde, da Mehrfachvererbung bedeutet, dass es viele Basisklassen geben kann. Sie können es also nach Belieben für die Klasse eingeben, die Ihrer Meinung nach die wichtigste Basisklasse ist.
quelle
Ich habe versucht, genau das gleiche Problem zu lösen. Ich habe ein paar Ideen herumgeschmissen, wie die Verwendung variabler Vorlagen und die Packerweiterung, um eine beliebige Anzahl von Eltern zu berücksichtigen, aber mir wurde klar, dass dies zu einer Implementierung wie 'super0' und 'super1' führen würde. Ich habe es weggeworfen, weil das kaum nützlicher wäre, als es von Anfang an nicht zu haben.
Meine Lösung umfasst eine Hilfsklasse
PrimaryParent
und wird folgendermaßen implementiert:Dann wird jede Klasse, die Sie verwenden möchten, als solche deklariert:
Um zu vermeiden, dass die virtuelle Vererbung in
PrimaryParent
on verwendet werden mussBaseClass
, wird ein Konstruktor verwendet, der eine variable Anzahl von Argumenten verwendet, um die Konstruktion von zu ermöglichenBaseClass
.Der Grund für die
public
Vererbung vonBaseClass
intoPrimaryParent
besteht darin,MyObject
die volle Kontrolle über die Vererbung von in zu haben,BaseClass
obwohl eine Helferklasse zwischen ihnen besteht.Dies bedeutet, dass jede Klasse, die Sie haben möchten, die
super
Hilfsklasse verwenden mussPrimaryParent
und jedes Kind nur von einer Klasse mit erben darfPrimaryParent
(daher der Name).Eine weitere Einschränkung für diese Methode besteht darin, dass
MyObject
nur eine KlassePrimaryParent
geerbt werden kann, von der geerbt wird, und dass eine Klasse mit geerbt werden mussPrimaryParent
. Folgendes meine ich:Bevor Sie dies aufgrund der scheinbaren Anzahl von Einschränkungen und der Tatsache, dass es zwischen jeder Erbschaft eine Mittelklasse gibt, als Option verwerfen, sind diese Dinge nicht schlecht.
Mehrfachvererbung ist ein starkes Werkzeug, aber in den meisten Fällen gibt es nur einen Hauptelternteil, und wenn es andere Elternteile gibt, handelt es sich wahrscheinlich um Mixin-Klassen oder Klassen, die
PrimaryParent
sowieso nicht erben . Wenn immer noch eine Mehrfachvererbung erforderlich ist (obwohl in vielen Situationen die Verwendung der Komposition zum Definieren eines Objekts anstelle der Vererbung von Vorteil wäre), definieren Siesuper
diese Klasse nur explizit und erben Sie nicht vonPrimaryParent
.Die Idee, zu definieren ,
super
in jeder Klasse für mich nicht sehr ansprechend, mitPrimaryParent
ermöglichtsuper
, eindeutig ein inheritence basierte alias, in der Klassendefinition Linie zu bleiben , anstatt die Klasse Körper , wo die Daten gehen.Das könnte aber nur ich sein.
Natürlich ist jede Situation anders, aber berücksichtigen Sie diese Dinge, die ich gesagt habe, wenn Sie sich für eine Option entscheiden.
quelle
Ich werde nicht viel sagen, außer den vorliegenden Code mit Kommentaren, die zeigen, dass Super nicht bedeutet, Base anzurufen!
super != base.
Kurz gesagt, was soll "super" überhaupt bedeuten? und was soll dann "base" bedeuten?
Diese beiden Regeln gelten für Typedefs in Klassen.
Betrachten Sie den Bibliotheksimplementierer und den Bibliotheksbenutzer, wer ist super und wer ist die Basis?
Für weitere Informationen finden Sie hier den Arbeitscode zum Kopieren und Einfügen in Ihre IDE:
Ein weiterer wichtiger Punkt hier ist:
Im Inneren verwenden
main()
wir polymorphe Call Downards, die nach oben rufen, im wirklichen Leben nicht wirklich nützlich, aber den Unterschied demonstrieren.quelle
Ich benutze das Schlüsselwort __super. Aber es ist Microsoft-spezifisch:
http://msdn.microsoft.com/en-us/library/94dw1w7x.aspx
quelle
Dies ist eine Methode, die ich verwende und die Makros anstelle eines typedef verwendet. Ich weiß, dass dies nicht die C ++ - Methode ist, aber es kann praktisch sein, wenn Iteratoren durch Vererbung miteinander verkettet werden, wenn nur die Basisklasse, die am weitesten unten in der Hierarchie liegt, auf einen geerbten Offset einwirkt.
Beispielsweise:
Das generische Setup, das ich verwende, erleichtert das Lesen und Kopieren / Einfügen zwischen dem Vererbungsbaum, der doppelten Code enthält, aber überschrieben werden muss, da der Rückgabetyp mit der aktuellen Klasse übereinstimmen muss.
Man könnte Kleinbuchstaben verwenden,
super
um das in Java beobachtete Verhalten zu replizieren, aber mein Codierungsstil besteht darin, alle Großbuchstaben für Makros zu verwenden.quelle