C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Design Frage

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (German)
View previous topic :: View next topic  
Author Message
albrecht.fritzsche
Guest





PostPosted: Thu Nov 23, 2006 1:13 am    Post subject: Design Frage Reply with quote



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





PostPosted: Thu Nov 23, 2006 6:53 am    Post subject: Re: Design Frage Reply with quote



"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





PostPosted: Thu Nov 23, 2006 1:24 pm    Post subject: Re: Design Frage Reply with quote



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





PostPosted: Thu Nov 23, 2006 3:17 pm    Post subject: Re: Design Frage Reply with quote

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





PostPosted: Fri Nov 24, 2006 1:00 am    Post subject: Re: Design Frage Reply with quote

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





PostPosted: Fri Nov 24, 2006 4:53 am    Post subject: Re: Design Frage Reply with quote

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





PostPosted: Fri Nov 24, 2006 10:11 am    Post subject: Re: Design Frage Reply with quote

"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





PostPosted: Fri Nov 24, 2006 10:11 am    Post subject: Re: Design Frage Reply with quote

"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





PostPosted: Fri Nov 24, 2006 2:48 pm    Post subject: Re: Design Frage Reply with quote

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





PostPosted: Sat Nov 25, 2006 5:13 am    Post subject: Re: Design Frage Reply with quote

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
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (German) All times are GMT
Page 1 of 1

 
Jump to:  
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


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.