Zum Inhalt springen

Empfohlene Beiträge

Geschrieben

Hallo Leute!

Ich habe eine Frage bezügliche der Initialisierung von Membervariablen, genauer gesagt, dem Unterschied zwischen der Zuweisung im Konstruktor und der Verwendung der Initialisierungsliste.

Beispiel:

// A: init list
class foo
{
public:
foo() : bar(0) {}

private:
int bar;
};

// B: ctor assignment
class foo2
{
public:
foo2() {
bar2 = 0;
}

private:
int bar2;
};[/CODE]

Ich weiß, dass bei einem const-Member nur A funktioniert. Aber gibt es weitere Unterschiede?

Geschrieben

Es gibt schon Unterschiede:

- Der Konstruktor legt erst alle verwendeten Variablen auf dem Stack an bevor in die Funktion gesprungen wird und danach die Variablen ein zweites mal mit dem Initialwert beschriftet werden, wodurch ein schlechteres Laufzeitverhalten folgt. Das macht die Initialisierungsliste in einem Rutsch.

- die Initialisierung der Member-Variablen ist übersichtlicher wenn sie gleich direkt beim Konstruktor erfolgt - im Konstruktor selbst ist es nicht mehr auf einen Blick erkennbar, ob es sich wirklich um Member- oder Lokale-Variablen handelt: Dient der Leserlichkeit!

Das Wichtigste wie Du schon gesagt hast:

Konstante, bzw. nicht-statische Member-Variablen können NUR über die Initialisierungsliste direkt beschrieben werden. Versucht man das im Konstruktor gibt´s eine Fehlermeldung:

"Variable XYZ" : muss in der Basisklassen/Element-Initialisierungsliste des Konstruktors initialisiert werden

Geschrieben

Danke, Crush, so was hatte ich vermutet.

Eine weitere Frage: Ist die Reihenfolge, in der die Member in der Liste stehen, auch die Reihenfolge, in der die Variablen initialisiert werden, oder darf man sich darauf nicht verlassen?

Geschrieben

Die Reihenfolge der Initialisierungsiste wird nicht direkt abgearbeitet! Die Compiler orientieren sich nach der Reihenfolge der Variablendeklarationen in der Klasse (sicherlich wegen der Stack- & Heap-behandlung beim Konstruktoraufruf) - das spielt aber für den C++-Programmierer eh keine Rolle (höchstens wenn man sich direkt an den Assembler-Code wagt).

Sollte mal irgendwo ein unerklärliches Initialisierungs-Problem auftauchen, könnte also u.U der Compiler dran schuld sein, weshalb es ratsam ist die Liste in Reihenfolge der Deklarationen vorzunehmen. Beim *** Visual C++ gibt´s da jedoch keine Probleme. Mir persönlich ist auch kein Compiler bekannt, bei dem das nicht korrekt bearbeitet wurde.

Ich verlasse mich also normal darauf, daß der Compiler keinen Mist baut, aber ich behalte das für eventuellen Ärger mal im Hinterkopf.

Gegenfrage außerhalb des Themas: Warum darf ich nicht mehr "Microsoft-Dollar" schreiben?

Geschrieben
Original geschrieben von Crush

- das spielt aber für den C++-Programmierer eh keine Rolle (höchstens wenn man sich direkt an den Assembler-Code wagt).

Naja, das folgende Beispiel ist zwar konstruiert, aber sowas könnte wichtig sein, auch ohne Assembler. Oder habe ich was falsch verstanden:

class bar1
{
public:
bar1() { printf("Erster\n"; }
};

class bar2
{
public:
bar2() { printf("Zweiter\n"; }
};

class foo
{
public:
foo() : b1(), b2() {}

private:
bar2 b2;
bar1 b1;
};[/CODE]

[b]Gegenfrage außerhalb des Themas: Warum darf ich nicht mehr "Microsoft-Dollar" schreiben? [/b]
Es ist eine (absichtliche) Falschschreibung mit dem Ziel der Verunglimpfung, damit Verstoß gegen die Boardregeln.
Geschrieben

Also Dein Beispiel könnte eigentlich (theoretisch) nicht wichtig sein, weil der Konstruktor von bar1 und bar2 auch ohne den Element-Konstruktoraufruf normal durchwandert wird. Ich glaube, das ist eher eine Konsequenzfrage und eine Frage des Programmierstils, falls man bei den Elementobjekten konstante Inhalte hat und diese nach außen hin versteckt initialisieren möchte. Damit hat foo() die Aufgabe eines Dekorierers oder einer Fassade um in den verwendeten Elementklassen Information-Hiding zu betreiben. Sowas kann bei bestimmten Konstruktionen Sinn haben, z.B. wenn man im Atomkraftwerk die Pumpe hat, welche von Pumpeninspektor an den Pumpenregler weitergereicht wird, so ist die Pumpe selbst versteckt, geschützt und so kann man schaffen, ohne daß man friends unbedingt einsetzen muß (obwohl die für solche Zwecke und Operatoren implementiert wurden). Außerdem kann man so private Vererbung vermeiden, wovon ja jeder abrät.

Es ist also wahr, daß man Deine Konstruktion schon noch in Sonderfällen verwenden muß, nämlich wenn konstante Elementobjekte von konstanten Elementen bei der Konstruktion initialisiert werden sollen!!! (hört sich das wieder kompliziert an... =8-)


class bar1

{

public:

  bar1(int Priv=0):priv(Priv){ TRACE("Erster\n"); }

  ~bar1() {;}

private:

