请考虑以下事项:
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 ++允许代码编译......?
答案 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()
提供实现,此时您将能够拥有此类派生类的实例。