C ++抽象类析构函数

时间:2014-06-19 21:42:46

标签: c++ abstract-class destructor

在父类中仅使用纯虚拟析构函数创建抽象类是否是一种好习惯(并且可能)?

这是一个样本

class AbstractBase {
public:
    AbstractBase () {}
    virtual ~AbstractBase () = 0;
};

class Derived : public AbstractBase {
public:
    Derived() {}
    virtual ~Derived() {}
};

否则,如果衍生类的属性和构造函数完全相同而另一个方法完全不同,我怎么能创建一个抽象类呢?

3 个答案:

答案 0 :(得分:13)

C ++中的接口应该有一个实现的虚拟析构函数,什么都不做。接口中的所有其他方法都被定义为抽象(例如,在声明中添加= 0)。这将确保您无法创建接口类的实例,但是一旦将接口指针指定给父对象,就可以删除对象。抱歉措辞不好,下面是一些代码:

class ISampleInterface
{
public:
    virtual ~ISampleInterface() { };
    virtual void Method1() = 0;
    virtual void Method2() = 0;
}

class SampleClass : public ISampleInterface
{
public:
    SampleClass() { };
    void Method1() { };
    void Method2() { };
}

int main()
{
    ISampleInterface *pObject = (ISampleInterface*)new SampleClass();
    delete pObject;
    return 0;
}

答案 1 :(得分:5)

在基类中只有一个纯虚拟析构函数很少是一种好的做法,但它有可能,在某些情况下甚至是可取的。
例如,如果依靠RTTI通过在指向基类的指针上尝试dynamic_cast来将消息分派给子类对象,则除了析构函数之外,基类中可能不需要任何方法。在这种情况下,将析构函数设为公共虚拟。

由于除了析构函数之外没有其他虚方法,因此必须使其纯化,以防止创建基类的对象。
在这里,为析构函数提供空体是至关重要的(即使它是“= 0”!)

struct AbstractBase {
     virtual ~AbstractBase() = 0;
}

AbstractBase::~AbstractBase() {
}

让body允许创建子类对象(假设子类定义析构函数并且不将其设置为纯粹的。)

答案 2 :(得分:2)

这个问题让我想起Old New Thing post

  

一位客户询问有关如何完成某事的建议......而且我不相信这是一个好主意,有点像是在寻求如何抓住牙齿棒球或者摘下所有奶酪的建议你的芝士汉堡。

     

我解释了他们的方法中的几个陷阱......我用句子结束,“这个想法充满了危险,我担心我对你的问题的回答将被解释为批准而不是不情愿的帮助。”

可以创建一个只有virtual析构函数的抽象基类。我不确定你为什么要这么做。知道对象派生自一个类型,比如Foo,应该意味着我知道我可以用该对象做什么。在这种情况下,我只知道我可以销毁对象,这不是有用的信息。

但你认为最明显的方法不会编译是正确的:

struct Foo {
    virtual ~Foo() = 0;
};

struct Bar : Foo {
    ~Bar() { }
};

struct Baz : Foo {
    ~Baz() override { } // C++11
};

当我尝试编译它时,我收到链接错误,因为,虽然定义了Bar::~Bar()Baz::~Baz(),但Foo::~Foo()不是,编译器想要调用Foo::~Foo()每当BarBaz被销毁时。

有两种解决方案。首先,virtual函数不必是纯虚函数:

struct Foo {
    virtual ~Foo() { }
};

struct Bar : Foo {
    ~Bar() { }
};

struct Baz : Foo {
    ~Baz() override { } // C++11
};

struct Quux : Foo { };

但是你特意要求一个纯虚拟析构函数。答案肯定是奇怪的:纯虚函数可以由声明它们纯虚拟的类定义:

struct Foo {
    virtual ~Foo() = 0;
};

Foo::~Foo() { }

struct Bar : Foo {
    ~Bar() { }
};

struct Baz : Foo {
    ~Baz() override { } // C++11
};

struct Quux : Foo { };

可以这样做的事实并不意味着这是一个好主意。在定义函数时,您希望声明一个纯虚函数是非常不寻常的。它可能会出现,但它将非常罕见。

  

否则,如果衍生类的属性和构造函数完全相同而另一个方法完全不同,我怎么能创建一个抽象类呢?

我认为真正困扰我的是现在大多数建议是使用纯虚函数来创建类似Java接口的东西。当你这样做时,你声明了派生类需要支持的方法,但是让这些类可以自由使用任何数据成员是有意义的。您计划仅声明数据成员类型必须包含的内容,并使这些类型可以自由地为数据设置截然不同的方法。这似乎是一个坏主意。