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
    Administrator Avatar von anda_skoa
    Registriert seit
    17.11.2001
    Ort
    Graz, Österreich
    Beiträge
    5.477
    Ich bin mir nicht ganz sicher, was du erreichen möchtest. Der Codeausschnitt gibt dazu zu wenig Informationen.

    Ich nehme an, du hast eine Variable mit dem Basistyp, also z.B. Document *document.
    Der zeigt in Falle von RECIPE auf eine Instanz von RecipeDocument.

    An einer bestimmten Stelle möchtest du mit diesem abgeleiteten Typ arbeiten, z.B. mit Funktionen die in RecipeDocument deklariert sind und in Document nicht vorhanden sind.

    Code:
    class Document
    {
    public:
        virtual ~Document() {}
    };
    
    class RecipeDocument : public Document
    {
    public:
        void printCalories(); // nur in RecipeDocument, nicht in Document
    };
    Code:
    Document *document = new RecipeDocument;
    
    // arbeiten mit den Methoden von Document
    
    // Fallunterscheidung für Spezialanforderungen
    
    switch (type) {
        case RECIPE:
            static_cast<RecipeDocument*>(document)->printCalories();
            break;
    }
    
    // oder für mehrere Aufrufe
    
    switch (type) {
        case RECIPE: {
            RecipeDocument *recipe = static_cast<RecipeDocument*>(document);
            recipe->printCalories();
            // andere RecipeDocument spezifische Aufrufe
            break;
        }
    }
    Oder wenn z.B. der Typ nicht bekannt ist
    Code:
    RecipeDocument *recipeDocument = dynamic_cast<RecipeDocument*>(document);
    if (receipeDocument != 0) {
        recipeDocument->printCalories();
    }
    Als generelle Empfehlung würde ich auf den Einsatz von Casts im C-Stil verzichten, also sowas
    Code:
    (RecipeDocument*)document
    Ciao,
    _
    Qt/KDE Entwickler
    Debian Benutzer

  2. #2
    Registrierter Benutzer
    Registriert seit
    02.08.2008
    Beiträge
    177
    Mein Problem war, das ich ein Objekt nach Bedarf umwandeln wollte:
    Code:
     mask     = (RecipeMask) mask; 
    ...
     mask     = (BookMask) mask;
    Doch das ist schon logisch nicht möglich. Da bei einer Typumwandlung der neue Typ eh neu aufgebaut werden muss. Also einen Konstruktor durchläuft.
    Hinzu kam, das das Signal erst nach Abarbeitung des Slots beendet wird und ich genau in dem Slot das Objekt löschen und neu initialisieren wollte.
    Da fehlt mir halt noch die Übung, aber danke das Du mir den cast noch einmal genauer erklärt hast.
    Auch sind die Mehtodenbezeichnungen MainWidget:newDocument() falsch ind irreführend. Mir fällt derzeit keine richtige Bezeichnung ein, sie müssten in etwa MainWidget::newDocumentAndMask() heissen.
    Geändert von dml (26-01-2014 um 14:36 Uhr)

  3. #3
    Administrator Avatar von anda_skoa
    Registriert seit
    17.11.2001
    Ort
    Graz, Österreich
    Beiträge
    5.477
    Zitat Zitat von dml Beitrag anzeigen
    Mein Problem war, das ich ein Objekt nach Bedarf umwandeln wollte:
    Code:
     mask     = (RecipeMask) mask; 
    ...
     mask     = (BookMask) mask;
    Doch das ist schon logisch nicht möglich.
    Das ist schon möglich, nur muss man sich das Resultat des Casts merken, d.h. die Typinformation nicht gleich wieder verwerfen so wie da in diesem Beispiel der Fall ist.

    Was du hier hast sind quasi zwei Teile:
    1) der Cast, z.b. (BookMask*)mask, besser static_cast<BookMask*>(mask);

    2) eine Zuweisung: mask = resultat_des_cast

    Nach (1) "sieht" der Compiler den gecasteten Typ, also BookMask*.
    "mask" ist aber vom Typ Mask*, d.h. nach (2) "sieht" der Compiler wieder nur die Typinformation Mask*


    Zitat Zitat von dml Beitrag anzeigen
    Da bei einer Typumwandlung der neue Typ eh neu aufgebaut werden muss. Also einen Konstruktor durchläuft.
    Nein. Der Pointercast ändert nichts am Objekt selbst, er verändert lediglich wie der Compiler das Objekt hinter dem Pointer betrachtet.

    Code:
    BookMask *bookMask = new BookMask;
    
    Mask *mask = bookMask; 
    
    BookMask *bookMask2 = bookMask;
    BookMask *bookMask3 = static_cast<BookMask*>(mask);
    Alle view Pointer zeigen auf das selbe Objekt.

    Zitat Zitat von dml Beitrag anzeigen
    Hinzu kam, das das Signal erst nach Abarbeitung des Slots beendet wird und ich genau in dem Slot das Objekt löschen und neu initialisieren wollte.
    Das sollte schon klappen. Der Code, der das Signal aussendet arbeitet davor und danach nur mit dem Basistyp, oder?

    Ciao,
    _
    Qt/KDE Entwickler
    Debian Benutzer

  4. #4
    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

  5. #5
    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

  6. #6
    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)

  7. #7
    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

Lesezeichen

Berechtigungen

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