 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
albrecht.fritzsche Guest
|
Posted: Thu Nov 23, 2006 1:13 am Post subject: Design Frage |
|
|
Irgendwie ist mein Kopf gerade blockiert - vielleicht sieht ja jmd die
beste Lösung (ich parse Xml sequentiell und halte die gelesenen Elemente
auf einem Stack):
Hier der Stand
class Element {
public:
virtual ~Element() {}
virtual const char* get_name() const = 0;
};
...lots of Leafs like...
class Foo : public Element {
public:
const char* get_name() const { return "Foo"; }
};
vector<Element*> myStack; // yeah, in reality with smart_ptrs
Nun haben aber ca. 40% der Leafs ein Datum A und bräuchten also dafür
Access- und Retrieval-Funktionen a la
class Foo_with_a : public Element {
public:
const char* get_name() const { return "Foo"; }
void set_a(const A& a) { m_a = a; }
const A& get_a() const { return m_a; }
private:
A m_a;
};
Okay, einfach eine Element_with_a Zwischenklasse und
class Foo_with_a : public Element_with_a {
...
};
*Aber* andere ca. 40% (dh nicht disjunkt, sonder überlappend) der Leafs
haben ein Datum B, und manche - damit es nicht zu einfach ist - beides,
dh sowohl ein A als auch ein B.
Wie ist der einfachste Weg, sich diese ganzen Kopien der Daten-Zugriffe
zu sparen und zB mittels Inheritance zu lösen?
Meine erste Idee: multiple Inheritance
HolderOfA Element HolderOfB
\ / | \ / |
ElementWithA Leaf ElementWithB |
\ |
ElementWithBothAAndB --+
Zum einen scheint das nicht ganz zu funktionieren, zum anderen gefällt
mir das nicht so ganz. Was sind einfache Lösungen, Element frei von
solchen Daten zu halten, aber nicht in allen Leafs diese Daten-Zugriffe
implementieren zu müssen?
Danke für jeden Hinweis
Ali |
|
| Back to top |
|
 |
Markus Schaaf Guest
|
Posted: Thu Nov 23, 2006 6:53 am Post subject: Re: Design Frage |
|
|
"albrecht.fritzsche" <albrecht.fritzsche (AT) arcor (DOT) de> schrieb:
| Quote: | Meine erste Idee: multiple Inheritance
HolderOfA Element HolderOfB
\ / | \ / |
ElementWithA Leaf ElementWithB |
\ |
ElementWithBothAAndB --+
Zum einen scheint das nicht ganz zu funktionieren, zum anderen gefällt
mir das nicht so ganz.
|
/Was/ gefällt Dir denn daran nicht? Der Konsistenz wegen würde ich
struct ElementWithBothAAndB : Element, HolderOfA, HolderOfB
ableiten. |
|
| Back to top |
|
 |
Rolf Magnus Guest
|
Posted: Thu Nov 23, 2006 1:24 pm Post subject: Re: Design Frage |
|
|
Markus Schaaf wrote:
| Quote: | "albrecht.fritzsche" <albrecht.fritzsche (AT) arcor (DOT) de> schrieb:
Meine erste Idee: multiple Inheritance
HolderOfA Element HolderOfB
\ / | \ / |
ElementWithA Leaf ElementWithB |
\ |
ElementWithBothAAndB --+
Zum einen scheint das nicht ganz zu funktionieren, zum anderen gefällt
mir das nicht so ganz.
/Was/ gefällt Dir denn daran nicht? Der Konsistenz wegen würde ich
struct ElementWithBothAAndB : Element, HolderOfA, HolderOfB
ableiten.
|
Dann kann er aber ElementWithBothAAndB nicht als ElementWithA oder
ElementWithB ansprechen, was es ja rein logisch eigentlich sein sollte. Ich
denke, das kann man nur mit virtueller Vererbung lösen. |
|
| Back to top |
|
 |
