2016-04-20 12 views
0

Ich bin neu in C++ als ich den Wechsel von Java/C# gemacht habe. Kann jemand erklären, warum mein Code nicht funktioniert, wie ich denke, dass es sollte. Ich habe eine einfache Hierarchie der Tierklasse, die dann von Hund und Katze geerbt wird. Der einzige Unterschied zwischen den Klassen ist ihre virtuelle Methode toString() /, die offensichtlich eine Zeichenkette zurückgibt, basierend auf welcher der Klassen sie aufgerufen wird. Okay, ich gebe Informationen ein und erstelle die Klassen mit CIN und schiebe sie in einen Vektor von Animals. Wenn ich jedoch versuchte, ihre toString() aufzurufen, bekam ich das Ergebnis von der Basis toString() und nicht das überschriebene. Hier ist der Code an dieser Stelle:C++ Aufruf von Override-Funktionen führt zum Aufruf der Basisfunktion

#include <iostream> 
#include <vector> 
#include "animal.h" 
#include "cat.h" 
#include "dog.h" 

using namespace std; 

int main() 
{ 
    vector<Animal> animals; 

    string type; 
    string name; 
    int age; 
    int weight; 

    while(cin >> type){ 
     cin >> name >> age >> weight; 
     if(type == "dog"){ 
      animals.push_back(Dog(name, age, weight); 
     } 

     else { 
      animals.push_back(Cat(name, age, weight); 
     } 
    } 

    for(vector<Animal>::iterator iter = animals.begin(); iter != animals.end(); 
     iter++){ 
      cout << iter -> toString() << endl; 
     } 

    return 0; 
} 

Aber dann, nachdem ich einige googeln habe ich einen Vorschlag gefunden, dass ich wegen etwas genannt Objekt Slicing verwenden Zeiger sollte. Also dann drehte meinen Code in diese:

#include <iostream> 
#include <vector> 
#include "animal.h" 
#include "cat.h" 
#include "dog.h" 

using namespace std; 

int main() 
{ 
    vector<Animal*> animals; 

    string type; 
    string name; 
    int age; 
    int weight; 

    while(cin >> type){ 
     cin >> name >> age >> weight; 
     if(type == "dog"){ 
      Dog tempDog(name, age, weight); 
      animals.push_back(&tempDog); 
     } 

     else { 
      Cat tempCat(name, age, weight); 
      animals.push_back(&tempCat); 
     } 
    } 

    for(vector<Animal*>::iterator iter = animals.begin(); iter != animals.end(); 
     iter++){ 
      cout << iter -> toString() << endl; 
     } 

    return 0; 
} 

Und jetzt habe ich einen Compiler-Fehler bin immer darauf hindeutet, sollte ich verwenden ‚->‘;

Auch eine Nebenfrage, während ich hier bin möchte ich fragen. Gibt es eine Möglichkeit, eine virtuelle Methode aus der CPP-Datei und nicht die Header-Datei, in der die Klasse definiert ist, zu überschreiben. Ich bin vor kurzem in den oop in C++ und meine Idee ist, dass ich in der Header-Datei nur Prototypen der Mitglieder der Klasse definieren und ich die Implementierung in einer anderen CPP-Datei.

+0

Es ist https://en.wikipedia.org/wiki/Object_slicing. Hier ist die Antwort: http://stackoverflow.com/questions/274626/what-is-object-slicing – fukanchik

+0

Oh, und bitte lesen Sie auch dieses: http: // stackoverflow.com/questions/408670/stack-static-and-heap-in-c Es ist keine gute Idee, die Adresse von Heap-Objekten zu speichern – fukanchik

+0

Speichern Sie den Zeiger des temporären Objekts nicht (was Sie mit Ihrem tempDog und tempCat tun). Sie sollten sie dynamisch erstellen. – zoska

Antwort

0
cout << iter -> toString() << endl; 

versucht, eine Elementfunktion des Typs *iter aufzurufen. Da *iter eine Animal* ist, hat es keine Mitgliedsfunktionen. Was Sie tun müssen, ist, den Wert des Iterators bekommen und dann seine Member-Funktion aufrufen mit -> wie

cout << (*iter)->toString() << endl; 

Beachten Sie auch, dass, wenn Sie den Zugriff auf C++ 11 oder höher haben Sie eine for-Schleife basierend reichten verwenden können wie

for (auto& e : animals) 
    cout << e->toString() << "\n"; 

ich auch "\n" statt endl geändert, wie sie typischerweise benötigen Sie den Anruf nicht zu flush so sollten Sie nur tun, wenn Sie was Sie wissen müssen.


Sie haben auch undefiniertes Verhalten in Ihrem Code.

if(type == "dog"){ 
    Dog tempDog(name, age, weight); 
    animals.push_back(&tempDog); 
} 

Wird einen Zeiger auf ein automatisches Objekt in den Vektor hinzufügen. Wenn Sie den if-Block verlassen, wird das automatische Objekt automatisch zerstört. Nach der Zerstörung haben Sie nun einen Zeiger auf ein Objekt, das nicht mehr existiert. Die schnelle Lösung ist new zu verwenden, um dynamisch das Objekt wie

if(type == "dog"){ 
    Dog* tempDog = new Dog(name, age, weight); 
    animals.push_back(tempDog); 
} 

nun der Zeiger in dem Vektor nach wie vor gültig ist zuzuteilen. Leider müssen Sie jetzt daran denken, alle diese Zeiger zu löschen, wenn Sie damit fertig sind. Anstatt die manuelle Speicherverwaltung zu verwenden, können Sie einen intelligenten Zeiger wie std::unique_ptr oder std::shared_ptr verwenden, der den Speicher für Sie verwaltet.