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

San*_*Gil 1 c++ polymorphism abstract-class return-by-value

我有一个抽象类,例如Animal。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();
};
Run Code Online (Sandbox Code Playgroud)

动物.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()
{}
Run Code Online (Sandbox Code Playgroud)

有了这个,将是:

猫.hpp

class Cat : public Animal
{

public:

    Cat();

    void Eat() const;
};
Run Code Online (Sandbox Code Playgroud)

目录

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

void Cat::Eat() const
{
    // The cat eats.
}
Run Code Online (Sandbox Code Playgroud)

但是,此代码不起作用,它在GetAnimal 中收到错误无效抽象返回类型“Animal”,因为 Animal 是抽象的并且无法实例化,尽管我的 API 确保它不会。

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

Som*_*ken 5

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

你可以让它返回 aAnimal*并在你使用它后释放结果:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

呼叫者:

Dog* myDog = GetAnimal(DOG);

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

但是如果您可以访问 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

呼叫者:

auto dog = GetAnimal(DOG);
//no explicit delete required.
Run Code Online (Sandbox Code Playgroud)