[C++] Echte private Methoden und Implementierungen

Hier können Artikel, Tutorials, Bücherrezensionen, Dokumente aller Art, Texturen, Sprites, Sounds, Musik und Modelle zur Verfügung gestellt bzw. verlinkt werden.
Forumsregeln
Möglichst sinnvolle Präfixe oder die Themensymbole nutzen.
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [C++] Echte private Methoden und Implementierungen

Beitrag von CodingCat »

Nochn Muster. Statische Interfaces (keine Daten in der öffentlichen Schnittstelle) mit nur einer Implementierung:

Code: Alles auswählen

// header (*.h)
class pimpl_interface
{
   // delete assignment operator
   pimpl_interface& operator =(const pimpl_interface&); // C++11: = delete;
public:
   virtual ~pimpl_interface() { }
};

class foo : public pimpl_interface
{
   // hide constructors to block alternative implementations via inheritance
   foo() { }
   foo(const foo&) { }
public:
   // allow for one internal implementation
   class M;
   // public methods
   void publicMethod();
};

std::unique_ptr<foo> createFoo(...);

// implementation (*.cpp)
class foo::M : public foo
{
   // attributes
   int i;

   // private methods
   void privateMethod()
   {
      ++i;
   }
};

// public methods
void foo::publicMethod()
{
    M &m = static_cast<M&>(*this);
    m.privateMethod();
    ++m.i;
}

std::unique_ptr<foo> createFoo(...)
{
   return unique_ptr<foo>( new foo::M(...) );
}
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
joggel

Re: [C++] Echte private Methoden und Implementierungen

Beitrag von joggel »

Was ist diese Klasse "M"?

[Nachtrag]
Ich habe leider nicht ganz den gesamten Thread hier mitverfolgt... wäre also möglich, das sich die Frage da beantwortet hätte.
Aber private Methoden/Member sind ja dafür da, dass sie nicht von außen benutzt werden können.
Wieso also nochmal extra "verstecken"?

Gruß
Zuletzt geändert von joggel am 21.10.2012, 19:00, insgesamt 1-mal geändert.
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [C++] Echte private Methoden und Implementierungen

Beitrag von CodingCat »

Die implementierende Klasse, die Daten und private Funktionalität enthält. foo::M ist die einzige Klasse, die von foo erben darf, weil alle foo-Konstruktoren privat sind und somit nur die innere Klasse M darauf Zugriff hat. Deshalb ist jede foo-Instanz mit Sicherheit auch eine foo::M-Instanz und der Cast zur Implementierung durch static_cast<M&>(*this) ist sicher.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [C++] Echte private Methoden und Implementierungen

Beitrag von CodingCat »

joggel hat geschrieben: [Nachtrag]
Ich habe leider nicht ganz den gesamten Thread hier mitverfolgt... wäre also möglich, das sich die Frage da beantwortet hätte.
Aber private Methoden/Member sind ja dafür da, dass sie nicht von außen benutzt werden können.
Wieso also nochmal extra "verstecken"?
Damit sie nicht in den Headers deklariert werden müssen und so für alle einbindenden Module unnötige Abhängigkeiten und Rebuilds verursachen.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
joggel

Re: [C++] Echte private Methoden und Implementierungen

Beitrag von joggel »

CodingCat hat geschrieben:
joggel hat geschrieben: [Nachtrag]
Ich habe leider nicht ganz den gesamten Thread hier mitverfolgt... wäre also möglich, das sich die Frage da beantwortet hätte.
Aber private Methoden/Member sind ja dafür da, dass sie nicht von außen benutzt werden können.
Wieso also nochmal extra "verstecken"?
Damit sie nicht in den Headers deklariert werden müssen und so für alle einbindenden Module unnötige Abhängigkeiten und Rebuilds verursachen.
Ah, okay. Ja, das macht sinn ^^
Benutzeravatar
Krishty
Establishment
Beiträge: 8413
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Echte private Methoden und Implementierungen

Beitrag von Krishty »

joggel hat geschrieben:Wieso also nochmal extra "verstecken"?
Es gibt bestimmte Sachen, die man auch mit private nicht verstecken kann – z.B. kannst du mit sizeof(Foo) die Größe einer Klasse Foo inklusive ihrer privaten Attribute ermitteln. Dadurch entstehen implizit Abhängigkeiten im Rest des Quelltextes – z.B., dass eine umgebende Klasse, die Foo als Attribut enthält, ebenfalls neu kompiliert werden muss, wenn sich Foo ändert. Am deutlichsten ist das bei den #includes, wenn Foo bspw. eine Liste als Attribut hat: Dann muss jeder, der Foo benutzt, auch <list> #includen, obwohl das als Implementierungsdetail von Foo versteckt sein sollte. Cat versucht hier, tatsächlich 100-prozentige Entkopplung zu erreichen, wo absolut nichts einer Implementierung nach außen dringt.

