Konstruktoren bei Qt

Azi

Erfahrenes Mitglied
<moderation moderator="Matthias Reitinger">Diese Frage stand ursprünglich in einem ganz anderen Thema im Testforum und wurde hierher verschoben.</moderation>

Öhm, wir sind hier nicht im Quiz-Forum ;) Das war eine Aussage, kein Rätsel :)
Da könnt ihr mir ja gleich mal erklären, was Zeilen 12 und 13 machen und warum der Prototyp der Zeile 9 keinen Code hat :)

Code:
#include <QApplication>
#include <QFont>
#include <QPushButton>
#include <QWidget>

class MyWidget : public QWidget
{
	public:
        MyWidget(QWidget *parent = 0);
};

MyWidget::MyWidget(QWidget *parent)
	: QWidget(parent)
{
        setFixedSize(200, 120);

        QPushButton *quit = new QPushButton(tr("Quit"), this);
        quit->setGeometry(62, 40, 75, 30);
        quit->setFont(QFont("Times", 18, QFont::Bold));

        connect(quit, SIGNAL(clicked()), qApp, SLOT(quit()));
}

int main(int argc, char *argv[])
{
        QApplication app(argc, argv);
        MyWidget widget;
        widget.show();
        return app.exec();
}
 
Hallo Azi,

der Konstruktor, der in Zeile 9 definiert wurde, wird ja in Zeile 12–22 implementiert. Die Notation in Zeile 13 sorgt lediglich dafür, dass der Konstruktor der Mutterklasse QWidget aufgerufen wird.

Grüße,
Matthias
 
Matthias Reitinger hat gesagt.:
Hallo Azi,

der Konstruktor, der in Zeile 9 definiert wurde, wird ja in Zeile 12–22 implementiert. Die Notation in Zeile 13 sorgt lediglich dafür, dass der Konstruktor der Mutterklasse QWidget aufgerufen wird.

Grüße,
Matthias
Zeile 13 musst du mir nochmal genauer erklären. Bewirkt die Notation, dass ein Befehl ausgeführt wird? Denk ich mal weniger.
 
Hallo,

Azi hat gesagt.:
Zeile 13 musst du mir nochmal genauer erklären. Bewirkt die Notation, dass ein Befehl ausgeführt wird? Denk ich mal weniger.
Diese Notation nennt sich „Initialisierer“. Bei der Erstellung eines Objektes werden zuerst die Konstruktoren der übergeordneten Klassen der Reihe nach aufgerufen, beginnend mit der Basisklasse. Dabei werden stets die Konstruktoren aufgerufen, die mit der (Parameter-)Signatur des in Frage kommenden Konstruktors der instanzierten Klasse übereinstimmen (also im Klartext: übereinstimmende Parameter in Anzahl und Typ). Wird ein solcher nicht gefunden, so wird der (parameterlose) Standardkonstruktor aufgerufen. Um das zu verhindern, kann man im Initialisierer eines Konstruktors explizit angeben, welcher Konstruktor mit welchen Parametern aufgerufen wird.

Da QWidget keinen Konstruktor besitzt, der einen einzelnen Parameter des Typs QWidget * akzeptiert, würde bei der Instanzierung eines MyWidget der Standardkonstruktor von QWidget aufgerufen werden. Um das zu verhindern, gibt man durch das Anhängsel : QWidget(parent) explizit an, wie der Aufruf des Superkonstruktors erfolgen soll.

Du kannst dieses Verhalten ganz einfach überprüfen:
Code:
#include <iostream>

class Basis {
public:
    Basis(int a = 0, int b = 0)
    {
        std::cout << "a = " << a << std::endl;
        std::cout << "b = " << b << std::endl;
    }
};

class Abgelitten : public Basis {
public:
    Abgelitten(int a) : Basis(a) {}
};

int main()
{
    Abgelitten a(123);
    return 0;
}
Einfach mal ausprobieren, wie sich die Ausgabe ändert, wenn man den Initialisator weglässt :)

Grüße,
Matthias

PS: Ich splitte das mal in ein separates Thema im C/C++-Forum ab…
 
Wofür genau steht das Anhängsel? Kann man da nur Konstruktoren einer Basisklasse angeben? Oder mehrere, falls mehrere vorhanden sind?
 
Hallo,
Wofür genau steht das Anhängsel?

das nennt sich wie Matthias bereits erwähnt hat Initiator oder auch Initialisierungsliste.

Kann man da nur Konstruktoren einer Basisklasse angeben?

Nein man kann da auch Konstruktoren von den Membern der jeweiligen Klasse
angeben um diese zu initialisieren:

C++:
#include <iostream>

using namespace std;

class Foo{
	private:
		int a;
		int b;
	public:
		Foo(){
			cout << "Constructing a Foo object" << endl;
		}
};

class A{
	Foo f;
	public:
        //die folgende Konstruktordefinition wird vom Kompiler zu A() : f(){} übersetzt
		A(){ 
		}
};

oder auch:

C++:
#include <iostream>

using namespace std;

class Foo{
	private:
		int member_a;
		int member_b;
	public:
		Foo(int a, int b) : member_a(a), member_b(b){
			cout << "Constructing a customized Foo object" << endl;
		}
};

class A{
	Foo f;
	public:
		A() : f(1, 2){ 
		}
};

und dasselbe geht auch für Membervariablen von primitiven Datentypen:

C++:
#include <iostream>

using namespace std;

class Foo{
	private:
		int member_a;
		int member_b;
	public:
		Foo(int a, int b) : member_a(a), member_b(b){
			cout << "Constructing a customized Foo object"
				 << "with a = " << a 
				 << " and b = " << b;

		}
};

class A{
	private:
		int a;
		int b;
		Foo f;
	public:
		A() : a(5), b(3), f(a, b){
		}
};

und nat. für die Konstruktoren der Basisklasse.

Btw. das erste Beispiel zeigt auch wieso man bei Membern welche nicht von
primitiven Datentypen sind, immer die Initialisierung über die Initialisierungsliste
machen sollte.

Gruß,
RedWing
 
Zurück