2016-11-09 54 views
1

我有一个抽象类,让它成为例如Animal。动物有一个纯粹的虚拟功能,如果他们不想饿死,每只动物必须实施。我保证只动物的孩子可以用这种方式进行实例化:C++使用纯虚函数实例化抽象类的子代

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() 
{} 

有了这个,一个将是:

Cat.hpp

class Cat : public Animal 
{ 

public: 

    Cat(); 

    void Eat() const; 
}; 

Cat.cpp

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

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

但是这个代码不工作,它得到一个错误无效抽象的返回类型“动物”GetAnimal,因为动物是抽象的,不能被实例化,尽管我的API确保它不会。

这个问题有哪些智能解决方案?我可以做的功能不纯,并给它一个默认的实现,但我不想这样做。

+0

@Galik有些相机是动物。 –

+1

虚拟成员函数使用指针 – Amadeus

+0

您确定首先需要运行时多态吗? – SergeyA

回答

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); 
    } 
} 

你说GetAnimal应返回Animal对象,这不是继承如何工作,继承主要通过指针工作。当您尝试返回某个类型的对象时,编译器隐式地必须创建一个Animal对象,但它不被允许,因为Animal是一个抽象类。即使你只制作eat()只有virtual你仍然有object slicing问题。

你可以把它返回一个Animal*和释放的结果,你使用后:

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); 
    } 
} 

来电:

Dog* myDog = GetAnimal(DOG); 

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

但是如果你有机会到C++ 11或更高版本,我建议使用智能指针代替裸指针,让指针自由本身:

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

来电:

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

你希望你的返回类型GetAnimal成为一个指向动物而不是动物本身的指针。一般来说,无论何时你试图使用多态,指针都是要走的路。

我最好的猜测是,这是发生了什么:你正在实例化一只猫。然后在你的return语句中,由于你没有返回指针,它必须复制你的数据。由于返回类型是Animal,它会尝试调用默认的动物拷贝构造函数。因此,它试图实例化一个动物类,这当然是不可能完成的。

0

虚拟成员函数与指针一起工作。只是改变了一下你的API,以类似的东西:

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

请注意,我假设你正在使用,至少,C++ 14

+0

虚拟成员函数与指针一起工作。 – curiousguy

+0

@curiousguy动态继承,用虚拟函数与指针一起工作,与OP请求 – Amadeus

+0

完全一样虚拟函数在自动对象上正常工作;当然,动态类型在编译器中是已知的,但它们“工作”。如果你需要在运行时选择一个对象的类型,当然你需要动态分配。 – curiousguy