Seite 1 von 1

Objekt umwandeln / zurückwandeln ?

Verfasst: 29. Juli 2009 19:25
von lx2
Hi,

ich sitzt jetzt schon seit Stunden über ein und dem selben Problem. :shock:

Ich habe eine Klasse von QTreeWidgetItem abgeleitet.
Diese Klasse ist fast identisch, bis auf dass sie zusätzlich eine QDomElement abspeichert, das beim Konstrukor angegeben wird.


dlatreewidgetitem.h

Code: Alles auswählen

#ifndef DLATREEWIDGETITEM_H
#define DLATREEWIDGETITEM_H

#include <QTreeWidgetItem>
#include <QtXml>

class DlaTreeWidgetItem : public QTreeWidgetItem
{
public:
    DlaTreeWidgetItem();
    DlaTreeWidgetItem(QDomElement myelem, QTreeWidgetItem *parentItem);
    QDomElement e;
};

#endif // DLATREEWIDGETITEM_H

dlatreewidgetitem.cpp

Code: Alles auswählen

#include "dlatreewidgetitem.h"

DlaTreeWidgetItem::DlaTreeWidgetItem()
{
}

DlaTreeWidgetItem::DlaTreeWidgetItem(QDomElement myelem , QTreeWidgetItem *parentItem):QTreeWidgetItem(parentItem){
    this->e = myelem;

}


Jetzt mochte ich in meinem QTreeWidget , immer wenn ich auf ein DlaTreeWidgetItem klicke, ein gewisses Attribut aus dem darin gespeicherten QDomElement zurückbekommen. Das erste Problem ist, dass ich vom QTreeWidget nur den

SLOT itemClicked(QTreeWidgetItem*,int) zu verfügung hab.
Was ich eigentlich bräuchte wäre ja itemClicked(DlaTreeWidgetItem*,int)

Einfach mal ignorieren... dacht ich mir. Geht ja trotzden, weil DlaTreeWidgetItem geerbt hat. Also hab ich mal schön verbunden:

Code: Alles auswählen

    connect( ui->treeWidget , SIGNAL(itemClicked(QTreeWidgetItem*,int)),
             this , SLOT(setMyText(QTreeWidgetItem*, int)));
Das klappt auch soweit, er ekennt also Klicks auf DlaTreeWidgetItems. Jetzt wieder zurück zum Problem:

Code: Alles auswählen

void MainWindow::setMyText(QTreeWidgetItem *mywid, int i){
    ui->label->setText(mywid->e.attribute("title"));
}
So wollt ich stur einfach erzwingen, dass er mir das Attribut ausgibt. Geht natürlich nicht - compiler meckert:
error: 'class QTreeWidgetItem' has no member named 'e'
Gibt es eine Möglichkeit das übergebene QTreeWidgetItem in der Methode setMyText() zurückwandeln? Oder kennt ihr irgend eine andere Lösung???

vielen Dank schon mal dass ihr es bis hierher geschafft habt! ;)
Auf Antworten würde ich mich riesig freuen :!:
Beste Grüße aus München

Verfasst: 29. Juli 2009 19:29
von upsala

Code: Alles auswählen

DlaTreeWidgetItem *mywid=dynamic_cast<DlaTreeWidgetItem*>(item);

JUHUUUU

Verfasst: 29. Juli 2009 19:48
von lx2
DANKE DANKE DANKE!

Das war es fast. So geht es:

Code: Alles auswählen

void MainWindow::setMyText(QTreeWidgetItem *mywid, int i){
    DlaTreeWidgetItem *newit=dynamic_cast<DlaTreeWidgetItem*>(mywid);
    ui->label->setText(newit->e.attribute("title"));
}

Jetzt brauch ich nur noch ein return value ob der Typecast geklappt hat, sonst schmiert er mir ab, weil auch noch normale QTreeWidgetItems im Baum hängen. Merci

Verfasst: 29. Juli 2009 19:52
von upsala
Du könntest auch in deiner C++-Doku nachsehen, was der Rückgabewert von dynamic_cast ist, wenn das Element nicht passt.

Verfasst: 29. Juli 2009 20:17
von -=Freaky=-
das interessiert mich, auch wenns absolut off-topic ist:
gibts in der form wirklich rueckgabewerte fuer c++ casts?
dachte es werden nur entspr. exceptions geworfen?

mfg,
julian

Verfasst: 29. Juli 2009 20:36
von franzf
-=Freaky=- hat geschrieben:gibts in der form wirklich rueckgabewerte fuer c++ casts?
dachte es werden nur entspr. exceptions geworfen?
Bei mir ist noch nie ne exception geworfen worden. Wenn der cast nicht klappt, gibt es eben nen nullptr zurück.

