Abgeleitete Klasse wird nicht anerkannt

Du bist neu in der Welt von C++? Dann schau hier herein!
Antworten
Gruwe
Beiträge: 21
Registriert: 14. April 2011 18:15

Abgeleitete Klasse wird nicht anerkannt

Beitrag von Gruwe » 21. September 2011 16:09

Hallo,

ich arbeite mich derzeit in Qt ein, bin momentan dabei ein wenig mit den Elementen eines Hauptfensters zu experimentieren.
Ich habe ein Hauptfenster erstellt und widme mich jetzt der Erstellung der Menubar. Die Menubar hinzuzufügen mit allerlei Aktionen funktioniert, jedoch würde ich jetzt aus Gründen der Übersichtlichkeit die einzelnen Menus direkt als eigene Klasse machen (also dass z.B. das Datei-Menu eine eigene Klasse ist, in der direkt alle Funktionen implementiert sind).

Ich habe also eine Klasse FileMenu von QMenu abgeleitet:

Code: Alles auswählen

class FileMenu : public QMenu
{
    Q_OBJECT

public:
    FileMenu(const QString, QMenu *parent = 0);
    ~FileMenu();

private:

    QAction *newFile;
    QAction *openFile;
    QAction *saveFile;
    QAction *saveFileAs;
    QAction *closeFile;
    QAction *quitProg;

};

Konstruktor, etc. habe ich auch in der entsprechenenden Quelldatei implementiert.

Nun möchte ich in der Klasse des Hauptfensters (MainWindow) einen entsprechenden Zeiger auf die neue Klasse FileMenu anlegen:

Code: Alles auswählen


class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow();
    ~MainWindow();

private:

    FileMenu *fileMenu;

Also lege ich wie zu sehen ist unter private einen Zeiger des Typs FileMenu an.

Wenn ich das jedoch dem Kompiler serviere, gibts nur folgende Fehlermeldung:

ISO C++ forbids declaration of 'FileMenu' with no type
expected ';' before '*' token

So wie ich die Fehlermeldung interpretiere, erwartet er einen Typ für den Zeiger. Aber stellt nicht die abgeleitete Klasse FileMenu einen Typen auf eben jene Klasse dar, so wie z.B. bei QMenu *menu das QMenu der Typ des Zeigers ist.

Kann mir da mal jemand eine Erklärung dazu abliefern?


MfG und Danke

Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Re: Abgeleitete Klasse wird nicht anerkannt

Beitrag von Christian81 » 21. September 2011 17:25

1. Wo genau tritt der Fehler auf?
2. Wird der Header denn auch inkludiert -> zu wenig Code bzw. kein minimales kompilierbares Beispiel
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung

Gruwe
Beiträge: 21
Registriert: 14. April 2011 18:15

Re: Abgeleitete Klasse wird nicht anerkannt

Beitrag von Gruwe » 21. September 2011 17:38

Hallo,

danke für die Antwort. Hier mal das bisher komplette Programm (kompilierbares Beispiel):

main.cpp:

Code: Alles auswählen

#include <QApplication>
#include "mainWindow.h"


int main ( int argc, char *argv[] )
{
    QApplication app (argc, argv);

    //Instanziierung von MainWindow
    MainWindow *window = new MainWindow();

    window->show();
    return app.exec();
}
Dann hier die Header-Datei des MainWindow, mainWindow.h:

Code: Alles auswählen

#include <QApplication>
#include <QtGui>

#include "menuBar.h"

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow();
    ~MainWindow();

private:

    FileMenuClass *fileMenu;

};
Die Source-Datei des MainWindow, mainWindow.cpp:

Code: Alles auswählen

#include "mainWindow.h"

MainWindow::MainWindow()
{
   showMaximized();
}

MainWindow::~MainWindow()
{
}
Dann die Header-Datei der MenuBar, menuBar.h:

Code: Alles auswählen

#include "mainWindow.h"

class FileMenuClass : public QMenu
{
    Q_OBJECT

public:
    FileMenuClass();
    ~FileMenuClass();


private:

    QAction *newFile;
    QAction *openFile;
    QAction *saveFile;
    QAction *saveFileAs;
    QAction *closeFile;
    QAction *quitProg;

};
und die entsprechende Source-Datei, menuBar.cpp:

Code: Alles auswählen

FileMenuClass::FileMenuClass()
{
    newFile = new QAction( tr("Neu..."), this);                 //Neue Datei
    openFile = new QAction( tr("Öffnen..."), this);             //Datei öffnen
    saveFile = new QAction( tr("Speichern"), this);             //Datei speichern
    saveFileAs = new QAction( tr("Speichern unter..."), this);  //Datei speichern unter
    closeFile = new QAction( tr("Schliessen"), this);           //Schliessen
    quitProg = new QAction( tr("Beenden"), this);               //Beenden
  
    addAction( newFile );
    addAction( openFile );
    addAction( saveFile );
    addAction( saveFileAs );
    addAction( closeFile );
    addSeparator();
    addAction( quitProg );

}

FileMenuClass::~FileMenuClass()
{

}
Also wie zu sehen ist, ist das Programm nicht wirklich umfangreich, da es mir in erster Linie darum geht mal auszuprobieren bzw. zu lernen, wie ich eigene Klassen ableite und entsprechend einfügen, hier also ein vorgefertigtes Menu.

