Sichtbarkeit von privat geerbten typedefs zu verschachtelten Klassen

8

Im folgenden Beispiel (Entschuldigung für die Länge) habe ich versucht, einige unerwartete Verhaltensweisen zu isolieren, die ich bei der Verwendung verschachtelter Klassen innerhalb einer Klasse, die privat von einer anderen Klasse erbt, festgestellt habe. Ich habe oft Aussagen darüber gesehen, dass es im Vergleich zu einer nicht verschachtelten Klasse nichts Besonderes an einer geschachtelten Klasse gibt, aber in diesem Beispiel kann man sehen, dass eine verschachtelte Klasse (zumindest gemäß GCC 4.4) die public typedefs von a sehen kann Klasse, die von der schließenden Klasse privat geerbt wird.

Ich schätze, dass Typdefs nicht dasselbe sind wie Mitgliederdaten, aber ich fand dieses Verhalten überraschend, und ich stelle mir viele andere auch vor. Also meine Frage ist zweifach:

  1. Ist das Standardverhalten? (Eine anständige Erklärung, warum wäre sehr hilfreich)
  2. Kann man erwarten, dass es bei den meisten modernen Compilern funktioniert (d. h. wie tragbar ist es)?
%Vor%     
beldaz 10.03.2010, 23:35
quelle

5 Antworten

4

Vorwort: In der folgenden Antwort verweise ich auf einige Unterschiede zwischen C ++ 98 und C ++ 03. Es stellt sich jedoch heraus, dass die Änderung, über die ich spreche, es noch nicht in den Standard gebracht hat, also unterscheidet sich C ++ 03 in dieser Hinsicht nicht wirklich von C ++ 98 (Danke an Johannes, dass er darauf hingewiesen hat). Irgendwie war ich mir sicher, dass ich es in C ++ 03 gesehen habe, aber in Wirklichkeit ist es nicht da. Allerdings gibt es das Problem tatsächlich (siehe die DR-Referenz in Johannes Kommentar) und einige Compiler implementieren bereits, was sie wahrscheinlich die vernünftigste Lösung dieses Problems betrachten. Daher sind die Verweise auf C ++ 03 im folgenden Text nicht korrekt. Bitte interpretieren Sie die Verweise auf C ++ 03 als Verweise auf einige hypothetische, aber sehr wahrscheinliche zukünftige Spezifikationen dieses Verhaltens, die einige Compiler bereits zu implementieren versuchen.

Es ist wichtig zu beachten, dass die Zugriffsrechte für verschachtelte Klassen zwischen C ++ 98 und C ++ 03 Standards erheblich geändert wurden.

Die verschachtelte Klasse in C ++ 98 hatte keine besonderen Zugriffsrechte auf die Member der umschließenden Klasse. Es war im Grunde völlig unabhängige Klasse, nur im Rahmen der eingeschlossenen Klasse deklariert. Es konnte nur auf public Member der umschließenden Klasse zugreifen.

In C ++ 03 erhielt die geschachtelte Klasse Zugriffsrechte für die Mitglieder der einschließenden Klasse als Mitglied der einschließenden Klasse. Genauer gesagt erhielt die geschachtelte Klasse dieselben Zugriffsrechte wie eine statische Memberfunktion der umschließenden Klasse. I.e. Jetzt kann die verschachtelte Klasse auf beliebige Mitglieder der einschließenden Klasse zugreifen, einschließlich private Einsen.

Aus diesem Grund können Sie die Unterschiede zwischen verschiedenen Compilern und Versionen desselben Compilers beobachten, je nachdem wann sie die neue Spezifikation implementiert haben.

Natürlich müssen Sie daran denken, dass ein Objekt der verschachtelten Klasse in keiner Weise an ein bestimmtes Objekt der einschließenden Klasse gebunden ist. Was die tatsächlichen Objekte angeht, sind dies zwei unabhängige Klassen. Um auf die nicht statischen Datenelemente oder Methoden der einschließenden Klasse von der verschachtelten Klasse zuzugreifen, müssen Sie ein spezifisches Objekt der einschließenden Klasse haben. Mit anderen Worten verhält sich die verschachtelte Klasse wieder wie eine statische Member-Funktion der einschließenden Klasse: Sie hat keinen spezifischen this -Zeiger für die umschließende Klasse, auf den sie nicht zugreifen kann die nicht statischen Member der einschließenden Klasse, es sei denn, Sie bemühen sich, ihr ein spezifisches Objekt der umschließenden Klasse für den Zugriff zu geben. Ohne es kann die geschachtelte Klasse nur auf Typdef-Namen, Enums und statische Member der einschließenden Klasse zugreifen.

Ein einfaches Beispiel, das den Unterschied zwischen C ++ 98 und C ++ 03 veranschaulicht, könnte wie folgt aussehen

%Vor%

Diese Änderung ist genau das, was es Ihrer PrivDerived::Nested::fred -Funktion ermöglicht, zu kompilieren. Es würde Kompilation in einem pedantischen C ++ 98 Compiler nicht bestehen.

    
AnT 11.03.2010, 00:13
quelle
2

Kurze Antwort: Geschachtelte Klassen haben Zugriff auf das private Member der enthaltenen Klassen in C ++ 0x, aber nicht in C ++ 1998 und C ++ 2003. Es ist jedoch legal für C ++ 98 und C ++ 2003 Compiler unterstützen das C ++ 0x-Verhalten, da das alte Verhalten als ein Fehler gilt.

