c++的沼泽之函数与虚函数

个人觉得c++继承与多态这块仿佛掉进了泥潭,深陷其中无法自拔。现将部分迷茫的问题总结如下:

1.析构函数为什么要声明为虚函数?

基类的析构函数需要声明为虚函数:
当派生类对象经由基类指针删除时,而基类带着一个non_virtual析构函数,实际执行时发生的是对象的派生类对象成员没有被销毁。即局部销毁,会发生内存泄漏,故通常将基类析构函数声明为虚函数

代码实现为:

#include <iostream>
using namespace std;
#include <windows.h>

class A //基类 
{
public:
    A()//构造函数
        :_a(1)
    {
        cout << "A()" << endl;
    }

    ~A()//析构函数
    {
        cout << "~A()" << endl;
    }
private:
    int _a;
};

class B :public A//B继承A
{
public:
    B()//构造函数
        :_b(2)
    {
        cout << "B()" << endl;
    }
    ~B()//析构函数
    {
        cout << "~B()" << endl;
    }
private:
    int _b;
};

int main()
{
    A *p = new B;//基类指针指向子类对象
    delete p;//删除指针
    system("pause");
    return 0;
}

结果:
这里写图片描述

由此可以发现最后只删除了A类的对象,而没有删除B类的,造成了局部销毁。
解决方案:将基类析构函数声明为virtual,此后删除派生类对象就会销毁整个对象,当然包括派生类成员。
解决部分代码:

//同上面代码区别是将A类的析构函数声明为虚函数
#include <iostream>
using namespace std;
#include <windows.h>

class A
{
public:
    A()
        :_a(1)
    {
        cout << "A()" << endl;
    }

    virtual ~A()//声明为virtual
    {
        cout << "~A()" << endl;
    }
private:
    int _a;
};

class B :public A
{
public:
    B()
        :_b(2)
    {
        cout << "B()" << endl;
    }
    ~B()
    {
        cout << "~B()" << endl;
    }
private:
    int _b;
};

int main()
{
    A *p = new B;
    delete p;
    system("pause");
    return 0;
}

结果为:
这里写图片描述
以上方法解决了局部销毁问题。delete p时经编译器特殊处理后调用destructor() +operator delete从而删除指针p

注意:

析构函数经编译器处理后并非~A(),而是destructor,因此会对基类的析构函数构成隐藏,再者析构函数不能被继承。将基类的析构函数声明为虚函数后,子类对基类的析构函数构成重写,根据对象的指向,调用相应的析构函数。

这里写图片描述

2.不能被声明为虚函数的函数

1. 普通函数
普通函数只能被重载,不能被重写,声明为虚函数无任何意义,因为编译器会在编译时绑定函数。

2.构造函数
因为构造函数本身就是为了初始化对象成员。如果被声明为虚函数,就需要通过vtable虚基表调用,但此时对象还未实例化,找不到vtable,因此不能为虚函数。
从实现上看,vtable实在构造函数调用后才建立的,故构造函数不能为虚函数,同时编译时会报错。

3.内联函数
内联函数是在代码中直接展开,减少调用函数栈的开销,而虚函数是为了继承后对象能准确的执行自己的操作,而且内联函数在编译时展开,虚函数在运行时动态绑定。

4.静态成员函数
静态成员函数对于每个类来说只有一份,各个对象共享一份代码,它的实现不是为了构成多态,而是为了处理静态数据成员,没有动态绑定的必要性。

5.友元函数
友元函数不能被继承即若A为B的友元函数,C是B的友元函数,则不能说C是A的友元函数。都没有继承特性,更谈不上虚函数的说法了!

猜你喜欢

转载自blog.csdn.net/kai29/article/details/80087700