Der Fehler tritt einfach dann auf, wenn ich versuche das Programm zu kompilieren. Ich benutze den Qt Creater und drücke in der Regel auf den grünen Pfeil, damit das Programm ausgeführt wird! ;)

Gruwe
Beiträge: 21
Registriert: 14. April 2011 18:15

Re: Abgeleitete Klasse wird nicht anerkannt

Beitrag von Gruwe » 21. September 2011 17:57

Hallo,

also was funktioniert ist, wenn ich folgendes in den Konstruktor von mainWindow eintrage:

Code: Alles auswählen

FileMenuClass *fileMenu = new FileMenuClass( tr("Datei") );
menuBar()->addMenu( fileMenu );
Das funktioniert und das Menu wird auch angezeigt.
Aber dazu eine Frage:

Ich dachte mir es sei sinnvoller, den Zeiger auf das Menu in der Klassendeklaration von MainWindow anzugeben, damit der Zeiger direkt beim Löschen der Instanz ebenfalls gelöscht wird. Wird er lediglich in einer zu MainWindow zugehörigen Funktion (wie in dem Fall dem Konstruktor) deklariert, so hab ich ja keinen Zugriff mehr darauf, ich kann also z.B. im Destruktor von MainWindow nicht auf diesen Zeiger zugreifen und somit beim Beenden des Programmes die Instanz löschen.
Oder seh ich da was falsch?

MfG

brax
Beiträge: 208
Registriert: 11. Mai 2010 11:22

Re: Abgeleitete Klasse wird nicht anerkannt

Beitrag von brax » 21. September 2011 18:03

Deine Includes funktionieren so nicht. Du kannst nicht sowohl in der mainWindow.h die menuBar.h includieren und dann auch noch in der menuBar.h die mainWindow.h. Da ein include nur eine textuelle Ersetzung ist führt das quasi zu einer Rekursion ohne Abbruchbedingung (die der Preprozessor zum Glück verhindert).

Im Moment brauchst Du in der menuBar.h nichts aus mainWindow.h, der include kann also einfach raus. Solltest Du doch noch diese Abhängigkeit brauchen, bietet C++ forward declarations an, um das Problem zu lösen. Du könntest z.B. in der mainWindow.h statt des

Code: Alles auswählen

#include "menuBar.h"
einfach

Code: Alles auswählen

class FileMenuClass;
schreiben und das include in die .cpp Datei verfrachten. Zu beachten ist das eine forward declaration nur funktioniert, wenn Du im Header die entsprechende Klasse nicht wirklich benutzt. Wäre z.B. fileMenu kein Pointer, würde das nicht funktionieren.

Übrigens: Ich finde es extrem verwirrend, dass Deine Dateien anders heißen als die darin definierten Klassen. Ich musste mehrfach hoch und runter scrollen in Deinem Post um sicher zu sein, dass es sich wirklich um das genannte Problem handelt. Macht zwar unter C++ keinen Unterschied (unter Java wäre das anders), ist aber deutlich einfacher zu überblicken bei größeren Projekten.

solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Re: Abgeleitete Klasse wird nicht anerkannt

Beitrag von solarix » 21. September 2011 21:11

Zum Include/Forwarddecl-Problem wurde ja schon alles gesagt, daher nur noch ein paar Kleinigkeiten:

1. Zyklische Abhängikeiten sind in Objekt-orientierten Strukturen äusserst fragwürdig und sollten wenn immer möglich vermieden werden (über das erste Problem dieser Abhängigkeiten bist du ja bereits gestoplert...).

2. Weil du ja -wie brax erwähnte- den Include gar nicht brauchst, sieht mir das nach einer "ich-includiere-einfach-immer-alles"-Strategie aus. Auch das ist "böse". Includiere immer so spät wie möglich (also möglichst wenig und davon möglichst viel in der cpp-Datei, nicht in der Header!).

3. Aus OOP-Sicht ist die Klasse "FileMenuClass" eher fragwürdig.. ich verstehe schon, dass es "nur ein Beispiel" ist, aber auch Beispiele sollten sinnvoll sein (es sei denn sie sollen Anti-Patterns demonstrieren :wink:). Anfänger (ver)erben einfach viel zu oft... in deinem Beispiel musst du ja deine MainView sowieso aufsetzen (im Ctor oder einer "setup"-Methode), egal wieviele Unterklassen du erstellst. Da machen die Menüpunkte auch nicht mehr viel aus.

4. In Qt zerstören "Parent"-Instanzen immer die "Child"s. Daher immer dieser "parent"-Pointer im Konstruktor. Die dienen dazu ein neues "Child" zu erstellen, welches ebenfalls zerstört wird, wenn der Parent gelöscht wird. Du hast dazu geschrieben:
so hab ich ja keinen Zugriff mehr darauf, ich kann also z.B. im Destruktor von MainWindow nicht auf diesen Zeiger zugreifen und somit beim Beenden des Programmes die Instanz löschen.
Diese Zeiger brauchst du auch nicht mehr.. wenn du "new FileMenuClass(this)" nehmen würdest, erledigt Qt das für dich. Das selbe gilt für die QActions: die braucht man normalerweise nicht als Membervariabeln...

hth!

Antworten