Anzeige:
Ergebnis 1 bis 15 von 25

Thema: Probleme mit abgeleiteten Klassen

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Registrierter Benutzer
    Registriert seit
    02.08.2008
    Beiträge
    177
    Code:
    BookMask *bookMask = new BookMask;
    
    Mask *mask = bookMask; 
    
    BookMask *bookMask2 = bookMask;
    BookMask *bookMask3 = static_cast<BookMask*>(mask);
    Es sieht ganz stark danach aus, das dessen Typ dann Mask ist. Wenn das so ist, ist meine Grundannahme von Typumwandlung falsch.
    Code:
    class MainWidget : public QWidget {
     	....
    	Mask		*mask;
    	Document	*document;
    }
    Werden immer Mask und Document sein. ich kann zwar Objekte abgeleiteter Klasse hinnein casten, doch am Ende werden es immer die Basisklassen Mask und Document bleiben. Und da liegt mein Fehler, ich brauchte es genau anders herrum.
    Mit new kann ich Ihnen einen neuen Typ zuweisen, doch stecke ich dann in dem Problem des Signals dessen Herrausgeber ich ja noch löschen muss. welches ich mit deleteLater() versuchen werde zu lösen. Und nach meiner ersten Testung auch funktioniert hat.
    Code:
    void MainWidget::setDocumentClass( ){
    qDebug()<<"void MainWidget::setDocumentClass()";
    
    	qDebug()<<"doctype=" << doctype;
    	
    	qDebug()<<"document="<<document<<"|\tmask="<<mask;
    	switch(doctype){
    /*	  
    		case ANIMAL:
    		      qDebug()<<"\ndocument = new AnimalDocument;";
    			      document = (AnimalDocument) new AnimalDocument;
    		      if(!document->start( absolute_document_path ))
    				doctype = EMPTY;
    		      else
    				mask->fill(document->getFileContent(), document->getFileInfo());
    		      break;
    */
    		case BOOK:
    		      qDebug()<<"\nBookDocument";
    		      
    		      disconnect(mask, 0, 0, 0);
    		      mask->deleteLater();
    		      mask = new BookMask;
    		      
    		      disconnect(document, 0, 0, 0);
    		      document->deleteLater();
    		      document = new BookDocument;
    
    		      break;
    		      
    		case RECIPE:
    		      qDebug()<<"\n\n\nRecipeDocument";
    
    		      disconnect(mask, 0, 0, 0);
    		      mask->deleteLater();
    		      mask = new RecipeMask;
    		      
    		      disconnect(document, 0, 0, 0);
    		      document->deleteLater();
    		      document = new RecipeDocument;
    
    		      break;
    		      
    		default:
    		      qDebug()<<"\n\nNo DocType found!";
    		      qDebug()<<"Document";
    		      mask     = mask;
    		      document = document;
    		      
    		      break;
    	}
    		
    	connect( mask, SIGNAL(SigDocTypeChanged( int )),
    		this, SLOT(DocumentTypeChanged( int )) );
    	
    	connect( document, SIGNAL(saved( QString )),
    		this, SLOT(loadDocument( QString )) );
    
    	connect( mask, SIGNAL(SigSave()),
    		this, SLOT(saveDocument()));
    	
    	qDebug()<<"document="<<document<<"|\tmask="<<mask;
    }
    Geändert von dml (26-01-2014 um 17:19 Uhr) Grund: Ein bisschen Angeben

  2. #2
    Administrator Avatar von anda_skoa
    Registriert seit
    17.11.2001
    Ort
    Graz, Österreich
    Beiträge
    5.477
    Zitat Zitat von dml Beitrag anzeigen
    Es sieht ganz stark danach aus, das dessen Typ dann Mask ist.
    Der Typ der Variable "mask" ist Mask* (also Pointer auf Mask). Das Objekt hinter dem Pointer ist nach wie vor vom Typ BookMask.

    Zitat Zitat von dml Beitrag anzeigen
    Werden immer Mask und Document sein. ich kann zwar Objekte abgeleiteter Klasse hinnein casten, doch am Ende werden es immer die Basisklassen Mask und Document bleiben. Und da liegt mein Fehler, ich brauchte es genau anders herrum.
    Ansich wird Polymorphie so angewandt, dass man möglichst wenig oft wissen muss, mit welchen Subtyp man gerade zu tun hat.

    Wie sieht denn ein Beispiel für eine Fallunterscheidung bei dir aus, abgesehen von der Erzeugung der Instanzen?

    Zitat Zitat von dml Beitrag anzeigen
    Mit new kann ich Ihnen einen neuen Typ zuweisen, doch stecke ich dann in dem Problem des Signals dessen Herrausgeber ich ja noch löschen muss. welches ich mit deleteLater() versuchen werde zu lösen. Und nach meiner ersten Testung auch funktioniert hat.
    Ja, deleteLater() ist dafür bestens geeignet. Das echte Löschen des Objekts wird über die Eventloop "verzögert" ausgeführt.


    Übrigens, das disconnect() kannst du auch kürzer so schreiben
    Code:
    mask->disconnect();
    Ciao,
    _
    Qt/KDE Entwickler
    Debian Benutzer

  3. #3
    Registrierter Benutzer
    Registriert seit
    02.08.2008
    Beiträge
    177
    Das Objekt hinter dem Pointer ist nach wie vor vom Typ BookMask.
    Ja aber ich hatte dabei das gleiche Objekt verwendet, weshalb es nur Mask bzw. Document sein konnte.
    Ein Beispiel in meiner Applikation ist ganz einfach:

    Code:
    void MainWidget::setDocumentClass( ){
    qDebug()<<"void MainWidget::setDocumentClass()";
    
    	qDebug()<<"doctype=" << doctype;
    	
    	qDebug()<<"document="<<document<<"|\tmask="<<mask;
    	switch(doctype){
    /*	  
    		case ANIMAL:
    		      qDebug()<<"\ndocument = new AnimalDocument;";
    			      document = (AnimalDocument) new AnimalDocument;
    		      if(!document->start( absolute_document_path ))
    				doctype = EMPTY;
    		      else
    				mask->fill(document->getFileContent(), document->getFileInfo());
    		      break;
    */
    		case BOOK:
    		      qDebug()<<"\nBookDocument";
    		      mask     = (BookMask*) mask;
    		      document = (BookDocument*) document;
    
    		      break;
    		      
    		case RECIPE:
    		      qDebug()<<"\nRecipeDocument";
    		      mask     = (RecipeMask*) mask;
    		      document = (RecipeDocument*) document;
    		      
    		      break;
    		      
    		default:
    		      qDebug()<<"\n\nNo DocType found!";
    		      qDebug()<<"Document";
    		      mask     = mask;
    		      document = document;
    		      
    		      break;
    	}
    		
    	
    	qDebug()<<"document="<<document<<"|\tmask="<<mask;
    }
    anwenden, und man erkennt an qDebug() das der Typ gleich geblieben ist. Wenn man in der Applikation auf Dokument->Bearbeiten drückt, müssten auch nur die Elemente der Basisklasse Mask und nicht der abgeleiteten Klasse BookMask, RecipeMask angezeigit werden.

    Ein Risiko bleibt aber noch, da die Verbindung während des disconnect() Befehles noch aktiv ist. Ich glaube das es funktioniert Da es sonst noch die Methode diconnectLater() geben würde.
    Geändert von dml (26-01-2014 um 21:03 Uhr)

  4. #4
    Administrator Avatar von anda_skoa
    Registriert seit
    17.11.2001
    Ort
    Graz, Österreich
    Beiträge
    5.477
    Das ist in dem Fall kein Beispiel das ich meinte, hier wird nichts mit den Objekten gemacht.

    Ich meinte ein Beispiel, wo du je nach Typ das Mask oder Document Objekt anders behandelst.
    D.h. entweder anderen Code durchläufst oder Methoden der Objekte aufrufst, die nicht in der Basisklasse deklariert sind.

    Ciao,
    _
    Qt/KDE Entwickler
    Debian Benutzer

  5. #5
    Registrierter Benutzer
    Registriert seit
    02.08.2008
    Beiträge
    177
    Code:
    void MainWidget::loadDocument( QString absolute_document_path ){
    
            ...
    	setDocumentClass();
            ...
    		mask->fill(document->getFileContent(), document->getFileInfo());
            ...
    }
    
    void RecipeMask::fill( QString file_content, QFileInfo fileinfo ){
            ...
    	//////////////////////
    	// get preparation  //
    	//////////////////////
            ...
    	        this->preparation_te->setText( exp.cap(1) );
            ...
    }
    Preparation ist nur in der abgeleiteten Klasse RecipeMask enthalten. Vom Methodenaufruf unterscheidet sich der Code nicht.

    Natürlich kann man jetzt sagen, das man eine SuperMaske hätte erstellen können und je nach Anwendungsfall die Members darstellen und auswerten.
    Code:
    class BookMask: public Mask{
            ...  
    	QTextEdit              *description_te;
            ...
    }
    
    class RecipeMask: public Mask{
            ...  
    	QTextEdit              *description_te;
            ...
    }
    Doch finde ich es so viel übersichtlicher.
    Geändert von dml (27-01-2014 um 10:16 Uhr)

  6. #6
    Administrator Avatar von anda_skoa
    Registriert seit
    17.11.2001
    Ort
    Graz, Österreich
    Beiträge
    5.477
    Aber die Methode fill() ist doch bereits in Mask deklariert (virtual) und wird von den Subklassen nur anders implementiert.

    D.h. der Aufruf in MainWidget::loadDocument() wird bereits durch den Polymorphismus auf den jeweiligen Code umgeleitet.

    Code:
    Mask *mask = new RecipeMask;
    
    mask->fill(...); // Aufruf von RecipeMask::fill();
    
    mask = new BookMask;
    
    mask->fill(...); // Aufruf von BookMask::fill();
    Für den Aufruf von fill() ist es bedeutungslos auf welche Subklasse mask gerade veweißt, zur Laufzeit wird die Implementierung der jeweiligen Subklasse ausgeführt.

    Wenn wir diesen Codeschnippsel kurz umschreiben
    Code:
    switch (doctype) {
        case RECIPE:
            mask = new RecipeMask;
            break;
    
        case BOOK:
            mask = new BookMask;
            break;
    }
    
    mask->fill(...);
    dann ist im Falle von doctype == RECIPE in der letzten Zeile ein Aufruf von RecipeMask::fill(), im Falle von doctype == BOOK ein Aufruf von BookMask::fill(), usw.

    Ciao,
    _
    Qt/KDE Entwickler
    Debian Benutzer

  7. #7
    Registrierter Benutzer
    Registriert seit
    02.08.2008
    Beiträge
    177
    In der Hoffnung Dich nicht inzwischen zu Nerven.
    Du hattest Recht der QDebug Befehl gibt Mask( , name="RecipeMask") herraus, ist also weiterhin vom Typ Mask.
    Das bringt mich zu dem Problem:
    Code:
    Document::saveDocument( Mask *mask );
    RecipeDocument::saveDocument( RecipeMask *rmask );
    aufgrund seines Parameters kann ich die Methode nicht als virtual deklarieren und so wird Document::saveDocument ausgeführt. Hast Du dafür vielleicht einen kleinen Tip für mich? Oder sollte ich dann doch besser eine große Maske erstellen die kleine Probleme mehr bereitet?
    Bzw: Wenn ich Maske wieder in Document einfüge muss ich eine Menge leerer virtueller Methoden in der Basisklasse schreiben, damit der Compiler alle Methoden der abgeleiteten Klassen akzeptiert.
    Geändert von dml (27-01-2014 um 16:45 Uhr)

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •