C++快速入门之virtual

virtual

为什么需要virtual,因为C++选择了优先静态绑定,所以需要一个特别的关键字来告诉编译器这个函数需要动态绑定(动态绑定通常就是所谓的“多态”)。
为什么Object-C没有这样的关键字?因为据我所知,Object-C等语言选择了动态绑定,所以它们没有像C++里面的静态绑定函数(不带virtual的),
所以就不需要这个关键字。大体上相当于其函数都是virtual的……

从语言风格上说,C++讲究的是对最终实现的极致把握。普通的类成员函数在调用时,直接执行相应内存地址的代码即可。
但如果有多态,那么实现起来需要维护一个表,在运行时动态根据对象的类型决定使用哪部分代码。这两者是有性能差异的。
C++允许你根据需要选择最快的实现方式。ObjC完全是考虑程序员的方便,面向对象部分用起来几乎就已经是“动态”语言了。
它通过消息传递实现类函数的调用,非常灵活。开销相比于C++是大不少的,但它不关心这点儿开销。

实例1

#include <iostream>

using namespace std;

class Base {
public:
    Base() {}

public:
    virtual void print() { cout << "Base"; }
};

class Derived : public Base {

public:
    Derived() {}

public:
    void print() { cout << "Derived"; }
};

int main() {
    Base *point = new Derived();
    point->print();

    delete point;
}

实例2

class ClxBase {

public :
    ClxBase() {};

    virtual ~ ClxBase() {};

    virtual void DoSomething() {
        cout << "Do something in class ClxBase ! " << endl;
    };
};


class ClxDerived : public ClxBase {

public :
    ClxDerived() {};

    ~ ClxDerived() {
        cout << "Output from the destructor of class ClxDerived!" << endl;
    };


    void DoSomething() {
        cout << "Do something in class ClxDerived ! " << endl;
    };
};

int main() {
    ClxBase *pTest = new ClxDerived;
    pTest->DoSomething();
    delete pTest;
}

这个很简单,非常好理解。
但是,如果把类ClxBase析构函数前的virtual去掉,那输出结果就是下面的样子了:

Do something in class ClxDerived!

也就是说,类ClxDerived的析构函数根本没有被调用!一般情况下类的析构函数里面都是释放内存资源,而析构函数不被调用的话就会造成内存泄漏。
我想所有的C++程序员都知道这样的危险性。当然,如果在析构函数中做了其他工作的话,那你的所有努力也都是白费力气。
所以,文章开头的那个问题的答案就是--这样做是为了当用一个基类的指针删除一个派生类的对象时,派生类的析构函数会被调用。
当然,并不是要把所有类的析构函数都写成虚函数。因为当类里面有虚函数的时候,编译器会给类添加一个虚函数表,里面来存放虚函数指针,这样就会增加类的存储空间。
所以,只有当一个类被用来作为基类的时候,才把析构函数写成虚函数。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!