简体   繁体   English

C ++中的虚函数和继承

[英]Virtual function and inheritance in C++

The code segment below works fine: 下面的代码段工作正常:

#include <iostream> 
#include <string>

using namespace std;

class HelpInterface {
public:
    void getHelp();
};

class Applicaiton : public HelpInterface {
public:
    void getHelp() {
        cout << "General help";
    }
};

int main(void) {
    Applicaiton applicaiton;
    applicaiton.getHelp();
}

Make the getHelp function virtual in HelpInterface class and I will get a linker error: 在HelpInterface类中将getHelp函数设为虚拟,然后我将得到一个链接器错误:

class HelpInterface {
public:
    virtual void getHelp();
};

If I make an empty implemenation of getHelp as below things will work again: 如果我对getHelp进行空实现,则以下内容将再次起作用:

class HelpInterface {
public:
    virtual void getHelp() {};
};

Can someone please help me understand why virtual throws a linker error unless I have an implementation for getHelp in the base class and why a non-virtual function with no implementation works just fine? 有人可以帮我理解为什么除非我在基类中有getHelp的实现,否则virtual抛出链接器错误的原因,为什么没有实现的非虚拟函数也可以正常工作? In this example, the base function never gets called. 在此示例中,基本函数永远不会被调用。

Here is a screenshot of VS2013 with the linker error: 这是带有链接器错误的VS2013的屏幕截图: VS2013的屏幕截图

If you want your base class method to be virtual and provide no implementation, you must set it equal to zero like this: 如果希望基类方法是虚拟的并且不提供任何实现,则必须将其设置为零,如下所示:

class HelpInterface {
public:
    virtual void getHelp() = 0;
};

This is known as a pure virtual method. 这被称为纯虚拟方法。 It has the effect of making your class abstract and forcing all of its derived classes to provide an implementation of the method. 它的作用是使您的类抽象化,并强制其所有派生类提供该方法的实现。 Consequently, take note that you will no longer be able to create an instance of the base class because it is abstract. 因此,请注意,您将不再能够创建基类的实例,因为它是抽象的。

When a method is in the base class but isn't virtual the linker will not actually reference the implementation of the method if you don't have an explicit call to that method on either a pointer/reference to the base type (On an instance of the derived class) or an instance of the base type. 当方法在基类中但不是虚拟方法时,如果您没有在指向基类型的指针/引用上显式调用该方法,则链接器实际上不会引用该方法的实现。派生类的名称)或基本类型的实例。

Virtual functions can be implemented a number of different ways, and are implementation specific. 虚函数可以通过多种不同的方式实现,并且是实现特定的。 One of the most common is by using a virtual table. 最常见的方法之一是使用虚拟表。 (Also known by virtual method table, virtual function table, virtual call table, dispatch table, vtable, or vftable), and I'm pretty sure your compiler (VS2013) uses this method of implementing virtual functions. (也被虚拟方法表,虚拟函数表,虚拟调用表,调度表,vtable或vftable所熟知),我很确定您的编译器(VS2013)使用此方法来实现虚拟函数。

A virtual table is a table of function pointers for the virtual member functions. 虚拟表是虚拟成员函数的函数指针表。 The class instance would contain a pointer to the table that the class belongs to. 该类实例将包含一个指向该类所属表的指针。

When you make a function virtual the linker tries to put it into the virtual table for that type. 将函数虚拟化时,链接器会尝试将其放入该类型的虚拟表中。 It doesn't matter whether you call it or not or instantiate a base class (also an implementation specific detail). 无论是否调用它或实例化基类(也是实现特定的细节)都没有关系。

As qexyn has already answered, to get around that you declare the method as pure virtual by adding = 0 after the virtual function declaration. 正如qexyn已经回答的那样,要解决此问题,您可以在虚拟函数声明之后添加= 0 ,从而将该方法声明为纯虚拟方法。 This tells the linker to put a null pointer in the virtual function table for the class. 这告诉链接器在类的虚拟函数表中放置一个空指针。 You can also declare the virtual function pure virtual and also provide an implementation. 您还可以将虚函数声明为纯虚函数,并提供实现。 This forces the derived classes to implement that function, but allows them to choose to use the default method. 这将强制派生类实现该功能,但允许他们选择使用默认方法。

The reason for this is that your base class definition is using indirection to get the actual function for Application . 这是因为您的基类定义使用间接获取Application的实际功能。

This is often implemented with a function pointer, but in any case there could be a derived class that doesn't override the base class implementation. 这通常是通过函数指针来实现的,但是在任何情况下都可能存在不覆盖基类实现的派生类。

Although this isn't usually reproducible that is simply because member functions are implicitly declared inline and when the implementation is visible an optimizing compiler will do exactly that; 尽管这通常是不可重现的 ,这仅仅是因为成员函数是隐式声明为inline声明的,并且当实现可见时,优化的编译器会做到这一点。 inline the function. 内联函数。 The proof is in the optimization. 证明在于优化。

What you want, is to make sure that every derived class from your base implements getHelp() . 您想要的是确保从基类派生的每个类都实现getHelp() This is a common idiom and is a core language feature. 这是一个常见的习惯用法,是一种核心语言功能。 You want a "pure virtual function". 您需要一个“纯虚函数”。 This will make your base class an "abstract base class" which is actually a synonym for "interface" in object-oriented jibber-jabber. 这将使您的基类成为“抽象基类”,它实际上是面向对象的jibber-jabber中“ interface”的同义词。

The way to do this in C++ is with a special member-function specific syntax after all of the member function qualifiers (I'm using trailing return types here cause I think they're pretty): 在C ++中,这样做的方法是在所有成员函数限定符之后使用特定于成员函数的特殊语法(我在这里使用尾随返回类型是因为我认为它们很漂亮):

class base{
    public:
        virtual auto func() -> void = 0;
};

This specifies that base is an abstract base class with a pure virtual function func() that all classes derived from it will implement. 这指定base是带有纯虚函数func()的抽象基类,所有从其派生的类都将实现该函数。

In your case you would write: 您的情况是:

class HelperInterface{
    public:
        virtual void getHelp() = 0; // probably want const qualifier
};

And just leave Application as it is. 并保持Application原样。

You learn something every day, huh? 你每天都学点东西吧?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM