Forum: PC-Programmierung [c++] vector mit pointern von template klasse


von Operator S. (smkr)


Lesenswert?

Ich habe folgendes Problem, welches ich nicht weiss wie elegant zu lösen 
ist.

In meinem Programm exisitert eine Template Klasse, welche als int, 
double oder bool instanziert wird. Wie ist es möglich, auf diese 
verschiedenen Klassen zuzugreifen, ohne jeweils einen cast machen zu 
müssen?

Als Beispiel folgender dummy code
1
template<class T>
2
class Item
3
{
4
    T Data;
5
public:
6
    Item() : Data( T() )
7
    {}
8
9
    void sync()
10
    {
11
        // sync algo
12
    }
13
};
14
15
int main (){ 
16
    Item<int> itemI;
17
    Item<double> itemD;
18
    Item<bool> itemB;
19
20
    std::vector< ?* > v;
21
    v.push_back(&itemI);
22
    v.push_back(&itemD);
23
    v.push_back(&itemB);
24
25
    v[0].sync();
26
}

Meine Lösung bisher war immer eine abstrakte Klasse zu erzeugen, welche 
diese Funktionen zur Verfügung stellt. Dann enthält der Vector eben 
pointer dieser abstrakten Klasse. Dabei geht aber immer viel 
Schreibarbeit einher und es müssen zwei Klassen von Hand gepflegt 
werden.

Gibt es dazu eine Lösung in der C++ Sprachwelt?

von Peter II (Gast)


Lesenswert?

leite doch dein Template von einer gemeinsamen Klasse ab, wo die syn als 
virtuell vorhande ist.

von Operator S. (smkr)


Lesenswert?

Ja, wie gesagt so habe ich es bisher gemacht. Gemäss obigem Beispiel 
sähe das so aus:
1
class BaseItem {
2
public:
3
  virtual ~BaseItem() = 0;
4
  virtual void sync() = 0;
5
protected:
6
  inline BaseItem() {};
7
8
};
9
10
template<class T>
11
class Item
12
{
13
    T Data;
14
public:
15
    Item() : Data( T() )
16
    {}
17
18
    void sync()
19
    {
20
        // sync algo
21
    }
22
};
23
24
...
25
std::vector< BaseItem* > v;
26
...

Nur dachte ich halt dass es sich hier im ein standardproblem handelt, 
mit welchem ich sicher nicht alleine dastehe. Und darum wollte ich 
nachfragen, ob es irgendwie möglich ist einen generischen pointer auf 
die templateklasse zu erhalten. Denn typunabhängig ist durch die 
templateisierung gegeben, dass alle Objekte diese Funktion implementiert 
haben. Nichts anderes wird durch eine abstrakte Klasse erreicht.

von Dr. Sommer (Gast)


Lesenswert?

Operator S. schrieb:
> Und darum wollte ich
> nachfragen, ob es irgendwie möglich ist einen generischen pointer auf
> die templateklasse zu erhalten.
Nein, das geht nicht. Die Klassen Item<int>, Item<double>, Item<bool> 
haben nichts miteinander zu tun und sind völlig unabhängig 
voneinander. Die Standardlösung ist, wie du schon erkannt hast, das 
Ableiten von einer gemeinsamen Basisklasse.

Operator S. schrieb:
> dass alle Objekte diese Funktion implementiert
> haben.
Richtig, aber C++ ist keine dynamische Sprache. Die drei Funktionen 
haben drei unterschiedliche Adressen im Programmspeicher, und beim 
Aufruf auf der Instanz im Vektor muss diese Adresse irgendwie 
herausgefunden werden. Das geht eben z.B. über virtuelle Funktionen und 
die gemeinsame Basisklasse. Einfach nur eine Funktion eines bestimmten 
Namens in einer beliebigen Klasse aufrufen geht nicht.
Die einzigen Container, die völlig unterschiedliche Klassen (wie eben 
Item<int>, Item<double> ... ) aufnehmen können sind std::tuple und 
std::pair, aber die haben feste Größe.

