虚函数和纯虚函数的区别

244

纯虚函数和虚函数有什么区别?我知道"纯虚函数是没有函数体的虚函数",但这意味着什么?下面这行代码实际上执行了什么操作:

virtual void virtualfunctioname() = 0

3
“一个没有主体的虚函数” > 这是不正确的。它们完全可以有主体。 - v.oddou
4个回答

299

虚拟函数使其所在的类成为一个多态基类。派生类可以重写虚拟函数。通过基类指针/引用调用的虚拟函数将在运行时解析。也就是说,对象的动态类型而不是静态类型将被使用:

 Derived d;
 Base& rb = d;
 // if Base::f() is virtual and Derived overrides it, Derived::f() will be called
 rb.f();  

纯虚函数是以=0结束的虚函数声明:

class Base {
  // ...
  virtual void f() = 0;
  // ...

定义纯虚函数的类会隐式变成抽象类(与Java不同,Java有一个关键字来显式声明抽象类),抽象类不能被实例化。派生类需要重写/实现所有继承的纯虚函数。如果不这样做,则它们也将变为抽象类。

C ++的一个有趣的“特性”是,类可以定义具有实现的纯虚函数。(这有争议的用法。)


请注意,C++11引入了一个新的用途,使用deletedefault关键字,其语法类似于纯虚函数:

my_class(my_class const &) = delete;
my_class& operator=(const my_class&) = default;

参见这个问题这个问题,了解更多关于使用deletedefault的信息。


4
哦,所以纯虚函数和Java/C#接口中的方法几乎是相同的东西。很棒。 - Nicholas Miller
6
@Nick: 的确如此。只是C ++在这方面给了你更多的自由。(你可以在C++中实现纯虚函数,并且你可以混合使用纯虚函数、非纯虚函数和非虚拟函数在同一个类中。(通常最好不要这样做,但如果需要,你可以这样做。) - sbi
@Sbi 我认为“使用=0来定义纯虚函数”的总结点值得保留。也许只需在最后添加“简而言之,如果您想要纯虚函数,请使用=0”。 - thecoshman
呵呵,有趣的“特性”……还是“漏洞”?毕竟两者之间可以互换。 - Xsmael
@Xsmael:Stroustrup宣称,你可以对任何纯虚函数这样做是一个特性。(对于纯虚析构函数而言这是_必须_的,而且Stroustrup在多次表示他不喜欢语法限制。) 而且,一个函数既可以是纯虚的又可以被实现。我会添加一个讨论这个问题的链接。 - sbi

43

对于虚函数,您需要在基类中提供实现。但派生类可以覆盖此实现以提供自己的实现。通常情况下,对于纯虚函数不提供实现。您可以在函数声明末尾添加 =0 来使函数成为纯虚函数。同时,包含纯虚函数的类是抽象的,即无法创建该类的对象。


25

纯虚函数通常不会(但可以)在基类中实现,并且必须在叶子子类中实现。

您可以通过在声明中附加 "= 0" 来表示这一事实,就像这样:

class AbstractBase
{
    virtual void PureVirtualFunction() = 0;
}

如果你的子类没有实现纯虚函数,那么你就不能声明和实例化该子类:

class Derived : public AbstractBase
{
    virtual void PureVirtualFunction() override { }
}

通过添加override关键字,编译器将确保有一个与基类的虚函数同名同参的函数存在。


3
在C++中,可以实现一个纯虚函数。 - sbi
3
是的,对于纯虚析构函数,它必须被实现。 - daramarak
@daramarak:C++中的纯虚构造函数? - Naveen
1
@Naveen:https://dev59.com/questions/pXE85IYBdhLWcg3wyGt_ - sbi
@sbi:我是读成构造函数而不是析构函数了。我的错误.. - Naveen
@Naveen:我也是。我把你的读成了“析构函数”(destructor)... - sbi

10

在C++中,您实际上可以为纯虚函数提供实现。唯一的区别是在派生类实例化之前,必须由派生类实现所有纯虚函数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接