7 Stimmen

Private Vererbung und statische Mitglieder/Typen in C++

Ich versuche zu verhindern, dass eine Klasse ihren "this"-Zeiger in einen Zeiger einer ihrer Schnittstellen umwandeln kann. Dazu verwende ich private Vererbung über eine mittlere Proxyklasse. Das Problem ist, dass ich finde, dass private Vererbung alle öffentlichen statischen Mitglieder und Typen der Basisklasse für alle Klassen unterhalb der vererbenden Klasse in der Hierarchie unzugänglich macht.

class Base
{
public:
    enum Enum
    {
        value
    };
};

class Middle : private Base
{ 
};

class Child : public Middle
{
public:
    void Method()
    {
        Base::Enum e = Base::value; // doesn't compile BAD!     
        Base* base = this; // doesn't compile GOOD!
    }
};

Ich habe dies sowohl in VS2008 (die erforderliche Version) als auch in VS2010 versucht, beide funktionieren nicht.

Fällt jemandem eine Abhilfe ein? Oder einen anderen Ansatz, um die Konvertierung zu stoppen?

Auch ich bin neugierig auf das Verhalten, ist es nur ein Nebeneffekt der Compiler-Implementierung, oder ist es durch Design? Wenn absichtlich, dann warum? Ich dachte immer, dass private Vererbung bedeutet, dass niemand weiß, dass Middle von Base erbt. Das gezeigte Verhalten deutet jedoch darauf hin, dass private Vererbung viel mehr als das bedeutet. Tatsächlich hat Child weniger Zugriff auf Base als jeder Namespace, der nicht in der Klassenhierarchie ist!

6voto

James McNellis Punkte 337231

Sie sollten in der Lage sein, auf Folgendes zuzugreifen Base::Enum indem er sie vollständig qualifiziert:

class Child : public Middle
{
public:
    void Method()
    {
        ::Base::Enum e = ::Base::value;
    }
};

Dies ist das von der Sprache vorgegebene Verhalten (C++03 §11.2/3):

Hinweis: Ein Mitglied einer privaten Basisklasse kann als geerbter Mitgliedsname unzugänglich, aber direkt zugänglich sein.

Es folgt ein erweitertes Beispiel, das Ihrem Beispielcode sehr ähnlich ist.

Es scheint jedoch, dass weder Visual C++ 2008 noch Visual C++ 2010 dies korrekt implementiert, so dass Sie zwar den Typ ::Base::Enum können Sie immer noch nicht auf die ::Base::value . (Tatsächlich scheint Visual C++ eine Menge davon falsch verstanden zu haben, da es Ihnen fälschlicherweise erlaubt, die nicht vollständig qualifizierte Base::Enum ).

Um das Problem zu "umgehen", können Sie using-Deklarationen in die Middle Klasse:

class Middle : private Base
{ 
protected:

    using Base::Enum;
    using Base::value;
};

Dies erlaubt Ihnen nicht die Verwendung von Base::Enum o Base::value in Ihrem Child Klasse, aber es erlaubt Ihnen, eine Enum y value o Middle::Enum y Middle::value .

1voto

Matthieu M. Punkte 266317

Ich habe nur eine Frage: Warum haben Sie überhaupt privat geerbt?

Vererbung ist meiner Meinung nach ein ziemlich kaputtes Konzept, weil es gegen das Prinzip der einen Verantwortung verstößt:

  • erben Sie die Schnittstelle
  • erben Sie die Implementierung

Leider ist die Vererbung für den Polymorphismus in objektorientiertem Code erforderlich, so dass man in diesem Fall nicht davor zurückschrecken kann.

Aber hier wollen Sie ausdrücklich NICHT Polymorphismus verwenden, so dass ich mich frage, warum Sie überhaupt Vererbung verwenden, da dies seine einzige interessante Verwendung ist (imo).

Stattdessen können Sie in C++ verwenden:

  • Komposition, für die Wiederverwendung von Code
  • Freie Funktionen (definiert in ihrem eigenen Namensraum)
  • using , typedef etc... um Objekte von außerhalb der Klasse zu bringen

Ihr Beispiel scheint hier eingeschränkt zu sein, aber auch ich verpacke meine Enums in struct um eine Verschmutzung des Namensraums durch tausend Symbole zu verhindern (und weil struct als Template-Parameter verwendet werden können, was bei Namespaces nicht möglich ist).

struct MyEnum
{
  enum type
  {
    value
  };
};

class Child
{
public:
  typedef MyEnum::type Enum;

  Child(Enum e = MyEnum::value);

private:
};

Ich sehe nichts Falsches daran, den Namen zu qualifizieren, im Gegenteil, ich denke, es macht es einfacher, ihn wieder zu lesen, da man weiß, von welchem Enum wir sprechen...

Wirklich, private Vererbung wird am besten vermieden (und in der Regel durch Komposition ersetzt). Der einzige gültige Fall (imo) ist für Empty Base Optimization... und ehrlich gesagt ist es nicht oft Sie es brauchen (wie üblich mit Optimierungen).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X