2016-11-09 2 views
1

Ich habe eine abstrakte Klasse, lassen Sie es zum Beispiel Animal. Ein Tier hat eine rein virtuelle Funktion essen, die jedes Tier implementieren muss, wenn sie nicht verhungern wollen. Ich stelle sicher, dass nur ein Kind eines Tieres kann durch diese Art und Weise instanziert werden:C++ Instantiierung von Childs einer abstrakten Klasse mit rein virtuellen Funktionen

ANIMAL.HPP

class Animal 
{ 

public: 

    enum eAnimal{ 
     CAT=0, 
     DOG=1, 
     BIRD=2 
    }; 

    // Instantiates the desired animal. 
    static Animal GetAnimal(const int animal); 

    virtual void Eat() const = 0; 

protected: 

    Animal(); 
}; 

Animal.cpp

Animal Animal::GetAnimal(const int animal) 
{ 
    switch(animal) 
    { 
    case CAT: 
     return Cat(); 
    case DOG: 
     return Dog(); 
    case BIRD: 
     return Bird(); 
    default: 
     cerr << "Animal not recognized." << endl; 
     exit(-1); 
    } 
} 

Animal::Animal() 
{} 

Damit ein Cat wäre:

CAT.HPP

class Cat : public Animal 
{ 

public: 

    Cat(); 

    void Eat() const; 
}; 

Cat.cpp

Cat::Cat() : Animal() 
{} 

void Cat::Eat() const 
{ 
    // The cat eats. 
} 

jedoch nicht dieser Code nicht funktioniert, wird es einen Fehler ungültig abstrakten Rückgabetyp 'Animal' in GetAnimal, weil Tiere abstrakt und nicht instanziiert werden kann, obwohl meine API sicherstellt, dass es nicht geht.

Welche intelligenten Lösungen könnte dieses Problem haben? Ich kann die Funktion essen nicht rein und geben Sie eine Standardimplementierung, aber ich möchte es nicht tun.

+0

@Galik Einige Kameras sind Tiere. –

+1

Virtuelle Member-Funktionen arbeiten mit Zeigern – Amadeus

+0

Sind Sie sicher, dass Sie hier Laufzeit-Polymorphismus benötigen? – SergeyA

Antwort

3
Animal Animal::GetAnimal(const int animal) 
{ 
    switch(animal) 
    { 
    case CAT: 
     return Cat(); 
    case DOG: 
     return Dog(); 
    case BIRD: 
     return Bird(); 
    default: 
     cerr << "Animal not recognized." << endl; 
     exit(-1); 
    } 
} 

Sie sagen, dass GetAnimal sollte ein Rück AnimalObjekt, so funktioniert die Vererbung nicht, Vererbung funktioniert hauptsächlich durch Zeiger. Wenn Sie versuchen, ein Objekt eines Typs zurückzugeben, muss der Compiler implizit ein Objekt Animal erstellen, aber es ist nicht zulässig, da Animal eine abstrakte Klasse ist. Selbst wenn Sie eat() nur virtual machen würden, hätten Sie immer noch das object slicing Problem.

Sie können es eine Animal* machen zurückkehren und das Ergebnis frei, nachdem Sie es verwendet:

Animal* Animal::GetAnimal(const int animal) 
{ 
    switch(animal) 
    { 
    case CAT: 
     return new Cat(); 
    case DOG: 
     return new Dog(); 
    case BIRD: 
     return new Bird(); 
    default: 
     cerr << "Animal not recognized." << endl; 
     exit(-1); 
    } 
} 

Anrufer:

Dog* myDog = GetAnimal(DOG); 

//somewhere later when you dont need myDog anymore..(don't forget this!) 
delete myDog; 

Aber wenn Sie den Zugriff auf C++ 11 oder höher Ich empfehle Verwenden von intelligenten Zeigern anstelle von rohen Zeigern, um den Zeiger sich selbst freizugeben:

Anrufer:

auto dog = GetAnimal(DOG); 
//no explicit delete required. 
1

Sie möchten, dass der Rückgabetyp von GetAnimal ein Zeiger auf ein Tier und nicht auf ein Tier selbst ist. Im Allgemeinen, wenn Sie versuchen, Polymorphie zu verwenden, sind Zeiger der Weg zu gehen.

Meine beste Vermutung ist, dass dies passiert: Sie erstellen eine Katze. Da in Ihrer Return-Anweisung kein Zeiger zurückgegeben wird, muss er eine Kopie Ihrer Daten erstellen. Da der Rückgabetyp Animal ist, wird versucht, den standardmäßigen Animal-Kopierkonstruktor aufzurufen. Daher versucht es eine Tierklasse zu instanziieren, was natürlich nicht möglich ist.

0

Virtuelle Member-Funktionen arbeiten mit Zeigern. Ändern Sie einfach ein bisschen API, um so etwas wie das:

std::unique_ptr<Animal> Animal::GetAnimal(const int animal) 
{ 
    switch(animal) 
    { 
    case CAT: 
     return std::make_unique<Cat>(); 
    (...) 
    } 
} 

Bitte beachte, dass ich nehme an, Sie verwenden, zumindest, C++ 14

+0

Virtuelle Member-Funktionen arbeiten mit und ohne Zeiger. – curiousguy

+0

@curiousguy dynamische inhärentheit, die mit virtuellen funktionen implementiert ist, arbeitet mit zeiger, genau wie OP ask – Amadeus

+0

Virtuelle funktionen arbeiten normalerweise auf einem automatischen objekt; Natürlich ist der dynamische Typ beim Compiler bekannt, aber sie "arbeiten". Wenn Sie zur Laufzeit den Typ eines Objekts wählen müssen, benötigen Sie natürlich eine dynamische Zuordnung. – curiousguy

Verwandte Themen