	int priv; // hätte man auch const priv schreiben können weil´s durch

//  foo eh konstant ist

// andererseits ist es so als einzelnes bar-Objekt noch für friends verwendbar

};


class bar2

{

public:

  bar2(int Priv=0):priv(Priv){ TRACE("Zweiter\n"); }

  ~bar2(){;}

private:

	int priv;

};


class foo

{

public:

//  foo(int zahl=0) : b1(zahl), b2(zahl) {}

// nur notwendig wenn den Initialisierer von bar1 und bar2 was anderes

// übergeben werden soll

  foo() {} // geht genauso und springt die Konstruktoren richtig durch

//	foo() {b2(5);} klappt ja leider nicht weil´s konstante

// Objekte sind, also EI notwendig ist

	~foo(){;}


private:

  const bar2 b2;

//  bar2 b2(5); // geht nicht, gilt als schon konstant (wunderlich, gell?)!!!

  const bar1 b1;

};


	foo boo;

//	foo boo2(2);

// hier muß man Dein Beispiel tatsächlich zwangsläufig einsetzen, also hast Du Recht

// es gibt also Ausnahmen

Was Daragon damit sagen wollte ... darüber rätsel ich noch etwas.

Geschrieben

Die member variablen werden, wie von crush schon erwähnt, in der reihenfolge ihrer deklaration in der klasse initialisiert. Der Grund ist einfach der, dass das zerstören der objekte genau in der umgekehrten reihenfolge der initialisierung ausgeführt wird. Verschiedene konstruktoren können eine unterschiedliche reihenfolge der initialisierungsliste festlegen und dann wäre die sache nicht eindeutig. Bei den aufrufen der konstruktoren der basisklassen ist die hierarchie entscheidend bzw. die reihenfolge in der liste basisklassen.

class c : public a, public b

konstruktor von a zuerst dann von b

Geschrieben

@Crush:

Es ging mir weniger darum, einen Fall zu konstruieren, in dem so ein Konstrukt erforderlich ist, als um die Reihenfolge der Konstruktoraufrufe. Du hattest geschrieben:

Compiler orientieren sich nach der Reihenfolge der Variablendeklarationen in der Klasse (...) - das spielt aber für den C++-Programmierer eh keine Rolle
Wenn aber (in meinem Beispiel) bar1 und bar2 etwas mehr tun würden, als nur "Zweiter" vor "Erster" auszugeben, z.B. Zugriff auf ein globales Objekt, dann wäre die Kenntnis über die Reihenfolge schon von Vorteil.
Geschrieben

Das könnte allerdings irgendwann so kompliziert werden, daß man kaum noch blickt, was ein Programm tatsächlich anstellt - und da hilft es mehr lieber kurz durchzutracen ob´s überhaupt läuft anstatt den Kopf vorher schon zum Platzen zu bringen.

Geschrieben

Andererseits hast Du recht Klotzkopp, wenn Objekt1 ein globales Objekt verändert und Objekt2 dieses dann verwendet... Aber tut denn sowas fieses (bringt doch nur alle durcheinander)? Ist aber ein guter Trick um Code für andere unzugänglich zu machen.

Man darf aber nicht vergessen, daß der normale Konstruktor ja auch nur als Ergänzung offen gelassen wurde, um dem Programmierer zu ermöglichen dynamisch Variablen für das jeweilige Objekt anzulegen und nicht nur irgendwelche eigenen Elemente zu initialisieren. Das man das auch noch meist tun kann ist ja nur ein beiläufiger Nebeneffekt aber nicht unbedingt in jeden Fall erwünscht wie die konstanten Elemente beweisen. Auch bei statischen Klassenelementen sollte die Initialisierung auch immer außerhalb durch den Programm-Lader erfolgen und nicht durch den Konstruktor der Klasse!

Folgendes hat mich schwer beschäftigt (schwieriger als manche sonstige Programmierfrage im Forum):

From Daragon:

Das ganze wird wie es aussieht (stimmt - sieht so aus als ob C++ objektorientiert sein könnte - aber da Spalten sich die OO-Robin Hoods, ich würde sagen C mit objektorientierten Erweiterungen jedenfalls hätte man das auch so verstehen können) mit einem objektorientien Compiler geschrieben (ob der Compiler objektorientiert ist - da bin ich mir nicht so sicher, weil der aus einer Zeit stammt, als es noch gar keine Objektorientierung gab =8-) und trotz alledem werden die Source-Codes in den einzelnen Dateien *.cpp etc sequentiell abgearbeitet (das hoff´ ich doch schwer, dann bräuchte man sonst keine Includes mehr und könnte gleich alles in eine einzige .CPP reinknallen, was ja geht). Das ganze kannst du aber auch mit dem Debugger durchgehen und läßt dir die lokalen Variablen anzeigen (das mit den Namespaces bringt aber nicht viel bei der Elementinitialisierung - nur mit Blick auf den Assembler-Code kann man wirklich "sehen" was passiert - ansonsten steht man immer vor vollendeten Resultaten). Dann kannst du dich selber überzeugen lassen (ist irgendwo der Wurm drin - entweder: Dann kannst du dich selber überzeugen oder Dann kannst du dich überzeugen lassen von wem denn? oder... wovon denn eigentlich? Das die Elemente überhaupt initialisiert werden?

Der Beitrag war bestimmt gut gemeint, allerdings wirft der für mich mehr Fragen auf als gestellt wurden und trägt so eher zur Verwirrung als zur Problemlösung bei. Trotzdem danke für den Versuch... (falsch war ja schließlich nichts - also: don´t worry - be happy!)

Dein Kommentar

Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...