如何在使用抽象类

时间:2017-12-07 19:53:46

标签: c++

假设我有以下类和对象:

#include <iostream>

class Animal
{
public:
    virtual void makeNoise() = 0;

    void eat()
    {
        std::cout << "Eating..." << "\n";
    }

    void sleep()
    {
        std::cout << "Sleeping..." << "\n";
    }
};

class Cat: public Animal
{
public:
    void makeNoise()
    {
        std::cout << "Miow..." << "\n";
    }
};

class Cow: public Animal
{
public:
    void makeNoise()
    {
        std::cout << "Mooo..." << "\n";
    }
};

int main()
{
    Animal *animal;
    Cat *cat = new Cat();
    Cow *cow = new Cow();

    animal = cat;
    animal->eat();
    animal->sleep();
    animal->makeNoise();

    animal = cow;
    animal->eat();
    animal->sleep();
    animal->makeNoise();

    return 0;
}

请注意,动物是一个抽象类。

如何正确删除指针animalcatcow

当我尝试delete animal;时,我收到以下警告消息:

  

警告:删除抽象类类型对象&#39; Animal&#39;其中有   非虚析构函数会导致未定义的行为。

另一方面,当我尝试delete cat;时,我收到以下消息:

  

警告:删除多态类类型的对象&#39; Cat&#39;其中有   非虚析构函数可能会导致未定义的行为。

2 个答案:

答案 0 :(得分:2)

一个基本的C ++规则说析构函数从派生类到基类的工作方式。当Cat被销毁时,Cat部分首先被销毁,Animal部分被销毁。

delete animal;是未定义的行为,因为为了正确遵循C ++销毁规则,必须在运行时知道哪个派生类部分应该在Animal基础部分之前销毁。一个virtual析构函数正是这样做的 - 它启用了一个动态调度机制,确保销毁按设计工作。

但是,您没有virtual析构函数,因此delete animal只是没有意义。没有办法调用正确的派生类析构函数,并且只销毁Animal部分也不是完全有意义的行为。

因此,C ++语言不会假设在这种情况下会发生什么。

你的编译器非常适合警告你。

delete cat,情况略有不同。 cat指针的静态类型是Cat*,而不是Animal*,所以即使没有任何派生类析构函数首先调用的动态调度机制,它也很清楚。

编译器仍然会对此发出警告,但它会使用不同的措辞(&#34;可能导致&#34; vs.&#34;将导致&#34;)。我相信原因是Cat本身可能是更多派生类的基类,因为它已经是具有virtual函数的类层次结构的一部分。

显然没有必要执行更完整的代码分析,以发现delete cat真的无害。

要解决此问题,请创建Animal析构函数virtual。在您使用std::unique_ptr时,请将原始指针替换为virtual。对于像您这样的类,您仍然必须遵循delete析构函数规则,但您不再需要执行手册Rails.application.config.middleware.use OmniAuth::Builder do provider :facebook, ENV['FACEBOOK_APP_ID'], ENV['FACEBOOK_APP_SECRET'], scope: '', info_fields: '' end

答案 1 :(得分:0)

这正是编译器警告你的内容。您需要为每个类定义和实现自己的析构函数,并确保将它们定义为virtual以进行继承。