albrecht.fritzsche Guest
|
Posted: Thu Nov 23, 2006 3:17 pm Post subject: Re: Design Frage |
|
|
Markus Schaaf wrote:
| Quote: | Zum einen scheint das nicht ganz zu funktionieren, zum anderen gefällt
mir das nicht so ganz.
/Was/ gefällt Dir denn daran nicht?
|
Gerade die Inkonsistenz - dank Deines Vorschlags gelöst.
| Quote: | Der Konsistenz wegen würde ich
struct ElementWithBothAAndB : Element, HolderOfA, HolderOfB
ableiten.
|
Ja danke, werd's ausprobieren - gestern gab's zur Laufzeit dann so
seltsame Probleme, dass ich den Wald vor lauter Bäumen nicht mehr sah.
Ali |
|
| Back to top |
|
 |
albrecht.fritzsche Guest
|
Posted: Fri Nov 24, 2006 1:00 am Post subject: Re: Design Frage |
|
|
Rolf Magnus wrote:
| Quote: | Markus Schaaf wrote:
/Was/ gefällt Dir denn daran nicht? Der Konsistenz wegen würde ich
struct ElementWithBothAAndB : Element, HolderOfA, HolderOfB
ableiten.
Dann kann er aber ElementWithBothAAndB nicht als ElementWithA oder
ElementWithB ansprechen, was es ja rein logisch eigentlich sein sollte.
|
Ja, genau dies hatte ich vorher versucht.
| Quote: | Ich
denke, das kann man nur mit virtueller Vererbung lösen.
|
Dies wollte ich vermeiden.
Nun stöber ich gerade ein bisschen in "Mixin-Based Programming" Papers.
Das kenne ich nicht, aber vielleicht findet sich dort was.
Nun lebe ich aber ersteinmal mit der oben vorgeschlagenen Variante.
Danke
Ali |
|
| Back to top |
|
 |
albrecht.fritzsche Guest
|
Posted: Fri Nov 24, 2006 4:53 am Post subject: Re: Design Frage |
|
|
albrecht.fritzsche wrote:
| Quote: | Nun stöber ich gerade ein bisschen in "Mixin-Based Programming" Papers.
Das kenne ich nicht, aber vielleicht findet sich dort was.
|
Ok, mit Mixins kann ich sowas schreiben (siehe weiter unten). Der
Vorteil nun ist, dass die Vererbung klar ist und man auch ohne virtuelle
Vererbung auskommt. Sieht jmd da irgendwelche gravierenden Nachteile?
Ali
// abstract subclass
template <typename Base>
class A_holder : public Base {
public:
void set_a(const A& a) { a_ = a; }
const A& get_a() const { return a_; }
private:
A a_;
};
// abstract subclass
template <typename Base>
class B_holder : public Base {
public:
void set_b(const B& b) { b_ = b; }
const B& get_b() const { return b_; }
private:
B b_;
};
// abstract base class
class Element {
public:
virtual ~Element() {}
virtual void print() const = 0;
};
// der eigentliche Clou
typedef A_holder<Element> Element_with_a;
typedef B_holder<Element> Element_with_b;
typedef A_holder<B_holder<Element> > Element_with_ab;
// ein paar Instanziierungen
class SimpleLeaf : public Element {
public:
void print() const { cout << " SimpleLeaf "; }
};
class ALeaf : public Element_with_a {
public:
void print() const {
cout << " AElement ";
const A& a = this->get_a();
}
};
class BLeaf : public Element_with_b {
public:
void print() const {
cout << " BElement ";
const B& b = this->get_b();
}
};
class ABLeaf : public Element_with_ab {
public:
void print() const {
cout << " ABElement ";
const A& a = this->get_a();
const B& b = this->get_b();
}
}; |
|
| Back to top |
|
 |
Markus Schaaf Guest
|
Posted: Fri Nov 24, 2006 10:11 am Post subject: Re: Design Frage |
|
|
"Rolf Magnus" <ramagnus@t-online.de> schrieb:
| Quote: | Markus Schaaf wrote:
"albrecht.fritzsche" <albrecht.fritzsche (AT) arcor (DOT) de> schrieb:
Meine erste Idee: multiple Inheritance
HolderOfA Element HolderOfB
\ / | \ / |
ElementWithA Leaf ElementWithB |
\ |
ElementWithBothAAndB --+
Zum einen scheint das nicht ganz zu funktionieren, zum anderen gefällt
mir das nicht so ganz.
/Was/ gefällt Dir denn daran nicht? Der Konsistenz wegen würde ich
struct ElementWithBothAAndB : Element, HolderOfA, HolderOfB
ableiten.
Dann kann er aber ElementWithBothAAndB nicht als ElementWithA oder
ElementWithB ansprechen, was es ja rein logisch eigentlich sein sollte.
|
Dieser Gedankengang scheint mir mit dem Obigen erstmal nichts zu
tun zu haben. Die Vererbung von "HolderOfA" und "HolderOfB"
dient ja laut der bisher bekannten Aufgabenstellung der Vererbung
von Implementierung, nicht eines Interfaces. Dementsprechend hat
auch nur "Element" virtuelle Methoden. |
|
| Back to top |
|
 |
Markus Schaaf Guest
|
Posted: Fri Nov 24, 2006 10:11 am Post subject: Re: Design Frage |
|
|
"albrecht.fritzsche" <albrecht.fritzsche (AT) arcor (DOT) de> schrieb:
| Quote: | Ok, mit Mixins kann ich sowas schreiben (siehe weiter unten). Der
Vorteil nun ist, dass die Vererbung klar ist und man auch ohne virtuelle
Vererbung auskommt. Sieht jmd da irgendwelche gravierenden Nachteile?
|
Es ist genau das gleiche wie vorher, nur mit Templates. Irgendwie
lässt Du Dich zu leicht davontreiben. Überlege doch mal als
Erstes, was für ein Design Du /brauchst/. Am Ende wird es
vielleicht ein "polymorpher" Container mit Visitor-Interface. |
|
| Back to top |
|
 |
albrecht.fritzsche Guest
|
Posted: Fri Nov 24, 2006 2:48 pm Post subject: Re: Design Frage |
|
|
Markus Schaaf wrote:
| Quote: | Es ist genau das gleiche wie vorher, nur mit Templates.
|
Bist Du Dir da sicher? Immerhin wurde im ersten Vorschlag Multiple
Inheritance verwendet, in der Template-Version hingegen nur einfache.
Das halte ich schonmal für einen Vorteil.
<vager Hintergrund>
Ich weiss das leider nicht mehr so genau, hatte aber wohl mal Probleme mit
struct Foo : public A, public B {};
// *a ist wirklich ein Foo-Objekt
B* retrieve_b(A* a) { return static_cast<Foo*>(a); }
weshalb ich bei multipler Inheritance nun auch immer einen statischen
Up-Cast hinzufüge.
</vager Hintergrund>
| Quote: | Irgendwie
lässt Du Dich zu leicht davontreiben. Überlege doch mal als
Erstes, was für ein Design Du /brauchst/. Am Ende wird es
vielleicht ein "polymorpher" Container mit Visitor-Interface.
|
Ja, das wollte ich eigentlich vermeiden. Und als Anlass meiner Frage
stand nur, Schreibarbeit zu sparen. Jedes zweite Collada-Element hat ein
asset-Child und jedes dritte Collada-Element ein extra-Child (Collada
ist ein 3D-Xml-Format). Vielleicht gibt's noch mehrere solcher oft
verwendeten Children - die jeweiligen getter/setter möchte ich mir sparen.
Danke
Ali |
|
| Back to top |
|
 |
Falk Tannhäuser Guest
|
Posted: Sat Nov 25, 2006 5:13 am Post subject: Re: Design Frage |
|
|
albrecht.fritzsche schrieb:
| Quote: | Immerhin wurde im ersten Vorschlag Multiple
Inheritance verwendet, in der Template-Version hingegen nur einfache.
Das halte ich schonmal für einen Vorteil.
vager Hintergrund
Ich weiss das leider nicht mehr so genau, hatte aber wohl mal Probleme mit
struct Foo : public A, public B {};
// *a ist wirklich ein Foo-Objekt
B* retrieve_b(A* a) { return static_cast<Foo*>(a); }
|
Das wäre ein Cross-cast. Wenn A polymorph ist (also z.B. virtuellen
Destruktor spendieren), geht
B* b = dynamic_cast<B*>(a);
was gegenüber der Variante mit static_cast<Foo*> den Vorteil hat, im
Fehlerfall (a zeigt nicht auf ein Foo-Objekt) statt Müll NULL
zurückzugeben. Weiterhin braucht die Klasse Foo im Kontext des
dynamic_cast nicht bekannt zu sein.
MfG
Falk |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|