In den C ++ 98 und 2003 Standards Abschnitt 11.8.1 hieß es:

  

Die Mitglieder einer geschachtelten Klasse haben keine   spezieller Zugang zu Mitgliedern eines   umschließende Klasse, noch zu Klassen oder   Funktionen, die Freundschaft gewährt haben   zu einer einschließenden Klasse; das Übliche   Zugangsregeln (Ziffer 11) sein   gehorcht. Die Mitglieder eines Einschließenden   Klasse haben keinen besonderen Zugang zu   Mitglieder einer verschachtelten Klasse; das Übliche   Zugangsregeln (Ziffer 11) sein   gehorcht.

C ++ 0x Abschnitt 11.8.1 sagt:

  

Eine verschachtelte Klasse ist ein Mitglied und als solches   hat die gleichen Zugriffsrechte wie alle anderen   anderes Mitglied. Die Mitglieder eines   umschließende Klasse haben keinen speziellen Zugriff   zu Mitgliedern einer geschachtelten Klasse; das   übliche Zugangsregeln (Ziffer 11)   befolgt werden.

Kernsprachefehlerbericht 45 zeigt, dass das ursprüngliche Verhalten war als Fehler betrachtet, ist es für Nicht-C ++ 0x-Compiler zulässig, das neue Verhalten auch zu unterstützen, obwohl dies nicht erforderlich ist.

    
catphive 24.12.2010 20:09
quelle
1

Gemäß dem Standard:

  

9.2 Klassenmitglieder

     

1 [...] Mitglieder einer Klasse sind Datenelemente, Elementfunktionen (9.3), verschachtelte Typen,   und Enumeratoren. Datenelemente und Elementfunktionen sind statisch oder nicht statisch; siehe 9.4.Gesteuerte Typen sind   Klassen (9.1, 9.7) und Aufzählungen (7.2), die in der Klasse definiert sind, und beliebige Typen, die von Benutzern als Mitglieder deklariert werden   einer typedef-Deklaration (7.1.3).

Um Ihre Fragen zu beantworten:

  
  1. Ist das Standardverhalten? (Eine anständige Erklärung, warum es so sein sollte   sehr hilfreich)
  2.   

Nein. Zumindest mit dem typedef s ist nicht erreichbar. Beachten Sie jedoch Folgendes:

%Vor%

ist problematisch. Die geschachtelte Klasse verfügt weder über eine Instanz von PubDerived noch über das% member-Objekt pub a static .

  
  1. Kann man erwarten, dass es bei den meisten modernen Compilern funktioniert (d. h. wie   tragbar ist es)?
  2.   

Ja. Überprüfen Sie jedoch die Dokumentation auf Einhaltung der Standards. Und immer: Probieren Sie mit einigen Compilern wie Comeau im strikten Modus aus.

    
dirkgently 10.03.2010 23:53
quelle
1

Ich habe mein Bestes getan, um alle relevanten Klauseln aus der ISO / IEC 14882: 1997 zusammenzustellen.

Abschnitt 9.7:

  

Eine in einem anderen definierte Klasse wird als verschachtelte Klasse bezeichnet. Der Name einer verschachtelten Klasse ist lokal für die einschließende Klasse. Die verschachtelte Klasse befindet sich im Bereich ihrer einschließenden Klasse. Außer mit expliziten Zeigern, Verweisen und Objektnamen können Deklarationen in einer geschachtelten Klasse nur Typnamen , statische Member und Enumeratoren der einschließenden Klasse verwenden.

11.2.1 (sollte ziemlich offensichtlich sein):

  

[...] Wenn eine Klasse mit dem privaten Zugriffsspezifizierer als Basisklasse für eine andere Klasse deklariert wird, sind die öffentlichen und geschützten Mitglieder der Basisklasse als private Mitglieder der abgeleiteten Klasse zugänglich.

9.9 Verschachtelte Typennamen:

  

Typnamen gehorchen genau denselben Bereichsregeln wie andere Namen.

Dann in 11.8:

  

Die Mitglieder einer geschachtelten Klasse haben keinen speziellen Zugang zu Mitgliedern einer einschließenden Klasse oder zu Klassen oder Funktionen, die einer einschließenden Klasse Freundschaft gewährt haben; die üblichen Zugangsregeln (11) sind einzuhalten. Die Member einer umschließenden Klasse haben keinen speziellen Zugriff auf Member einer verschachtelten Klasse. die üblichen Zugangsregeln (11) sind einzuhalten.

Daraus entnehme ich, dass das Verhalten, das Sie erleben, nicht standard ist. Die geschachtelte Klasse sollte keinen "speziellen" Zugriff auf das private Mitglied der Basis haben.

Allerdings hat Comeau C ++, das die beste Standardunterstützung zu haben scheint, das gleiche Verhalten wie GCC (erlaubt fred , erlaubt bar nicht mit "error: type" Base :: priv_t "(erklärt in Zeile 4) ist nicht zugänglich ").

    
p00ya 10.03.2010 23:55
quelle
0

Dies beantwortet Ihre Frage nicht, aber nach meiner Lektüre von C ++ FAQ Lite 24.6 was Sie versuchen, ist nicht erlaubt. Ich bin mir nicht sicher, warum gcc das erlaubt; Hast du es auch in anderen Compilern versucht?

    
fbrereto 10.03.2010 23:54
quelle