von Dr. Sommer (Gast)


Lesenswert?

Operator S. schrieb:
> Nichts anderes wird durch eine abstrakte Klasse erreicht.
Falsch, die gemeinsame abstrakte Klasse lässt den Compiler eine vtable 
anlegen, über die die Adresse der aufzurufenden Funktion gefunden wird.

So super viel Schreibarbeit ist die gemeinsame Klasse doch auch nicht:
1
#include <memory>
2
#include <vector>
3
4
class BaseItem {
5
public:
6
  virtual ~BaseItem() {} // Destruktor nicht definieren führt zu undefined-reference-Error
7
  virtual void sync() = 0;
8
protected:
9
  inline BaseItem() {};
10
};
11
12
template<class T>
13
class Item : public BaseItem
14
{
15
    T Data;
16
public:
17
    Item() : Data {} // <- das reicht so auch
18
    {}
19
20
    virtual void sync() override // <- klarer so
21
    {
22
        // sync algo
23
    }
24
};
25
26
int main () {
27
  std::vector<std::unique_ptr<BaseItem>> v;
28
  v.emplace_back (new Item<int>);
29
  v.emplace_back (new Item<double>);
30
31
  for (auto& item : v) {
32
    item->sync ();
33
  }
34
  // Freigabe erfolgt automatisch dank unique_ptr, kein delete nötig
35
}

von Operator S. (smkr)


Lesenswert?

Danke für die Antworten, ergibt schon Sinn, dass die Klassen nicht 
dieselben sind.

Dr. Sommer schrieb:
> So super viel Schreibarbeit ist die gemeinsame Klasse doch auch nicht:

Naja, aber sie ist halt da, obwohl dies auch automatisch erzeugt werden 
könnte. Und ein template setzt man in erster linie ein, um 
Doppelspurigkeiten zu vermeiden, ansonsten könnte man auch gleich die 
Klassen überladen statt ein template zu schreiben ;-)

In meinem Fall handelt es sich um ca 5-8 template Klassen mit je 2-10 
Methoden welche ich in abstrakte Klassen packen muss.

von Oliver S. (oliverso)


Lesenswert?

Operator S. schrieb:
> Und ein template setzt man in erster linie ein, um
> Doppelspurigkeiten zu vermeiden, ansonsten könnte man auch gleich die
> Klassen überladen statt ein template zu schreiben ;-)

Vietuelle Klassen sind zwar heutzutage oldschool, aber immer noch ein 
durchaus probates Mittel der Wahl.

Oliver

von Operator S. (smkr)


Lesenswert?

Oliver S. schrieb:
> heutzutage oldschool

Meinst du damit: ist seit Jahren bekannt und etabliert
oder: früher machte man das so, heute gibts andere Lösungen

Wenn letzteres, welche wären das? Mag auch nur ein Link auf einen 
Artikel o.Ä. sein.

von Oliver S. (oliverso)


Lesenswert?

Ich meine damit: Wenn die Struktur sich am besten durch virtuelle 
Klassen darstellen lässt, dann soll man die auch nutzen, und keine 
Templates dafür missbrauchen (sofern es keine anderen guten Gründe für 
den Einsatz von Templates gibt).

Oliver

von Vlad T. (vlad_tepesch)


Lesenswert?

Oliver S. schrieb:
> Ich meine damit: Wenn die Struktur sich am besten durch virtuelle
> Klassen darstellen lässt, dann soll man die auch nutzen, und keine
> Templates dafür missbrauchen (sofern es keine anderen guten Gründe für
> den Einsatz von Templates gibt).

was sind denn virtuelle Klassen? Ich kenne nur virtuelle Vererbung und 
virtuelle Methoden.

Wenn der Code in der Sync-Methode bis auf den Datentyp der gleiche ist, 
ist doch das Template das mittel der Wahl. Auch eine gemeinsame 
Basisklasse ist ist doch üblich.

Nur Vectoren von Raw-Pointern sind mehr als hässlich. Aber auch da hat 
Dr. Sommer einen guten Weg gezeigt.

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.