C++用纯虚拟函数实例化抽象类的子类
C++ Instantiating childs of an abstract class with pure virtual functions
我有一个抽象类,例如Animal。动物有一个纯粹的虚拟功能吃,如果它们不想挨饿,每个动物都必须实现这个功能。我确保只有动物的孩子才能通过这种方式实例化:
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中得到一个错误无效的抽象返回类型"Animal">,因为Animal是抽象的,不能实例化,尽管我的API确保它不会。
这个问题可能有哪些明智的解决方案?我可以不纯地执行Eat函数,并给它一个默认实现,但我不想这样做。
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
,您仍然会遇到对象切片问题。
您可以让它返回一个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.
您希望GetAnimal的返回类型是指向Animal而不是Animal本身的指针。一般来说,无论何时尝试使用多态性,指针都是首选。
我最好的猜测是,这就是正在发生的事情:你正在实例化一只猫。然后在您的return语句中,由于您没有返回指针,它必须复制您的数据。由于返回类型为Animal,因此它尝试调用默认的Animal复制构造函数。因此,它试图实例化一个Animal类,这当然是不可能的。
虚拟成员函数使用指针。只要把你的API改一点就可以了:
std::unique_ptr<Animal> Animal::GetAnimal(const int animal)
{
switch(animal)
{
case CAT:
return std::make_unique<Cat>();
(...)
}
}
注意,我假设您至少使用C++14
- 有没有办法按值将纯抽象类的所有子类传递给 C++ 中的函数?
- 文本冒险游戏 - 如何区分一种项目类型与另一种项目类型以及如何构建项目类/子类
- 如何将子类作为函数的参数传递给期望基类,然后将该对象传递到指向这些抽象类对象的指针向量中?
- 我们可以在没有新实例化的情况下声明一个抽象方法来返回抽象超类中的子类对象吗
- 如何调用传递给 JNI 'jobject' 的 Java 对象的子类/子类的方法
- 如何将抽象类的可访问性限制为另一个抽象类及其子类?
- 模型类/子类,其中子类类型在C++中先验未知
- 如何从其抽象母类上的指针初始化子类?
- 使用抽象类的容器来保存子类
- 从子类中的抽象类调用方法
- 从子类到具有相同基数的抽象子类的隐式转换
- 具有虚拟析构函数的基类子类中的默认析构函数
- 使用默认构造函数的父类;子类的析构函数意外调用
- 尝试引用子类中的抽象对象时收到编译错误
- Qt c++ 类 + 子类使用 Q_OBJECT 不起作用
- 提升 Python 包装的虚拟类 - 子类返回错误:与C++签名不匹配
- 宠物动物园C++/继承类/子类
- 模板基类子类的模板专用化
- 在c++中,如何确定一个类是否是继承链中的最后一个类/子类?它位于基类的另一端
- 如何使用模板类的模板类子类从哈希表实现哈希集