我有一个抽象类,例如 Animal 。动物有一个纯粹的虚拟功能 eat ,如果他们不想饿死,每个动物都必须实施。我确保只有动物的孩子才能通过这种方式实例化:
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 将是:
Cat.hpp
class Cat : public Animal
{
public:
Cat();
void Eat() const;
};
Cat.cpp
Cat::Cat() : Animal()
{}
void Cat::Eat() const
{
// The cat eats.
}
但是这段代码不起作用,它会在 GetAnimal 中出现无效的抽象返回类型&#39; Animal&#39; ,因为Animal是抽象的并且无法实例化,尽管我的API确保它不会。
这个问题有哪些智能解决方案?我可以做 Eat 这个函数并不是纯粹的,并给它一个默认的实现,但我不想这样做。
答案 0 :(得分: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 :(得分:1)
您希望GetAnimal的返回类型是指向Animal而不是Animal本身的指针。通常,无论何时尝试使用多态,都可以使用指针。
我最好的猜测是,这就是正在发生的事情:你正在实例化一只猫。然后在return语句中,由于您没有返回指针,因此它必须复制您的数据。由于返回类型是Animal,它会尝试调用默认的Animal复制构造函数。因此,它试图实例化一个Animal类,当然这是无法完成的。
答案 2 :(得分:0)
虚拟成员函数与指针一起使用。只需将您的API更改为类似的内容:
std::unique_ptr<Animal> Animal::GetAnimal(const int animal)
{
switch(animal)
{
case CAT:
return std::make_unique<Cat>();
(...)
}
}
请注意,我假设您正在使用,至少是C ++ 14