verschiedene Klassen in einem Vektor
-
Hallo,
warum ist dies nicht erlaubt?
#include <iostream.h> #include <vector> std::vector<void*> g_vTest; class CBase { public: int m_iBase; }; class CTest:public CBase { public: int m_iTest; }; class CTest2:public CBase { public: int m_iTest2; }; void main() { g_vTest.resize(2); g_vTest[0]=new CTest; g_vTest[1]=new CTest2; g_vTest[0]->m_iTest=1; g_vTest[0]->m_iBase=2; g_vTest[0]->m_iTest2=0; g_vTest[0]->m_iBase=999; for(int i=0; i<g_vTest.size(); i++) { delete(g_vTest[0]); } }
Die Fehler:
error C2227: Der linke Teil von '->m_iTest' muss auf Klasse/Struktur/Union zeigen
error C2227: Der linke Teil von '->m_iBase' muss auf Klasse/Struktur/Union zeigen
error C2227: Der linke Teil von '->m_iTest2' muss auf Klasse/Struktur/Union zeigen
error C2227: Der linke Teil von '->m_iBase' muss auf Klasse/Struktur/Union zeigenDanke,
Anfänger
-
aus dem selben grund, warum folgendes nicht funktioniert:
void *v = new Foo; v->bar(); //Fehler //was erlaubt ist: static_cast<Foo*>(v)-> bar();
Der statische Typ ist void, nicht Foo.
Lass den vector Zeiger auf die gemeinsame Basisklasse enthalten, spendier der Basisklasse einen virtuellen Destruktor und schon kannst du dynamic_cast verwenden. Allerdings deutet ziemlich alles auf einen Designfehler hin, wenn dein Code so aussieht.Außerdem: Was falsch ist an void main() und
Warum man <iostream> statt <iostream.h> verwenden sollte
-
Siehs mal aus der Sicht des Compilers. g_vTest[0] ist laut Deklaration ein void-Pointer. Hat void ein Member namens m_iTest? Nein! Damit ist der Fall für den Compiler abschließend erledigt. Jedenfalls in einer statischen Programmiersprache wie C++.
Sowas wie du konstruiert hast, sollte man nicht ohne Not machen. Aber wenn es schonmal so ist und sich nicht ändern läßt ... alles was dir bleibt, ist, dem Compiler mit dem Vorschlaghammer klarzumachen, dass sich hinter dem void-Pointer ein bestimmter Typ verbirgt:static_cast<CTest*>(g_vTest[0])->m_iTest = 1;
Du musst nur aufpassen, dass sich dahinter auch wirklich ein CTest befindet.
-
Aha,
es geht nämlich um folgendes. Ich habe ein Simulation programmiert. Dabei gibt es verschiedene Objekte;, Nun möchte ich nicht für jede Objektart einen eigenen Vektor anlegen. Desswegen: es gibt einen Vektor void* und es wird in diesem Vektor immer das Objekt angelegt, was benötigt wird. z.B. new CShip, new CTree, new ... . Dabei hat jedes Objekt bestimmte Grundfunktionen, nämlich Move und Render. Desswegen dachte ich, ich gehe einfach den Vektor durch, rufe Move und Render auf und dann hat es sich. Ist doch besser als das gleiche, aber bei 10 verschiedenen Vektoren
Aber, trotzdem Danke,
Mfg
-
Wie wärs mit Vererben und virtuellen Methoden ?
-
Definiere move und render als virtuelle Methoden in CBase und leite alle Klassen die in den Vector sollen (als CShip, CTree) von CBase ab. Wenn Du denn Vektor dann so deklarierst:
std::vector<CBase*> g_vTest;
,kannst du Du move und render von allen deinen Objekten in einer Schleife aufrufen.
-
Und als kleinen Bonus kannst du die Objekte dann ohne undefiniertes Verhalten freigeben, wenn du ihnen einen virtuellen Konstruktor spendierst. Ansonsten hätte "delete v[i]" vermutlich nur den Speicher freigegeben, aber den Destruktor nie aufgerufen.
-
Definiere move und render als virtuelle Methoden in CBase und leite alle Klassen die in den Vector sollen (als CShip, CTree) von CBase ab. Wenn Du denn Vektor dann so deklarierst:
Daran hatte ich auch gedacht, aber es gibt ja in verschiedenen Klassen auch verschiedenen Variablen. z.B. in der Klasse CTree nicht nur Move und Render, sondern auch int m_iNumberOfBlätta, in der CShip-Klasse gibt es eine Variable zu den Waffen... Wie kann man soetwas darin hineinbauen
Danke,
Mfg
-
struct base { virtual void move(); virtual void render(); }; class tree : public base; { private: node irgendwas; public: void move(); void render(); void addNode(......); }
-
Aha,
aber, wenn ich es so mache wie du, muss ich immer noch viel, viel Casten. Zu viel, um ehrlich zu sein. Ich könnte nämlich nicht sagen:
m_vEinheiten[0]=new CTree; m_vEinheiten[0]->addNode(); // falsch, da kein Objekt von CBase static_cast<CTree*>(m_vEinheiten[0])->addNode(); // richtig
danke,
__Anfänger__
-
OT-Frage an davie und Bashar:
Warum nimmt man in diesem Fall static_cast? Es handelt sich doch in beiden Fällen um Pointer, die nur anders interpretiert werden - wäre das nicht ein Grund für den gleichnamigen reinterpret_cast? Oder gibt es Systeme, auf denen ein void-Pointer eine andere Größe besitzt als einer auf eine Klasse?
-
naja, um das casten wirst nicht drumherumkommen, wenn du nicht auf der basisfunktionalitaet sitzen bleiben willst. Oder du machst halt alles zu basisfunktionen, und manche objecte machen dann halt gar nix da ... auch keine so elegante Loesung.
Irgendwie muesstest dein komplettes strukturelles design dann aendern, wenn sowas vermeiden willst .
Woher weisst du z.b. das an pos 0 im vector nen CTree sitzt ?
wenn die info nur beim einfuegen brauchst, musst naturlich ned casten ...CTree * pTree = new CTree; pTree->addNode(); m_vEinheiten[0]=pTree;
Mir waeren die 4byte mehr aufn stack lieber als der cast :p
Prinzipiell ists eh fast immer ne gute Idee, containerklassen zu kapseln und zu spezialisieren ... besonders wennst da drinnen Zeiger auf dynamisch erzeugten Objekten hast . Ansonsten ist die gefahr zu gross, das man die obejekte ned loescht, wenn der container verworfen wird ... oder das man die inhalte der container kopiert, und zeiger aus dem einem samt Objekt loescht und aus dem anderen nicht ....
Ciao ...
-
Cocaine schrieb:
Warum nimmt man in diesem Fall static_cast? Es handelt sich doch in beiden Fällen um Pointer, die nur anders interpretiert werden - wäre das nicht ein Grund für den gleichnamigen reinterpret_cast?
Normalerweise braucht man reinterpret_cast um einen Pointer-Typ in einen anderen umzuwandeln. Da es aber automatische Konvertierungen jedes Pointer-Typs nach void* gibt, kann man den umgekehrten Weg auch mit static_cast gehen. Genauso beim Downcast in einer Hierarchie ... von base* nach derived* komm ich mit static_cast.
static_cast ist ein scharfes Messer und reinterpret_cast eine Kettensäge, im Zweifelsfall nehme ich das schwächste Werkzeug was den Job noch tut
-
reinterpret_cast<>() ist doch der unsicherste von allen (den C-Cast mal ausgenommen) ... er macht nix anderes als die bitfolge einfach anders zu interpretieren ?
static_cast<>() dagegen beruecksichtig die standard conversionen von datentypen .... und mault, wenn was eigentlich nicht gehen sollte (wenn der compiler denkt es geht ned, long nach char z.b.) ...
bei nem pointer zu pointer cast gehen beide, und ich wuerd den "sichereren" nehmen ...
castest den Pointer dagegen polymorph hoch, so wie es mittels der gemeinsamen Basisklasse im Thread vorher vorgeschlagen wurde ... dann kommt wahrscheinlich dynamic_cast<>() ins Spiel ... (wenn RTI eingeschalten)
Ciao ...
-
RHBaum schrieb:
bei nem pointer zu pointer cast gehen beide, und ich wuerd den "sichereren" nehmen ...
Das war mir schon klar, nur suchte ich nach dem Grund für static_cast.
Bashar schrieb:
Da es aber automatische Konvertierungen jedes Pointer-Typs nach void* gibt, kann man den umgekehrten Weg auch mit static_cast gehen. Genauso beim Downcast in einer Hierarchie ... von base* nach derived* komm ich mit static_cast.
Danke, das erklärt's
-
nur suchte ich nach dem Grund für static_cast.
Paranoia ?
Ciao ...
-
Also,
ich hab das jetzt so gemacht (nicht ganz so, aber man könnte es so sehe):
class CBase : public CIrgendeineKlasseVonDerEngine { public: int m_iLebenspunkte... BOOL IstSichtbar; virtual void Render(float fTime)=0; virtual void Move(float fTime)=0; } // ... class CPlane : public CBase { public: int m_iAnzahlSchüsse; void Render(float fTime)=0; void Move(float fTime)=0; }
std::vector<CObject*> vObject; vObject.resize(1); vObject[0]=new CPlane;
Wenn ich aber nun vObject->Move() oder vObject->Render() aufrufe, stürzt der Computer ab, bzw. springt in die Zeile, bei der die Funktion aufgerufen wurde. Die eigentlich Funktion wurde aber nicht aufgerufen.
Hat jemand eine Idee, was falsch ist,
Danke
-
Was meinte eigentlich operator void? Das habe ich auch nicht ganz verstanden...
-
Nimm doch ma das =0 am Ende der Methodendeklarationen der abgeleiteten Klasse weg...
-
Schuldigung.
Heißt natürlich virtual void Render(); und auch BOOL IsVisible**()**
Hoffe, dass mein Problem gelöst werden kann,
Danke,
__Anfänger__
PS: und wie ist das nun mit dem
Und als kleinen Bonus kannst du die Objekte dann ohne undefiniertes Verhalten freigeben, wenn du ihnen einen virtuellen Konstruktor spendierst. Ansonsten hätte "delete v[i]" vermutlich nur den Speicher freigegeben, aber den Destruktor nie aufgerufen...