繁体   English   中英

C ++使用纯虚函数实例化抽象类的子级

[英]C++ Instantiating childs of an abstract class with pure virtual functions

我有一个抽象类,例如让它为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();
};

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

这样,一只将是:

class Cat : public Animal
{

public:

    Cat();

    void Eat() const;
};

目录

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

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

但是此代码不起作用,它在GetAnimal中得到一个错误无效的抽象返回类型'Animal' ,因为Animal是抽象的并且无法实例化,尽管我的API可以确保不会这样做

这个问题可能有哪些智能解决方案? 我可以执行Eat 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的返回类型是动物的指针,而不是动物本身。 通常,每当您尝试使用多态时,都可以使用指针。

我最好的猜测是,这就是正在发生的事情:您正在实例化Cat。 然后,在您的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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM