Vererbung und Überschreiben von STDOUT
-
müssen die 3 methoden in TestClassA, TestClassB und TestClassC virtuell sein ?
heißt das Schlüsselwort "virtual" soviel wie "davon gibts mehrere, such dir die, die am besten zum Objekt passt" ?
-
Dein Vektor ist vermutlich
vector<TestClassA>. Damit kann nur noch der Stream Operator << (ostream &, TestClassA) für ein Vektorelement aufgerufen werden. Insbesondere sind in Deinem Vektor auch nie irgendwelche TestClassB drin. Auch wenn Du sie mit push_back in den Vector gesteckt hast. Dabei wird automatisch ein TestClassA aus dem TestClassB erzeugt (Kopie). Damit Du in Deinem Vector beide Klassen haben kannst, solltest Du
vector<TestClassA*>verwenden.
Damit hättest Du dann TestClassB Elemente in Deinem Vector, beim Aufruf
cout << *Testi[0] << endl;kann Dein Compiler aber wieder nur den Stream-Operator <<( ostream&, TestClassA) nehmen. Eine andere Typ-Information ist zur Compile-Zeit ja nicht vorhanden.
Um Dein gewünschtest Ergebnis zu erzielen, gehst Du besser so wie virtuell Realisticer inzwischen vorgeschlagen hat...
-
TanjaAnke schrieb:
müssen die 3 methoden in TestClassA, TestClassB und TestClassC virtuell sein ?
heißt das Schlüsselwort "virtual" soviel wie "davon gibts mehrere, such dir die, die am besten zum Objekt passt" ?
Ist eine Elementfunktion als virtual deklariert und gibt es selbige auch in der
von einer Klasse Abgeleiteten Klasse, so wird beim Aufruf der Funktion
automatisch die richtige Funktion aufgerufen. Hierzu wird intern eine sogenannte
vtable (virtual function table) erstellt, welche die Zeiger auf die "richtigen"
virtuellen Funktionen enthaelt.mfg
v R
-
Das Problem bei den virtuellen Klassen ist, dass ich dann keinen Zugriff auf die privaten Variablen der Superklasse habe.
class TestClassB : public TestClassA { private: //... public: virtual void write(std::ostream& out) const { out<<z<<x; } };Das 'x' aus der TestClassA ist hier unten leider nicht zugreifbar, egal ob ichs public oder private deklariere.
-
und zu
virtual void write(std::ostream& out) const { out<< alter << " " << gewicht; }sagt mein Compiler nur
:\test\TestClassA.cpp(36) : error C2270: "write" : Modifizierer für Funktionen, die keine Member-Funktionen sind, nicht zulässig

-
TanjaAnke schrieb:
Das Problem bei den virtuellen Klassen ist, dass ich dann keinen Zugriff auf die privaten Variablen der Superklasse habe.
class TestClassB : public TestClassA { private: //... public: virtual void write(std::ostream& out) const { out<<z<<x; } };Das 'x' aus der TestClassA ist hier unten leider nicht zugreifbar, egal ob ichs public oder private deklariere.
Wenn du sie als public deklarierst, dann musst du drauf zugreifen koennen.
Alternativ kannst du diese noch in den protected-Bereich deklarieren oder du
stellst Elementfunktionen bereit, mit deren Hilfe du auf die Klassenelemente
zugreifen kannst.mfg
v R
-
TanjaAnke schrieb:
und zu
virtual void write(std::ostream& out) const { out<< alter << " " << gewicht; }sagt mein Compiler nur
:\test\TestClassA.cpp(36) : error C2270: "write" : Modifizierer für Funktionen, die keine Member-Funktionen sind, nicht zulässig

Das 'virtual' taucht nur in der Deklaration, innerhalb der Klasse auf. Nicht
bei der Definition in der .cpp-Datei. Ausserdem musst du hier dann auch
voll qualifizieren, d. h. du musst 'void TestClassA::write(std::ostream& out) const'
schreiben.mfg
v R
-
ich hab das jetzt mal auf
36 -- virtual void TestClassA::write(std::ostream& out) const { 37 -- out<< alter << " " << gewicht << " " ; 38 -- }geändert - dann komm ich wieder zu den variablen
im H-File hab ich unter public
virtual void write (std::ostream& out)const;drinnen
und die Fehlermeldung lautet
test\TestClassA.cpp(36) : error C2723: 'write' : Speicherklassenbezeichner 'virtual' ungueltig fuer Funktionsdefinition Fehler beim Ausführen von cl.exe.Warum geht das nicht ?

-
da haben wir uns jetzt überkreuzt

deine letzte Antwort hat mir mein Problem gelöst !
Danke

-
Es ist leider noch immer so, dass die WRITE-Methode der Superklasse aufgerufen wird - ganz egal welches Objekt ich in den Vector stecke :(:(
woran kanns da noch liegen ?
vielleicht erbarmt sich noch jemand meiner...

-
TanjaAnke schrieb:
Es ist leider noch immer so, dass die WRITE-Methode der Superklasse aufgerufen wird - ganz egal welches Objekt ich in den Vector stecke :(:(
woran kanns da noch liegen ?
vielleicht erbarmt sich noch jemand meiner...

Zeig mal den Code, der die Instanzen in den vector packt.
mfg
v R
-
wie "niemand" vorgeschlagen hat, hab ich jetzt den Vektor in
std::vector<TestClassA*> Testi;geändert
Beim Aufruf von
Testi.push_back(TestClassB(alter,gewicht,groesse));kommt dann plötzlich
:\test\test.cpp(97) : error C2664: 'push_back' : Konvertierung des Parameters 1 von 'class TestClassB' in 'class TestClassA *const & ' nicht moeglich
Ursache: Konvertierung von 'class TestClassB' in 'class TestClassA *const ' nicht moeglich
-
Testi.push_back(new TestClassB(alter,gewicht,groesse));delete nicht vergessen
Kurt
-
Es muss
Testi.push_back( new TestClassB( alter,gewicht,groesse));heissen.
-
Das ist auch richtig. Du speicherst jetzt einen Zeiger auf TestClassA-Instanzen
ab und musst natuerlich auch entsprechende liefern:Testi.push_back(new TestClassB(alter,gewicht,groesse));Du erstellst jetzt dynamisch eine Instanz der Klasse TestClassB, welche an
'TestClassA*' zugewiesen werden kann.Was du auf jeden Fall jetzt beachten musst: Du reservierst Speicher dynamisch und
musst diesen folglich auch wieder freigeben://irgendwo bei programm ende for(size_t i = 0; i < Testi.size(); ++i) delete Testi[i];mfg
v R
-
Es ist zwar jetzt so dass die Fehlermeldung weg ist - der Aufruf der write-Methode erreicht aber jetzt weder die der SuperKlasse noch die der erbenden Klasse.
Und laut Debugger ist da wieder nur ein TestClassA-Objekt drinnen - d.h. nur die Basis-Variablen sind vorhanden
PS: ich habe jetzt auch mit dem Debugger festgestellt dass beim Aufruf, also bei
Testi.push_back(new TestClassB(alter,gewicht,groesse));alle Werte richtig befüllt wurden...
Das Ganze wird dann an den Konstruktor
TestClassB::TestClassB(int alter, int gewicht, int groesse_in) : TestClassA(alter, gewicht) { groesse = groesse_in; }und trotzdem kommt am schluss immer ein TestClassA-Objekt in den Vector....
-
TanjaAnke schrieb:
Es ist zwar jetzt so dass die Fehlermeldung weg ist - der Aufruf der write-Methode erreicht aber jetzt weder die der SuperKlasse noch die der erbenden Klasse.
Und laut Debugger ist da wieder nur ein TestClassA-Objekt drinnen - d.h. nur die Basis-Variablen sind vorhanden
Selbstverstaendlich ist nur ein TestClassA-Objekt im vector enthalten. Aber da
TestClassB und TestClassC von TestClassA erben, ist diese Zuweisung legitim.Zu deinem Problem:
Kannst du den Code mal hier: http://rafb.net/paste/ posten und den Link hier
reinstellen?mfg
v R
-
Ich habe jetzt gleichmal das Original gepostet und nicht mehr meine Fantasie-Klassen

Es gibt die Klasse Fahrzeug = Oberklasse = entspricht TestClassA
und Klasse PKW = erbende Klasse = entspricht TestClassBDie Main ist in einem weiteren externen File und arbeitet mit dem Vector
-
Hallo,
die 'friend'-Deklarationen benoetigst du nicht. Das Problem das du hast:
Du hast lediglich eine Definition von
'std::ostream& operator<<(std::ostream& out, const Fahrzeug& val)' in der
.cpp-Datei. Du musst diese aber auch in der Header haben, sonst ist der op<<
ja gar nicht bekannt.Mir ist noch aufgefallen, dass es hier Fahrzeug* sein muss. Dein Programm sieht
also so aus:fahrzeug.h
#ifndef FUHRPARK_FAHRZEUG_H_INCLUDED #define FUHRPARK_FAHRZEUG_H_INCLUDED #include <string> class Fahrzeug { public: Fahrzeug(char car_type[20],char plate[8],int age, int performance); ~Fahrzeug(); void change_plate(char plate[8]); void show_car(); virtual void write (std::ostream& out)const; char car_type[20]; char plate[8]; int age; int performance; }; std::ostream& operator<<(std::ostream& out, const Fahrzeug* val); #endiffahrzeug.cpp
#include <iostream> #include <string> #include "Fahrzeug.hpp" using namespace std; Fahrzeug::Fahrzeug(char car_type_in[20], char plate_in[8],int age_in, int performance_in) { cout << "Neues Fahrzeug eingestellt " << endl; strcpy(car_type,car_type_in); strcpy(plate,plate_in); age = age_in; performance = performance_in; } Fahrzeug::~Fahrzeug() { } void Fahrzeug::change_plate(char input[]) { strcpy(plate,input); } void Fahrzeug::show_car() { cout << "Kennzeichen: "; for (int i=0;i<8;i++) { cout << plate[i]; } cout << " Baujahr: "<< age <<" Leistung: "<< performance << endl; } void Fahrzeug::write(std::ostream& out) const { cout << "TEST12345"; } std::ostream& operator<<(std::ostream& out, const Fahrzeug* val) { val->write(out); return out; }pkw.h
#ifndef pkwHPP #define pkwHPP #include <string> #include "fahrzeug.hpp" class PKW : public Fahrzeug { public: PKW(char car_type[20],char plate[8],int age, int performance,int seat,bool child_carrier); virtual ~PKW(); void set_child_carrier(bool x); virtual void write (std::ostream& out)const; private: int seat; bool child_carrier; }; #endifpkw.cpp
#include <iostream> #include <string> #include "pkw.hpp" using namespace std; PKW::PKW(char car_type[], char plate[],int age, int performance, int seat_in, bool child_carrier_in) : Fahrzeug(car_type,plate,age,performance) { seat = seat_in; child_carrier = child_carrier_in; } PKW::~PKW() { } void PKW::set_child_carrier(bool x){ child_carrier = x; } void PKW::write(std::ostream& out) const { out << "Ein PKW der Marke: "; int i=0; while (car_type[i]!='\0') { out << car_type[i]; i++; } out << "\nKennzeichen: "; i=0; while (plate[i]!='\0') { out << plate[i]; i++; } out<<"\nBaujahr: "<<age<<"\nLeistung: "<<performance<<"\nSitze: "<<seat; if (child_carrier) out<<"\nEs ist ein Kindersitz vorhanden"; else out<<"\nEs ist kein Kindersitz vorhanden"; }main.cpp
#include <iostream> #include <vector> #include <string> #include "fahrzeug.hpp" #include "pkw.hpp" using namespace std; int main() { std::vector<Fahrzeug*> Fahrzeuge; Fahrzeuge.push_back(new PKW("OPEL","ABC",1980,75,5,true)); Fahrzeuge.push_back(new PKW("VW","DEF",1990,90,5,false)); Fahrzeuge.push_back(new PKW("VOLVO","GHI",1996,110,4,true)); cout << "\n\n"<<Fahrzeuge.size()<<"\n\n"; //< nicht <= !!! for (int i=0; i<Fahrzeuge.size();i++) cout << Fahrzeuge[i] <<endl; return 0; }mfg
cu
-
SUUUPER - GANZ HERZLICHEN DANK !!

Jetzt funktioniert es wie es soll - und gibt auch aus was es soll

Ich habe nur noch eine einzige winzigkleine Frage, obwohl ich jetzt schon ein relativ schlechtes Gewissen habe

Ich lege ja ein fixes Char-Array der Größe 20 an um die Typenbezeichnung einzulesen.
Falls jemand mehr als diese 20 Stellen eingibt wird der String eben abgeschnitten und setze an die letzte Stelle ein '\0'.Falls aber jemand z.B. nur 5 Zeichen eingibt wird trotzdem an die 20ste Stelle das '\0' gesetzt - und ich bekomme je nach Vorbelegung des Speichers einen Haufen Mist in die Ausgabe.
Lässt sich so ein Char-Array irgendwie einfach mit '\0' vorbelegen ?
Oder je nach Länge der Eingabe irgendwie "abschneiden" ?char type [20]; cin >> type; type[19]='\0';Ein glückliches Programmier-Mädel