// edit:
http://cplusplus.com/reference/std/typeinfo/bad_cast/
wird nur geworfen, wenn man Referenezen castet, nicht aber mit pointern :)

Verfasst: 29. Juli 2009 21:20
von -=Freaky=-
hm, hast recht ...
d.h. es ist nicht eindeutig, denn zumindest laut msdn (erste google ergebnisse ;)) werden nullptr auch zu nullptr des gewuenschten typs gecastet, und in dem fall waere es kein indikator fuer nen fehler.

mfg,
julian

Verfasst: 29. Juli 2009 22:45
von solarix
-=Freaky=- hat geschrieben:hlaut msdn (erste google ergebnisse ;))
Also bei der Doku von MS-Managed-C++ wäre ich etwas misstrauisch was den Standard betrifft..
-=Freaky=- hat geschrieben:nullptr auch zu nullptr des gewuenschten typs gecastet, und in dem fall waere es kein indikator fuer nen fehler.
Hä? NULL ist NULL..egal ob von "void*" oder "Foo*"

Verfasst: 29. Juli 2009 23:47
von -=Freaky=-
solarix hat geschrieben:
-=Freaky=- hat geschrieben:hlaut msdn (erste google ergebnisse ;))
Also bei der Doku von MS-Managed-C++ wäre ich etwas misstrauisch was den Standard betrifft..
-=Freaky=- hat geschrieben:nullptr auch zu nullptr des gewuenschten typs gecastet, und in dem fall waere es kein indikator fuer nen fehler.
Hä? NULL ist NULL..egal ob von "void*" oder "Foo*"
stimmt beides, zweiteres dachte ich mir genauso, warum sollte es auch anders sein, aber da stands so, wenn ich mich nicht verlesen hab ...

mfg,
julian

Verfasst: 30. Juli 2009 12:41
von RHBaum
Aber gleich mal den virtuellen Zeigefinger hochheben !

Nen upcast ist immer nen Indikator fuer ne Design-Schwaeche !!!
dynamic_cast funktioniert nur, wenn RTTI im compiler eingeschalten iss, sonst gibts immer Nullpointer. Sollte aber bei QT - programmen soweiso an sein.
Oder kennt ihr irgend eine andere Lösung???
Versuch mal hinter das MVC Konzept zu steigen.
Und ich versprech dir, du willst bei der QT und den ganzen Table,List und treeviews keine Itembasierenden Versionen mehr verwenden :-) Naja, ok in ausnahmefällen vielleicht.

Ich habe eine Klasse von QTreeWidgetItem abgeleitet.
Diese Klasse ist fast identisch, bis auf dass sie zusätzlich eine QDomElement abspeichert, das beim Konstrukor angegeben wird.
Mir kraeuseln sich grad die Fussnägel :twisted:

C++ Designregeln:

- Klassen klein und uebersichtlich halten. Eine Klasse fuer genau eine Funktionalitaet !
- öffentlich Vererben nicht um code wiederzuverwenden sondern ausschliesslich um unterschiedlichen klassen eine einheitliche Schnittstelle zu verpassen und damit ermöglichen, funktionalitaeten unterschiedliche klassen zur laufzeit unterzuschieben.

du versteosst gegen beide regeln.

Du erweiterst TreeWidget item mit ner serialize funktion ....das heisst dein neues element ist Treewidget und serializer zugleich.

Du wirst in dem context immer nur die neue erweiterte Klasse verwenden. Sprich deinen Funktionalitaeten wirst du nie zur laufzeit mal ne Instanz von nem orginalen TreewidgetItem und dann mal eine Instanz von deiner neuen klasse unterschieben. Ergo -> Polymorphie unnötig !

Besser:
schreib dir nen "Adapter" oder ne konvertierungsfunktion, der QTreewidget Items uebernimmt, und deren Inhalt in eine DomStruktur ueberfuehsrt ....
Das wird dir auf dauer viel viel aerger ersparen ^^ und wird in lesbareren und damit wartbareren Code resultieren.

Mit der Zeit wirst das aber lernen, gutes C++ design iss definitiv erlernbar.
Grad vererbung ist einer der groesseren Fallstricke fuer c++ Einsteiger. Die meisten verwenden das zu extensiv und an den falschen stellen.

Ciao ....

Verfasst: 3. August 2009 22:48
von lx2
- Klassen klein und uebersichtlich halten. Eine Klasse fuer genau eine Funktionalitaet !
- öffentlich Vererben nicht um code wiederzuverwenden sondern ausschliesslich um unterschiedlichen klassen eine einheitliche Schnittstelle zu verpassen und damit ermöglichen, funktionalitaeten unterschiedliche klassen zur laufzeit unterzuschieben.

