Constructor in class ohne Namen
-
Ich hätte da mal eine Frage. Wie kann ich dieser class einen Constructor geben:
class{ int i; public: //brauch Constructor hier }a;
Desweiteren würde es mich interessiren wie man nicht inline Funktion in so eine class bastelt. Und dann hätte ich noch ein Problem für das ich zwar eine Lösung habe allerdings mich frage ob es eine bessere gibt. Wenn ich nun meine namenlose class in ein Header packe und dieser dann in 2 cpp Dateien inkludire hab ich zwei Instances von a (eine in jeder Datei). Nun will ich aber, dass ich nur eine habe. Also für den Moment löse ich das Problem so:
In den Header kommt:#ifndef A extern #endif class{ int i; public: //brauch Constructor hier }a;
und dann definire ich A nur in einer Datei. Allerdings will ich wissen ob man das nicht vielleicht anderes lösen könnte.
-
wozu brauchst du eine Klasse ohne Namen?
-
Du willst anscheinend das Singleton-Pattern implementieren.
Das geht aber auch einfacher.z.B. so:
class A { private: A(); ~A(); A(const A&); A& operator=(const A&); public: static A& TheOneAndOnly() { static A a; return a; } };
Dann kannst du ohne Probleme eine Cpp-Datei mit der Implementierung dieser Klasse erstellen.
Das einzige Objekt dieser Klasse erhälst du so:void foo() { A::TheOneAndOnly().machWas(); A& a = A::TheOneAndOnly(); a.machMehr(); }
-
Du willst anscheinend das Singleton-Pattern implementieren.
Das geht aber auch einfacher.Ja das klappt aber dann hab ich einen zusätzlichen Typ und eigentlich wollte ich das vermeiden aber wenn es nicht anders geht bleibt mir wohl nicht viel anderes übrig. Danke für deine Antwort.
-
Du hast auch mit deiner Methode einen zusätzlichen Typ erzeugt, nur halt einen namenlosen.
Warum diese unbegründete Angst vor neuen Typen?
Klassen schaden niemandem. Falls es Kollisionen geben sollte gibt es immer noch namespaces.
-
Wie kann ich dieser class einen Constructor geben
Gar nicht. Unbenannte Klassen dürfen keine Konstruktoren besitzen.
Desweiteren würde es mich interessiren wie man nicht inline Funktion in so eine class bastelt
Gar nicht. Unbenannte Klassen können weder statische Elemente noch out-of-line Memberfunktionen besitzen.
Wenn ich nun meine namenlose class in ein Header packe und dieser dann in 2 cpp Dateien inkludire hab ich zwei Instances von a (eine in jeder Datei).
Nö. Solange du die Instanz nicht mit static qualifiziert hast, ist die Instanz extern. Du hast also eine ODR-Verletzung, nicht zwei Instanzen.
-
Warum diese unbegründete Angst vor neuen Typen?
Klassen schaden niemandem. Falls es Kollisionen geben sollte gibt es immer noch namespaces.Ich habe mich halt nur gefragt ob es geht ohne die Klasse verstecken zu müssen. Aber trotzdem danke für deine Antwort.
Gar nicht. Unbenannte Klassen dürfen keine Konstruktoren besitzen.
Danke für die klare Antwort
Gar nicht. Unbenannte Klassen können weder statische Elemente noch out-of-line Memberfunktionen besitzen.
Nicht ganz unmöglich, fals eine inline Funktion zu kompilzirt ist wird sie ja als dateistatische Funktion implementirt.
Nö. Solange du die Instanz nicht mit static qualifiziert hast, ist die Instanz extern. Du hast also eine ODR-Verletzung, nicht zwei Instanzen.
Wenn ich jetzt wüsste wofür ODR steht wäre ich jetzt ein Stück weiter. Aber ich gehe mal davon aus, dass es ein Linker error ist.
-
odr - one definition rule
jemand schrieb:
Nicht ganz unmöglich, fals eine inline Funktion zu kompilzirt ist wird sie ja als dateistatische Funktion implementirt.
was nichts daran ändert, dass trotzdem inline davorstehen darf und es innerhalb deiner klasse implizit tut, was glaube ich das ist, was hume meint.
-
Nicht ganz unmöglich, fals eine inline Funktion zu kompilzirt ist wird sie ja als dateistatische Funktion implementirt.
Irrtum (und irrelevant).
Inline-Funktionen haben laut Standard external linkage (nicht so wie in Prä-Standard-C++ internal linkage). D.h ein Compiler muss dafür sorgen, dass eine inline-Funktion keine oder genau eine out-of-line-Definition hat. Nicht eine pro Übersetzungseinheit.Ich habe mich da aber in der Tat missverständlich ausgedrückt. Methoden einer unbenannten Klasse können *nicht* außerhalb der Klassendefinition definiert werden. Punkt.
Nebensächlich folgt daraus insbesondere, dass alle Methoden einer unbenannten Klasse per Definition inline sind. Das heißt aber natürlich nicht, dass einzelne Methoden nicht out-of-line generiert werden können. Es heißt nur dass, was der Standard für inline definiert. Also insbesondere, dass solche Methoden genau einmal pro Übersetzungseinheit definiert werden dürfen (im Gegensatz zu normalen Funktionen/Methoden die nur genau einmal pro Programm definiert werden dürfen).
-
Irrtum (und irrelevant).
Ich hab mir jetzt ein par mal deine Posts durchgelesen und den link über die odr, aber ich versteh trotzdem nicht was falsch sein soll.
Also wir haben ein header:
class{ public: void func(){for(int i=0;i<50;i++);}//zu komplizirt zum inlinen }a;
Eine cpp Datei:
#include"header" int f1(){ a.func(); }
Und die andere cpp Datei:
#include"header" int f2(){ a.func(); }
Da die Funktion (func) nicht inline implementirt (das heist in f1 und f2) werden kann, wird sie als Funktion implementirt die von f1 und f2 aufgeruffen wird. Jetzt sagt ODR, dass es nur eine Definition geben darf, also einen in der ersten cpp Datei oder in der zweiten.
Allerdings sind die 2 Funktionen, inline Funktion, Token für Token identisch, desweiteren sind sie in verschieden Übersetzungseinheiten und haben die selbe Bedeutung, also ist dieser Fall eine Ausnahme und die Definition darf in meherern Modulen angelegt werden.
Damit es später beim Linken keine Nameskonflikte entstehen werden keine external Referneces angelegt, also ist die eigentlich func Funktion nur in ihrem Modul bekannt und soweit ich weis heiß das dateistatisch.
-
jemand schrieb:
Da die Funktion (func) nicht inline implementirt (das heist in f1 und f2) werden kann, wird sie als Funktion implementirt die von f1 und f2 aufgeruffen wird.
Irrelevant als was sie generiert wird. Der Compiler kann mit ihr machen was er will: inline, nicht inline oder wenn er lustig ist auch mal was anderes.
Wichtig ist, dass sie 'inline' ist. Das bedeutet, dass sie (als Definition) in mehreren übersetzungseinheiten (cpp Dateien) vorkommen darf.
Jetzt sagt ODR, dass es nur eine Definition geben darf, also einen in der ersten cpp Datei oder in der zweiten.
exakt. und inline hebt die ODR auf, wenn du so willst. Denn inline sagt: die funktion wird zwar hier definiert, aber sie verletzt trotzdem nicht die ODR.
Allerdings sind die 2 Funktionen, inline Funktion, Token für Token identisch, desweiteren sind sie in verschieden Übersetzungseinheiten und haben die selbe Bedeutung, also ist dieser Fall eine Ausnahme und die Definition darf in meherern Modulen angelegt werden.
nur wenn func als inline deklariert wurde. und eine Funktion die 'inline in einer Klassendefinition' definiert wird, ist inline.
Damit es später beim Linken keine Nameskonflikte entstehen werden keine external Referneces angelegt, also ist die eigentlich func Funktion nur in ihrem Modul bekannt und soweit ich weis heiß das dateistatisch.
nein.
inline funktionen haben external linkage - dh der Compiler liest ein
inline void foo() {}
wie wenn es ein
void foo();
wäre. Allerdings merkt er sich zusätzlich wie foo implementiert ist und kann gegebenenfalls den Aufruf
foo();
direkt durch den Körper von foo ersetzen (muss es aber nicht). Er kann genauso aus foo(); einen Aufruf von foo() machen und den Körper von foo() dann nur einmal irgendwo aufscheinen lassen - und alle foo()-Aufrufe leiten dorthin.deine ODR Verletzung erhältst du von a. Denn a ist eine Variable. Und variablen können nicht inline deklariert werden.
a wird also sowohl in der ersten als auch in der zweiten cpp Datei instanziiert (angelegt). Danach schreit der Linker - denn es gibt 2 instanzen von a.
-
nein.
inline funktionen haben external linkage - dh der Compiler liest ein
inline void foo() {}
wie wenn es ein
void foo();
wäre. Allerdings merkt er sich zusätzlich wie foo implementiert ist und kann gegebenenfalls den Aufruf
foo();
direkt durch den Körper von foo ersetzen (muss es aber nicht). Er kann genauso aus foo(); einen Aufruf von foo() machen und den Körper von foo() dann nur einmal irgendwo aufscheinen lassen - und alle foo()-Aufrufe leiten dorthin.Das versteh ich nun nicht. Das heist fals er foo() nicht inline ersetzt er es durch:
call _foo
Und _foo ist als external Label declariert. Soweit so gut aber wo ist das Label _foo denn nun? Wenn der compiler ein Modul kompilirt weis er ja nicht mit wie vielen anderen Modulen es verlink werden wird und wie viele von denen foo declarirt haben also muss er damit er sicher ist, dass es ein Label gibt es in das Modul packen, das er gerade kompilirt. Wenn allerdings der Linker nun versucht die globalen Labels mit einander zuverknüpfen kommt es zu einem Problem, _foo ist in allen Dateien definirt in denen foo declarirt ist, welechen Label so er nun welchem verlinken, er kann ja nicht wissen, dass es egal ist weil alle identisch sind da er ja nicht vergleichen kann.
Shade Of Mine schrieb:
deine ODR Verletzung erhältst du von a. Denn a ist eine Variable. Und variablen können nicht inline deklariert werden.
a wird also sowohl in der ersten als auch in der zweiten cpp Datei instanziiert (angelegt). Danach schreit der Linker - denn es gibt 2 instanzen von a.
HumeSikkins schrieb:
Nö. Solange du die Instanz nicht mit static qualifiziert hast, ist die Instanz extern. Du hast also eine ODR-Verletzung, nicht zwei Instanzen.
Irgendwie erscheinen mir die zwei Aussagen widersprüchich.
-
Irgendwie erscheinen mir die zwei Aussagen widersprüchich
Wieso?
Zweimal definieren, vs. zweimal instanzieren.
-
jemand schrieb:
Das versteh ich nun nicht. Das heist fals er foo() nicht inline ersetzt er es durch:
call _foo
Und _foo ist als external Label declariert.
Kann, muss aber nicht sein.
foo darf auch wirklich inline generiert werden, also direkt der code an die Stelle, statt dem call.Soweit so gut aber wo ist das Label _foo denn nun?
Ja das darf sich der Compiler aussuchen. Um ehrlich zu sein: ich weiss es nicht.
Ich nehme an, er wird die Funktion in jede Übersetzungseinheit hineinschreiben und sie dem Linker als 'inline' markieren, so dass der Linker sie dann wieder hinaushaut und nur eine Version in die .EXE übernimmt.
Aber es spricht nichts dagegen, dass der Compiler es nicht auch anders machen kann - die Standard definiert nur das Ergebnis, wie der Compiler dieses Ergebnis erreicht, ist sein Bier.
Shade Of Mine schrieb:
deine ODR Verletzung erhältst du von a. Denn a ist eine Variable. Und variablen können nicht inline deklariert werden.
a wird also sowohl in der ersten als auch in der zweiten cpp Datei instanziiert (angelegt). Danach schreit der Linker - denn es gibt 2 instanzen von a.
HumeSikkins schrieb:
Nö. Solange du die Instanz nicht mit static qualifiziert hast, ist die Instanz extern. Du hast also eine ODR-Verletzung, nicht zwei Instanzen.
Irgendwie erscheinen mir die zwei Aussagen widersprüchich.
Hume hat sich 'technisch korrekt' ausgedrückt und ich eher schlampig, sorry
Aber das Ergebnis ist das selbe: was ich unter "Danach schreit der Linker - denn es gibt 2 instanzen von a" meinte ist nichts anderes als eine ODR-Verletzung. Denn die ODR besagt, dass es eben keine 2 instanzen von a geben darf.
Hast du dir den Link von davie schon durchgelesen?
class { /.../ } a;
ist im Prinzip nichts anderes als
Klasse obj;
eine definition einer Variablen.In dem Link von davie steht schön erklärt warum das nicht gut gehen kann.
-
Shade Of Mine schrieb:
Jetzt sagt ODR, dass es nur eine Definition geben darf, also einen in der ersten cpp Datei oder in der zweiten.
exakt. und inline hebt die ODR auf, wenn du so willst. Denn inline sagt: die funktion wird zwar hier definiert, aber sie verletzt trotzdem nicht die ODR.
Den Punkt den du machen willst, verstehe ich und er ist auch ok. Nur ist imo die Formulierung "Inline hebt die ODR auf" sehr unglücklich.
Inline hebt nicht die ODR auf. Vielmehr erhält inline seine Bedeutung direkt aus der ODR.Die ODR legt fest unter welchen Umständen bestimmte Definition benötigt werden und wie oft Definitionen auftreten dürfen.
Dabei unterscheidet sie zwei Bedingungen für Definitionen:
1. Einmal pro Programm
2. Einmal pro Übersetzungseinheit.Wie man sieht gilt schon mal generell: Nichts (keine Variable, keine Funktion, keine Klasse...) darf mehr als einmal pro Übersetzungseinheit definiert werden.
Funktionen gehören nun zu den Dingen die nur genau einmal pro Programm definiert werden dürfen (so sie nicht als static deklariert sind). Es sei denn sie sind inline. inline-Funktionen dürfen nicht nur, sondern müssen in jeder ÜE definiert werden, in der sie verwendet werden.
Genau das ist die entscheidene Bedeutung von inline. Also nocheinmal (viele Wiederholungen verstärken den Trainingseffekt): Die Bedeutung von inline im Sinne des C++ Standards ist nicht, dass eine Funktion inline-generiert wird, sondern das eine solche Funktion einmal pro ÜE definiert werden muss.jemand schrieb:
Und _foo ist als external Label declariert. Soweit so gut aber wo ist das Label _foo denn nun? Wenn der compiler ein Modul kompilirt weis er ja nicht mit wie vielen anderen Modulen es verlink werden wird und wie viele von denen foo declarirt haben also muss er damit er sicher ist, dass es ein Label gibt es in das Modul packen, das er gerade kompilirt. Wenn allerdings der Linker nun versucht die globalen Labels mit einander zuverknüpfen kommt es zu einem Problem, _foo ist in allen Dateien definirt in denen foo declarirt ist, welechen Label so er nun welchem verlinken, er kann ja nicht wissen, dass es egal ist weil alle identisch sind da er ja nicht vergleichen kann.
Wie eine Implementation das realisiert bleibt ihr überlassen. Ich kenne drei Strategien:
1. Compiler + Linker arbeiten zusammen: Hier generiert der Compiler mehrere Versionen der inline-Funktion. Beim Linken schmeißt der Linker allerdings alle bis auf eine Version raus.
Diese Vorgehensweise ist weit verbreitet, führt aber zu lustigen Ergebnissen, wenn man die ODR im Punkt "Token-by-Token-identisch" verletzt.2. Repository: In diesem Fall verwendet der Compiler ein einzelnes repository für alle out-of-line generierten inline-Funktionen. Wann immer eine inline-Funktion eine out-of-line-Implementation braucht, schaut der Compiler in sein repository. Existiert dort bereits eine Definition verwendet er diese. Ansonsten wird eine neue Definition in das repository gepackt. Diese vorgehensweise hat den Nachteil, dass ein fehlende repository immer eine komplette Neukompilation zur Folge hat.
3. Die Implementation ignoriert den C++ Standard und macht inline-Funktionen standardmäßig file-static. Dieser Weg ist nicht gerade selten.
-
Genau das ist die entscheidene Bedeutung von inline. Also nocheinmal (viele Wiederholungen verstärken den Trainingseffekt): Die Bedeutung von inline im Sinne des C++ Standards ist nicht, dass eine Funktion inline-generiert wird, sondern das eine solche Funktion einmal pro ÜE definiert werden muss.
Heist das nun, dass ich(, fals mein Kompiler dem Standard folgt), alle meine Funktionen in einem Header inline definiren kann (anstatt sie zu declariren) und somit kein extra Modul brauche um sie zu definiren (als nicht inline Funktion), allerdings wird meine exe deshalb nicht grösser, es dauert nur länger zum compiliren. Oder hab ich da nun was missverstanden?
-
Heist das nun, dass ich(, fals mein Kompiler dem Standard folgt), alle meine Funktionen in einem Header inline definiren kann (anstatt sie zu declariren) und somit kein extra Modul brauche um sie zu definiren (als nicht inline Funktion), allerdings wird meine exe deshalb nicht grösser, es dauert nur länger zum compiliren. Oder hab ich da nun was missverstanden?
Korrekt. Wenn dir die Vorteile der Kapselung völlig egal sind, dann kannst du alle deine Methoden innerhalb der Klassendefinition definieren und auf eine extra cpp-Datei verzichten. Das macht dein Programm aus Sicht des Standards kein bischen weniger korrekt.
PS:
Problematisch wird das nur bei vielen Compilern im Zusammenhang mit virtuellen Methoden. Einige Compiler plazieren die vtabel einer Klasse nämlich gerne in die ÜE, die die erste virtuelle Methode einer Klasse definiert. Hast du nun alle Methoden in einem Header, dann passiert es schnell, dass deine vtabel mehrfach im Programm vorkommt. Die Programm-Datei wird also doch wieder größer.PPS:
Wozu mit C++ und Klassen programmieren, wenn man nicht an Kapselung und Trennung von Interface und Implementation interessiert ist?
-
Ok danke
Wozu mit C++ und Klassen programmieren, wenn man nicht an Kapselung und Trennung von Interface und Implementation interessiert ist?
Wollt ja nur sicher sein, dass ich das nun auch richtig verstanden habe.
Ich hätte da noch eine Frage. Wenn ich in einer Datei zum Beispiel list<int> benutze und in einer anderen auch list<int> werden dann die Klassen Funktionen genau wie inline Fuktionen auch nur einmal pro exe angelegt?
-
Wenn ich in einer Datei zum Beispiel list<int> benutze und in einer anderen auch list<int> werden dann die Klassen Funktionen genau wie inline Fuktionen auch nur einmal pro exe angelegt?
Jup. So sollte es sein.