使用纯虚方法的抽象类 - 为什么可以做“Abstract * abs3;”?

时间:2011-09-01 10:42:07

标签: c++ abstract-class pure-virtual

请考虑以下事项:

class Abstract
{
public:
    virtual void func() = 0;
};

int main() {

    Abstract abs1; // doesn't compile
    Abstract * abs2 = new Abstract(); // doesn't compile
    Abstract * abs3;  // compiles

    return 0;
}

请注意我没有实施func(),为什么可以Abstract * abs3; 我们有一个纯虚方法和一个抽象类? 我知道如果我尝试做abs3-> func(),我会遇到运行时错误。但是,我还不清楚为什么C ++允许代码编译......?

谢谢,罗恩

6 个答案:

答案 0 :(得分:7)

abs3是指向该类的指针。它可以初始化为Abstract的任何具体子类,或者安全地初始化为NULL。编译器必须允许它,因为虽然您不能创建抽象类,但您必须能够创建指向它们的指针。请参阅下面的示例

class Concrete: public Abstract
{
public:
    virtual void func() { // do something };
};


int main ()
{
   Abstract* abs3 = NULL;
   abs3 = new Concrete;
}

答案 1 :(得分:4)

你不能实例化一个抽象类,但是有一个指向它的指针是完全可以的。事实上,这在OO设计中经常使用。

答案 2 :(得分:3)

简答

编译器不会发出任何错误,因为创建指向Abstract Class的指针是完全正确的。

长答案

除非,为了实例化一个类并创建一个类型的对象,编译器需要知道该类型的组成。

您可以创建指向Abstract类的指针,因为系统上的所有指针都具有相同的大小,无论它们指向何种类型。
请注意,创建指针不会调用构造函数。

您无法创建Abstract类的对象,因为该类具有一些未完全定义的方法,因此编译器不知道该类的组成。因此,禁止它的实例化。

编辑:
即使您为纯虚函数提供了一个定义(并且它完全有效)您仍然无法实例化Abstract类,因为当您将函数声明为纯虚拟时,编译器将该类视为抽象(不完整)并且它无法再实例化。

答案 3 :(得分:1)

实际上,有可能创建指向抽象类的指针的一点是将它指向派生自抽象类的(具体)类:

class Abstract
{
public:
    virtual void func() = 0;
};

class Derived1 : public Abstract
{
public:
    virtual void func() { /* do something */ }
}

class Derived2 : public Abstract
{
public:
    virtual void func() { /* do something else */ }
}

然后,例如:

Abstract * ap;

if (/*something*/)
    ap = new Derived1();
else
    ap = new Derived2();

ap->func();
delete ap;

答案 4 :(得分:1)

继承是你缺少的关键想法。如果Vehicle是抽象的,并且Car是车辆,则Vehicle*是指向实例化Car的指针的完全有效类型。抽象基类是作为方法(引用)的参数的有效类型,无论是Car还是Bike,都将调用func的正确虚拟实现。这是该语言的一个关键特征。

答案 5 :(得分:0)

您根本无法拥有一个尚未实现一个或多个方法的类实例。

你在这里要做的是拥有一个类的实例,它有一个名为func()的纯抽象方法:这是不可能的。

Abstract * abs3

编译为未初始化的指针,您没有分配Abstract的任何实例。

Abstract abs1;
Abstract * abs2 = new Abstract();

永远不会编译。 您应该指定Abstract(通过继承)为func()提供实现,此时您将能够拥有此类派生类的实例。