du versteosst gegen beide regeln.
Ich bin zwar erst am Anfang meiner OOP-Erfahrungen, aber mit der Sache mit der Vererbung kann ich dir nicht ganz zustimmen (nicht böse gemeint ;) ).
Es besteht zwar die öffentliche Diskussion, ob der Grundanspekt der Vererbung die Polymorphie ist, man kann jedoch Vererbung auch dazu benutzen um eine Klasse mit Funktionalität/Eigenschaften (also mit Attributen und Methoden) "tieferzulegen" beziehungsweise auch einzuschränken. Ich wüsste nicht wie dadurch das ganze unübersichtlich wird? In der Uni sagt man immer, eine Klasse "hat was" (=Attribute) und "kann was" (=Methoden). Wenn diese Klasse ganau für meinen zweck Passt und nur ein Attribut fehlt, wiso soll ich die nicht wiederverwenden und ganau das was ich brauch rankleben?

Verfasst: 3. August 2009 23:51
von -=Freaky=-
lx2 hat geschrieben:
- Klassen klein und uebersichtlich halten. Eine Klasse fuer genau eine Funktionalitaet !
- öffentlich Vererben nicht um code wiederzuverwenden sondern ausschliesslich um unterschiedlichen klassen eine einheitliche Schnittstelle zu verpassen und damit ermöglichen, funktionalitaeten unterschiedliche klassen zur laufzeit unterzuschieben.

du versteosst gegen beide regeln.
Ich bin zwar erst am Anfang meiner OOP-Erfahrungen, aber mit der Sache mit der Vererbung kann ich dir nicht ganz zustimmen (nicht böse gemeint ;) ).
Es besteht zwar die öffentliche Diskussion, ob der Grundanspekt der Vererbung die Polymorphie ist, man kann jedoch Vererbung auch dazu benutzen um eine Klasse mit Funktionalität/Eigenschaften (also mit Attributen und Methoden) "tieferzulegen" beziehungsweise auch einzuschränken. Ich wüsste nicht wie dadurch das ganze unübersichtlich wird? In der Uni sagt man immer, eine Klasse "hat was" (=Attribute) und "kann was" (=Methoden). Wenn diese Klasse ganau für meinen zweck Passt und nur ein Attribut fehlt, wiso soll ich die nicht wiederverwenden und ganau das was ich brauch rankleben?
vllt. versteh ich das auch falsch, aber ich denke, das wort "öffentlich" (->public) spielt in dem satz schon eine rolle.

mfg,
julian

Verfasst: 6. August 2009 09:46
von RHBaum
Ich wüsste nicht wie dadurch das ganze unübersichtlich wird?
Auf den ersten Blick und bei kleineren Projekten sicherlich wirst kaum die auswirkungen spueren.
Aber bei groesseren Projecten mit klassen im mehr als 2 stelligen bereich und paar komplexeren beziehungen untereinander wirst schnell ins schwitzen geraten.

Unnötige vererbung fuehrt oft zu unnötig imperformanten (vtables wo man keine braucht, optimierungen vom compiler werden verhindert), unnötig tiefe Abhaengigkeitshirarchien, code zum umgehen von logischen Unzulaenglichenkeiten bei unsachgemeaesser vererbung (diamond of death) ....

Bei 80% der Fälle fällts vielleicht gar ned so auf, weil die klasse selber nimmer erweitert wird, sie kein mitglied einer Hirarchie ist, die performance keine so bedeutende rolle spielt ...
Aber man sollt so frueh wie möglich anfangen, Vererbung lieber 2 mal hinterfragen, bevor man sie wirklich verwendet ! Bei komplexeren strukturen ist das goldwert !
Wenn diese Klasse ganau für meinen zweck Passt und nur ein Attribut fehlt, wiso soll ich die nicht wiederverwenden und ganau das was ich brauch rankleben?
Vererbung ist nicht die einzigste Technik zur Wiederverwendung. Um funktionalitaet wiederzuverwenden sollte Aggregation (bzw Komposition als Sonderform) die erste Wahl sein.

Wenn Du dich wirklich eingehend mit c++ Design beschaeftigen willst, solltest Du auch entsprechende Literatur zu lesen ....

empfehlen kann ich:
Effective c++
exceptional c++
modern c++ design

In einem von den buechern wird auch genau da drauf eingegangen, warum unnötige vererbung so ein Fallstrick ist.

Ciao ...