Forum: PC-Programmierung C++ Klasse zur Laufzeit aussuchen


von Werner (Gast)


Lesenswert?

Hallo Knobler,

ich möchte zur Laufzeit Klassen instanziieren, wobei erst zur Laufzeit 
anhand einer Konfigurationsdatei bekannt ist welche das konkret sein 
sollen:
1
class Fahrzeug
2
{
3
};
4
5
class Fahrrad: public Fahrzeug
6
{
7
};
8
9
class Auto: public Fahrzeug
10
{
11
};

Die Konfigurationsdatei könnte wie folgt aussehen:
1
config = {"Auto", "Fahrrad", "Fahrrad"};

Nun möchte ich natürlich sowas wie
1
if value=="Fahrrad"
2
  objlist.add(new Fahrrad);
3
else if value=="Auto"
4
  objlist.add(new Auto);
vermeiden, sondern irgendwie automatisiert die richtigen Objekte 
erzeugen.

Weiterhin soll es die Möglichkeit geben dass beim Anlegen eines Objektes 
(z.B. eines Autos) selbiges feststellen kann dass es nicht vollständig 
konfiguriert werden kann (z.B. weil in der config Datei das 
Nummernschild nicht gesetzt ist), und das Objekt gleich wieder zerstört 
wird.

Wie macht man sowas am besten?

Gruß
Werner

von Klaus W. (mfgkw)


Lesenswert?

Dazu braucht jede Klasse eine factory (oder virtueller Konstruktor), 
außerdem muß sich jede abgeleitete Klasse irgendwo anmelden als 
"Fahrrad" etc. und dort einen Zeiger auf ihre statische factory-Methode 
hinterlegen lassen, z.B. in einer map. Über diese Map kann dann mit dem 
Namen ein Objekt erzeugt werden.

von Εrnst B. (ernst)


Lesenswert?

Werner schrieb:
> sondern irgendwie automatisiert die richtigen Objekte
> erzeugen.

mach eine map von "Name im Konfigfile" auf Constructor-Functor, der 
lässt sich als Template recht leicht anlegen.

Werner schrieb:
> ... und das Objekt gleich wieder zerstört
> wird.

wirf eine Exception aus dem Konstruktor.

von Mark B. (markbrandis)


Lesenswert?

Werner schrieb:
> sondern irgendwie automatisiert die richtigen Objekte erzeugen.

Schau Dir mal das Factory Pattern an:
http://en.wikipedia.org/wiki/Factory_pattern

> Weiterhin soll es die Möglichkeit geben dass beim Anlegen eines Objektes
> (z.B. eines Autos) selbiges feststellen kann dass es nicht vollständig
> konfiguriert werden kann (z.B. weil in der config Datei das
> Nummernschild nicht gesetzt ist), und das Objekt gleich wieder zerstört
> wird.

Warum? Auch in der realen Welt kann ein Auto ohne Nummernschild 
existieren. In der Software würde man ein solches Objekt anlegen, und 
sein entsprechendes Attribut (automobil->nummernschild) auf einen 
definierten "undefiniert" :-) Wert setzen.
Nur weil ein Attribut beim Anlegen des Objekts nicht definiert ist, 
heißt das ja nicht, dass es zur Laufzeit niemals dazu kommen kann. Das 
Auto wird vielleicht doch noch zugelassen, oder umgemeldet ;-)

von Werner (Gast)


Lesenswert?

Danke für die schnellen Antworten!

>Warum?

Weil ich natürlich keine Autos und Fahrräder implementiere, sondern 
Objekte die im übertragenem Sinne unbedingt ein Nummernschild brauchen. 
Die Klasse müsste ganz korrekt heißen 
"AutoMitWelchemEsBeiEinerVerkehrskontrolleZuKeinerleiProblemenKommt" ;-)

>Dazu braucht jede Klasse eine factory (oder virtueller Konstruktor),
>außerdem muß sich jede abgeleitete Klasse irgendwo anmelden
Ok, d.h. ich baue mir eine Form von einer Liste (map) in der meine 
config Namen ("Fahrrad", "Auto") mit den entsprechenden abgeleiteten 
Klassen verknüpft sind. In dieses Listenobjekt baue ich eine Methode ein 
der ich den Namen übergebe, und bei einem Match wird in dieser Methode 
der virtuelle Konstruktor aufgerufen. Wozu brauche ich in diesem Fall 
dann noch den virtuellen Konstruktor, ich könnte ja dann gleich den 
normalen Konstruktor aufrufen?
Und wie könnte ich meine Klassen in einer Liste registrieren, solange 
nichts instanziert wird, passiert ja auch nichts...

Gruß
Werner

von Karl H. (kbuchegg)


Lesenswert?

Werner schrieb:

>>Dazu braucht jede Klasse eine factory (oder virtueller Konstruktor),
>>außerdem muß sich jede abgeleitete Klasse irgendwo anmelden
> Ok, d.h. ich baue mir eine Form von einer Liste (map) in der meine
> config Namen ("Fahrrad", "Auto") mit den entsprechenden abgeleiteten
> Klassen verknüpft sind.

Eigentlich nicht mit der Klasse an sich, sonder mit einer Funktion, die, 
wenn man sie aufruft, ein entsprechendes Objekt erzeugt und 
zurückliefert.

Diese Funktion nennt man den 'virtuellen Konstruktor'.

von Werner (Gast)


Lesenswert?

>Diese Funktion nennt man den 'virtuellen Konstruktor'.
Jetzt komme ich durcheinander; ich dachte der virtuelle Konstruktor ist 
die statische Methode in meinen abgeleiteten Klassen, in der das Objekt 
(z.B. ein Fahrrad) instanziiert wird?

von Mark B. (markbrandis)


Lesenswert?

Werner schrieb:

> Weil ich natürlich keine Autos und Fahrräder implementiere, sondern
> Objekte die im übertragenem Sinne unbedingt ein Nummernschild brauchen.
> Die Klasse müsste ganz korrekt heißen
> "AutoMitWelchemEsBeiEinerVerkehrskontrolleZuKeinerleiProblemenKommt" ;-)

automobil->fahrer->setPromillewert(NUR_EIN_BIER_EHRLICH);

Hier ist ein Beispiel zum virtuellen Konstruktor:
http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Virtual_Constructor

von Karl H. (kbuchegg)


Lesenswert?

Werner schrieb:
>>Diese Funktion nennt man den 'virtuellen Konstruktor'.
> Jetzt komme ich durcheinander; ich dachte der virtuelle Konstruktor ist
> die statische Methode in meinen abgeleiteten Klassen, in der das Objekt
> (z.B. ein Fahrrad) instanziiert wird?

ist es ja auch.
Am besten ein Beispiel studieren.

von Werner (Gast)


Lesenswert?

>Am besten ein Beispiel studieren.

Das versuche ich gerade, z.B. das hier:

http://de.wikipedia.org/wiki/Fabrikmethode#Ein_Beispiel_in_C.2B.2B

Ich schaffe es nicht das ganze auf meine Problemstellung zu übertragen, 
und ich sehe in diesem Beispiel weit und breit keine statischen 
Methoden.

Muss ich meine Problemstellung so aufbauen?
1
class Fahrzeug
2
{
3
  virtual Fahrzeug* Create(void) = 0;
4
};
5
6
class Fahrrad: public Fahrzeug
7
{
8
//ist das nun eine factory method??!
9
  virtual Fahrzeug* Create(void) {return new Fahrrad};
10
};
11
12
class Auto: public Fahrzeug
13
{
14
//ist das nun eine factory method??!
15
  virtual Fahrzeug* Create(void) {return new Auto};
16
};

Die Create Methode kann ich ja nun nicht aufrufen, da es noch nicht mal 
ein Objekt gibt?

von Εrnst B. (ernst)


Lesenswert?

Werner schrieb:
> Die Create Methode kann ich ja nun nicht aufrufen, da es noch nicht mal
> ein Objekt gibt?

Falsches Pattern.

eher sowas:
1
class base_constructor_func {
2
public:
3
  virtual Fahrzeug * create()=0;
4
};
5
6
template <class XYZ>
7
class constructor_func: public base_constructor_func {
8
public:
9
  Fahrzeug * create() { return new XYZ; } // oder "operator()()"
10
};
11
12
13
std::map<std::string, base_constructor_func*> constructors;
14
15
...
16
constuctors["Auto"]=new constructor_func<Auto>();
17
constuctors["PKW"]=new constructor_func<Auto>();
18
constuctors["Fahrrad"]=new constructor_func<Fahrrad>();
19
constuctors["LKW"]=new constructor_func<Lastwagen>();
20
21
22
...
23
24
Fahrzeug * neues_fahrzeug=constructors[configfile.xyz]->create();

Ach ja, die Pointer in der map sind nicht unbedingt guter Stil. Ggfs. 
shared_ptr oder sowas stattdessen verwenden.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.