C++ 为什么要使用虚函数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8824359/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 19:10:10  来源:igfitidea点击:

Why use virtual functions?

c++virtual-functions

提问by haris

Possible Duplicate:
Can someone explain C++ Virtual Methods?

可能的重复:
有人可以解释 C++ 虚拟方法吗?

I have a question regarding to the C++ virtual functions.

我有一个关于 C++ 虚函数的问题。

Why and when do we use virtual functions? Can anyone give me a real time implementation or use of virtual functions?

为什么以及何时使用虚函数?谁能给我实时实现或使用虚拟功能?

回答by Alok Save

You use virtual functions when you want to override a certain behavior (read method) for your derived class rather than the one implemented for the base class and you want to do so at run-time through a pointer to the base class.

当您想要覆盖派生类的某种行为(读取方法)而不是为基类实现的行为,并且您希望在运行时通过指向基类的指针来实现时,您可以使用虚函数。

The classic example is when you have a base class called Shapeand concrete shapes (classes) that derive from it. Each concrete class overrides (implements a virtual method) called Draw().

典型的例子是当你有一个基类Shape和从它派生的具体形状(类)时。每个具体类都覆盖(实现一个虚方法)称为Draw().

The class hierarchy is as follows:

类层次结构如下:

Class hierarchy

类层次结构

The following snippet shows the usage of the example; it creates an array of Shapeclass pointers wherein each points to a distinct derived class object. At run-time, invoking the Draw()method results in the calling of the method overridden by that derived class and the particular Shapeis drawn (or rendered).

以下代码段显示了示例的用法;它创建了一个Shape类指针数组,其中每个指针指向一个不同的派生类对象。在运行时,调用该Draw()方法会导致调用由该派生类覆盖的方法,并Shape绘制(或呈现)特定的方法。

Shape *basep[] = { &line_obj, &tri_obj,
                   &rect_obj, &cir_obj};
for (i = 0; i < NO_PICTURES; i++)
    basep[i] -> Draw ();

The above program just uses the pointer to the base class to store addresses of the derived class objects. This provides a loose coupling because the program does not have to change drastically if a new concrete derived class of shapeis added anytime. The reason is that there are minimal code segments that actually use (depend) on the concrete Shapetype.

上面的程序只是使用指向基类的指针来存储派生类对象的地址。这提供了松散耦合,因为如果shape随时添加新的具体派生类,则程序不必大幅更改。原因是实际使用(依赖)具体Shape类型的代码段最少。

The above is a good example of the Open Closed Principleof the famous SOLIDdesign principles.

以上是著名的SOLID设计原则的开闭原则的一个很好的例子。

回答by Volodymyr Rudyi

You use virtual functions when you need handle different objects in the same way. It`s called polymorphism. Let's imagine you have some base class - something like classical Shape:

当您需要以相同的方式处理不同的对象时,您可以使用虚函数。这叫做多态。假设您有一些基类 - 类似于经典 Shape:

    class Shape
    {
        public:
           virtual void draw() = 0;
           virtual ~Shape() {}
    };

    class Rectange: public Shape
    {
        public:
            void draw() { // draw rectangle here } 
    };


    class Circle: public Shape
    {
        public:
           void draw() { // draw circle here }
    };

Now you can have vector of different shapes:

现在您可以拥有不同形状的向量:

    vector<Shape*> shapes;
    shapes.push_back(new Rectangle());
    shapes.push_back(new Circle());

And you can draw all shapes like this:

你可以像这样绘制所有形状:

    for(vector<Shape*>::iterator i = shapes.begin(); i != shapes.end(); i++)
    {
          (*i)->draw();
    }

In this way you are drawing different shapes with one virtual method - draw(). Proper version of method is selected based on run time information about type of object behind pointer.

通过这种方式,您可以使用一种虚拟方法绘制不同的形状 - draw()。根据有关指针后面对象类型的运行时信息选择方法的正确版本。

NoticeWhen you use virtual functions you can declare them as pure virtual(like in class Shape, just place " = 0" after method proto). In this case you won't be able to create instance of object with pure virtual function and it will be called Abstract class.

注意当您使用虚函数时,您可以将它们声明为虚函数(就像在类 Shape 中,只需在方法 proto 之后放置“=0”)。在这种情况下,您将无法使用纯虚函数创建对象的实例,它将被称为抽象类。

Also notice "virtual" before destructor. In case when you are planning work with objects through pointers to their base classes you should declare destructor virtual, so when you call "delete" for base class pointer, all chain of destructors will be called and there won't be memory leaks.

还要注意析构函数之前的“虚拟”。如果您计划通过指向其基类的指针来处理对象,您应该将析构函数声明为 virtual,因此当您为基类指针调用“delete”时,将调用所有析构函数链,并且不会出现内存泄漏。

回答by holgac

Think of animals class, and derived from it are cat, dog and cow. Animal class has a

想想动物类,从它衍生而来的是猫、狗和牛。动物类有一个

virtual void SaySomething()
{
    cout << "Something";
}

function.

功能。

Animal *a;
a = new Dog();
a->SaySomething();

Instead of printing "Something", dog should say "Bark", cat should say "Meow". In this example you see that a is a Dog, but there are some times that you have an animal pointer and don't know which animal it is. You don't want to know which animal it is, you just want the animal to say something. So you just call virtual function and cats will say "meow" and dogs will say "bark".

不要打印“Something”,狗应该说“Bark”,猫应该说“Meow”。在这个例子中,你看到 a 是一只狗,但有时你有一个动物指针,但不知道它是哪种动物。你不想知道它是哪种动物,你只想让动物说点什么。所以你只要调用虚函数,猫会说“喵”,狗会说“吠”。

Of course, SaySomething function should have been pure virtual to avoid possible errors.

当然,SaySomething 函数应该是纯虚函数以避免可能的错误。

回答by CashCow

You would use a virtual function to implement "polymorphism", in particular where you have an object, don't know what the actual underlying type is, but know what operation you want to perform on it, and the implementation of this (how it does it) differs dependent on what type you actually have.

您将使用虚函数来实现“多态性”,特别是在您拥有一个对象的情况下,不知道实际的底层类型是什么,但知道您想对其执行什么操作,以及它的实现(它是如何实现的)是否)取决于您实际拥有的类型。

Essentially what is commonly called the "Liskov Substitution Principle" named after Barbara Liskov who spoke about this around 1983.

基本上就是通常所说的“Liskov 替换原则”,以 Barbara Liskov 的名字命名,她在 1983 年左右谈到了这一点。

Where you need to use dynamic runtime decisions where, at the point the code invoking the function is called, you do not know what types may pass through it, either now or in the future, this is a good model to use.

在需要使用动态运行时决策的地方,在调用函数的代码时,您不知道现在或将来可能通过它的类型,这是一个很好的模型。

It isn't the only way though. There are all sorts of "callbacks" that can take a "blob" of data and you might have tables of callbacks dependent on a header block in the data that comes in, e.g. a message processor. For this there is no need to use a virtual function, in fact what you would probably use is sort-of how a v-table is implemented only with one entry (e.g. a class with just one virtual function).

但这不是唯一的方法。有各种各样的“回调”可以获取“blob”数据,并且您可能有依赖于传入数据中的标头块的回调表,例如消息处理器。为此,没有必要使用虚函数,事实上,您可能会使用的是如何仅使用一个条目(例如,只有一个虚函数的类)来实现 v 表。