(Ja zu spät aber fertiggetippt war es zu schade zum Wegschmeißen.)
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [C++] Echte private Methoden und Implementierungen

Beitrag von CodingCat »

Ganz genau.

Im Übrigen zeige ich die Muster hier unsystematisiert und in Reinform. In meinem eigenen Quelltext bin ich längst mit einem Rudel Makros auf Qt-Niveau angekommen. Obiges Beispiel eines statischen Interfaces sähe hier in etwa so aus:

Code: Alles auswählen

// header (*.h)
class LEAN_INTERFACE foo
{
   LEAN_SHARED_STATIC_INTERFACE_BEHAVIOR(foo)

public:
   // allow for one internal implementation
   class M;
   // public methods
   void publicMethod();
};

std::unique_ptr<foo> createFoo(...);

// implementation (*.cpp)
class foo::M : public foo
{
   // attributes
   int i;

   // private methods
   void privateMethod()
   {
      LEAN_SIMPL_M
      ++m.i;
   }
};

// public methods
void foo::publicMethod()
{
    LEAN_SIMPL_M
    m.privateMethod();
    ++m.i;
}

std::unique_ptr<foo> createFoo(...)
{
   return unique_ptr<foo>( new foo::M(...) );
}
Damit bin ich zwar fernab reinen C++, dafür habe ich ein besseres Gewissen bei den Abhängigkeiten. ;)

Makros:

Code: Alles auswählen

/// Reduces overhead for purely virtual classes.
#define LEAN_INTERFACE __declspec(novtable)

/// Makes the given class behave like an interface.
#define LEAN_INTERFACE_BEHAVIOR(name) \
		protected: \
			LEAN_INLINE name& operator =(const name&) { return *this; }  \
			LEAN_INLINE ~name() { } \
		private:

/// Makes the given class behave like an interface supporting shared ownership.
#define LEAN_SHARED_INTERFACE_BEHAVIOR(name) \
		public: \
			virtual ~name() { } \
		protected: \
			LEAN_INLINE name& operator =(const name&) { return *this; }  \
		private:

/// Makes the given class behave like a static interface.
#define LEAN_STATIC_INTERFACE_BEHAVIOR(name) LEAN_INTERFACE_BEHAVIOR(name) \
		private: \
			LEAN_INLINE name() { } \
			LEAN_INLINE name(const name&) { }  \
		private:

/// Makes the given class behave like a static interface supporting shared ownership.
#define LEAN_SHARED_STATIC_INTERFACE_BEHAVIOR(name) LEAN_SHARED_INTERFACE_BEHAVIOR(name) \
		private: \
			LEAN_INLINE name() { } \
			LEAN_INLINE name(const name&) { }  \
		private:


#define LEAN_SIMPL(t, m) t &m = static_cast<t&>(*this);
#define LEAN_SIMPL_M LEAN_SIMPL(M, m)
#define LEAN_SIMPL_CM LEAN_SIMPL(const M, m)
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
joggel

Re: [C++] Echte private Methoden und Implementierungen

Beitrag von joggel »

Code: Alles auswählen

// public methods
void foo::publicMethod()
{
    M &m = static_cast<M&>(*this);
    m.privateMethod();
    ++m.i;
}
Wieso funktioniert das denn?
unter welchen C++-Standard? C++11?

Krishty hat geschrieben: Es gibt bestimmte Sachen, die man auch mit private nicht verstecken kann – z.B. kannst du mit sizeof(Foo) die Größe einer Klasse Foo inklusive ihrer privaten Attribute ermitteln. Dadurch entstehen implizit Abhängigkeiten im Rest des Quelltextes – z.B., dass eine umgebende Klasse, die Foo als Attribut enthält, ebenfalls neu kompiliert werden muss, wenn sich Foo ändert. Am deutlichsten ist das bei den #includes, wenn Foo bspw. eine Liste als Attribut hat: Dann muss jeder, der Foo benutzt, auch <list> #includen, obwohl das als Implementierungsdetail von Foo versteckt sein sollte. Cat versucht hier, tatsächlich 100-prozentige Entkopplung zu erreichen, wo absolut nichts einer Implementierung nach außen dringt.
Achso.. ja stimmt. Wird mir jetzt klar, also fast.
Das überrascht mich:
...inklusive ihrer privaten Attribute ermitteln
Aber sowas ginge ja auch, oder?

Code: Alles auswählen

// header (*.h)
class ImplClass;
class AClass
{
private:
 ImplClass* mImpl;
public:
 AClass(...)
 ~AClass()
 TypA FuncA();
 TypB FuncB();
 ...
}

Code: Alles auswählen

// implementation (*.cpp)
#include "ImplClass"

 AClass::AClass(...)
{
 mImpl = new ImplClass(...)
}
...
TypA AClass::FuncA()
{
 return mImpl->funcA();
}
...
Zuletzt geändert von joggel am 21.10.2012, 20:24, insgesamt 1-mal geändert.
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [C++] Echte private Methoden und Implementierungen

Beitrag von CodingCat »

joggel hat geschrieben:

Code: Alles auswählen

// public methods
void foo::publicMethod()
{
    M &m = static_cast<M&>(*this);
    m.privateMethod();
    ++m.i;
}
Wieso funktioniert das denn? unter welchen C++-Standard? C++11?
Unter jedem mir bekannten Standard und jedem mir bekannten Compiler. Das ist nichts weiter als ein normaler Downcast. Womit hast du Probleme?
joggel hat geschrieben:Das überrascht mich:
...inklusive ihrer privaten Attribute ermitteln
Schon wenn du eine Instanz via Foo foo; anlegst muss die Größe von foo bekannt sein. Das schließt selbstverständlich sämtliche Attribute mit ein. Oder willst du auf etwas anderes hinaus?
joggel hat geschrieben:Aber sowas ginge ja auch, oder? ...
Ja, das ist das klassische PImpl-Muster, wenn auch suboptimal umgesetzt. Mehr dazu auf Herb Sutters Blog und im Eingangspost dieses Threads.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
joggel

Re: [C++] Echte private Methoden und Implementierungen

Beitrag von joggel »

CodingCat hat geschrieben:
joggel hat geschrieben:

Code: Alles auswählen

// public methods
void foo::publicMethod()
{
    M &m = static_cast<M&>(*this);
    m.privateMethod();
    ++m.i;
}
Wieso funktioniert das denn? unter welchen C++-Standard? C++11?
Unter jedem mir bekannten Standard und jedem mir bekannten Compiler. Das ist nichts weiter als ein normaler Downcast. Womit hast du Probleme?
Das man auf private Methoden der Instanz dieser Klasse M zugreifen kann.

CodingCat hat geschrieben:
joggel hat geschrieben:Das überrascht mich:
...inklusive ihrer privaten Attribute ermitteln
Schon wenn du eine Instanz via Foo foo; anlegst muss die Größe von foo bekannt sein. Das schließt selbstverständlich sämtliche Attribute mit ein. Oder willst du auf etwas anderes hinaus?
Achso.. hatte ich falsch verstanden. Letztendlich hat man nur die Größe der privaten Attribute im Gesamten. Was dann das für welche sind ja nicht... hatte das aber irgendwie so interpretiert.
CodingCat hat geschrieben:
joggel hat geschrieben:Aber sowas ginge ja auch, oder? ...
Ja, das ist das klassische PImpl-Muster, wenn auch suboptimal umgesetzt. Mehr dazu auf Herb Sutters Blog und im Eingangspost dieses Threads.
Jo danke. werd mir das mal durchlesen.
Zuletzt geändert von joggel am 21.10.2012, 20:09, insgesamt 1-mal geändert.
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [C++] Echte private Methoden und Implementierungen

Beitrag von CodingCat »

joggel hat geschrieben:
CodingCat hat geschrieben:
joggel hat geschrieben:

Code: Alles auswählen

// public methods
void foo::publicMethod()
{
    M &m = static_cast<M&>(*this);
    m.privateMethod();
    ++m.i;
}
Wieso funktioniert das denn? unter welchen C++-Standard? C++11?
Unter jedem mir bekannten Standard und jedem mir bekannten Compiler. Das ist nichts weiter als ein normaler Downcast. Womit hast du Probleme?
Dass man auf private Methoden der Instanz dieser Klasse M zugreifen kann.
Aha! Sehr guter Einwand. Weil ich mir bei Modulinterna ohnehin keine Gedanken um Sichtbarkeit mache (sprich intern alles public), habe ich dieses Detail tatsächlich übersehen. Eigentlich hatte ich auch erwartet, dass äußere Klassen auf innere genauso Vollzugriff haben wie innere auf äußere, dem ist aber tatsächlich nicht so. Also entweder modulintern Attribute nicht verstecken, oder in der inneren Klasse ein friend class Foo; hinzufügen.
joggel hat geschrieben:
CodingCat hat geschrieben: Schon wenn du eine Instanz via Foo foo; anlegst muss die Größe von foo bekannt sein. Das schließt selbstverständlich sämtliche Attribute mit ein. Oder willst du auf etwas anderes hinaus?
Achso.. hatte ich falsch verstanden. Letztendlich hat man nur die Größe der privaten Attribute im Gesamten. Was dann das für welche sind ja nicht... hatte das aber irgendwie so interpretiert.
Genau. Das macht nur leider in Bezug auf Abhängigkeiten keinen Unterschied, weil zur Berechnung der Gesamtgröße de facto der vollständige Typ eines jeden Attributs bekannt sein muss.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
joggel

Re: [C++] Echte private Methoden und Implementierungen

Beitrag von joggel »

btw:
Ich fing ja an, mir schon Klassen-Diagramme zu malen, und hatte da ziemliche Probleme das darzustellen mit so einer internen Klasse.
Dafür gibts ja keine Klassen-Diagramm-Konvention... oder?
Benutzeravatar
RustySpoon
Establishment
Beiträge: 298
Registriert: 17.03.2009, 13:59
Wohnort: Dresden

Re: [C++] Echte private Methoden und Implementierungen

Beitrag von RustySpoon »

joggel hat geschrieben:btw:
Ich fing ja an, mir schon Klassen-Diagramme zu malen, und hatte da ziemliche Probleme das darzustellen mit so einer internen Klasse.
Dafür gibts ja keine Klassen-Diagramm-Konvention... oder?
Doch, doch (ganz unten): http://www.sparxsystems.com.au/resource ... agram.html
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [C++] Echte private Methoden und Implementierungen

Beitrag von CodingCat »

Das Verpacken von Members in eine interne struct M { members... } m; hat den netten Nebeneffekt, dass sich Kopierkonstruktion auch vor C++11 explizit außerhalb der Klasse defaulten lässt:

Code: Alles auswählen

class Foo {
   struct M {
      int a;
      std::string b;
   } m;

public:
   Foo(const Foo &right);
};

Foo::Foo(const Foo &right)
   : m(right.m) { }
Mein Code - mein Schlachtfeld.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
starvald
Beiträge: 31
Registriert: 16.04.2010, 17:20
Wohnort: Heppenheim

Re: [C++] Echte private Methoden und Implementierungen

Beitrag von starvald »

CodingCat hat geschrieben: Leider gibt es Fälle, in denen die Einzelübergabe privater Attribute an private Funktionen alleine aufgrund der großen Attributanzahl äußerst mühsam und damit unpraktikabel wird. In diesem Fall kann auf eine verschachtelte Attributstruktur zurückgegriffen werden, deren Typ öffentlich zugänglich, die Instanz selbst jedoch privat ist:

Code: Alles auswählen

// header (*.h)
class foo
{
public:
   foo(...);

   // public methods
   void publicMethod();

   struct M
   {
      // attributes
      int sth;
      int sthElse;

      M(...);
   };

private:
   M m;
};

// implementation (*.cpp)
foo::M::M(...)
   : sth(0),
   sthElse(1)
{
   // consistent member access
   M &m = *this;
   m.sth = ...;
   // ...
}

foo::foo(...)
   : m(...)
{
}

// private methods
void privateMethod(foo::M &m)
{
    m.sth = ...;
}

// public methods
void foo::publicMethod()
{
    privateMethod(m);
    m.sthElse = ...;
}
Hallo,

ich habe eine Frage zu diesem Ansatz: Welchen Grund gibt es, dass die Member-Struct öffentlich zugänglich ist? Warum nicht protected oder private?

Gruß,
Starvald
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [C++] Echte private Methoden und Implementierungen

Beitrag von CodingCat »

Damit sich private Methoden "tatsächlich privat", also rein modulintern, als freie Funktionen definieren lassen (siehe void privateMethod(foo::M &m)). Alles andere würde die Deklaration dieser freien Funktionen als friends im Header erfordern, womit jeglicher Vorteil zunichte wäre, denn dann ließen sich mit weniger Umstand auch einfach direkt private Methoden verwenden.

Im Übrigen schadet das wenig, denn das Attribut selbst ist wieder private. Die Klasse hat es also nach wie vor selbst in der Hand, an wen sie die Interna rausgibt.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
starvald
Beiträge: 31
Registriert: 16.04.2010, 17:20
Wohnort: Heppenheim

Re: [C++] Echte private Methoden und Implementierungen

Beitrag von starvald »

CodingCat hat geschrieben:Damit sich private Methoden "tatsächlich privat", also rein modulintern, als freie Funktionen definieren lassen (siehe void privateMethod(foo::M &m)). Alles andere würde die Deklaration dieser freien Funktionen als friends im Header erfordern, womit jeglicher Vorteil zunichte wäre, denn dann ließen sich mit weniger Umstand auch einfach direkt private Methoden verwenden.

Im Übrigen schadet das wenig, denn das Attribut selbst ist wieder private. Die Klasse hat es also nach wie vor selbst in der Hand, an wen sie die Interna rausgibt.
Besten Dank an Dich und das beste Forum überhaupt! :-) Ich setze diesen Thread übr. gerade in einer Firma um und muss diese "unkonventionelle" Art und Weise des Programmierens rechtfertigen.
Antworten