【C++语法实践】10-C++ 虚函数

override和overwrite实例代码

#include <iostream>
using namespace std;

class Base
{
public:
    virtual void func1()
    {
        cout << "Base::func1" << endl;
    }

    void func2()
    {
        cout << "Base::func2" << endl;
    }
};

class Drived : public Base
{
public:
    void func1()
    {
        cout << "Drived::func1" << endl;
    }

    void func2()
    {
        cout << "Drived::func2" << endl;
    }
};

int main()
{
    Base* base;
    Drived drived;
    base = &drived;
    base->func1(); // 是虚函数,基类指针指向派生类对象,调用的派生类对象的虚函数,override
    base->func2(); // 是非虚函数,根据p指针实际类型来调用相应类的成员函数,overwrite
    return 0;
}

/*
Drived::func1
Base::func2
*/

虚析构函数

#include <iostream>
using namespace std;

class Base
{
public:
    Base()
    {
        cout << "Base Constructor" << endl;
    }

    virtual ~Base()
    {
        cout << "Base Destructor" << endl;
    }

    // 如果一个类要作为多态基类,要将析构函数作为虚析构函数
    virtual void func1()
    {
        cout << "Base::func1" << endl;
    }

    void func2()
    {
        cout << "Base::func2" << endl;
    }
};

class Derived : public Base
{
public:
    Derived()
    {
        cout << "Derived Constructor" << endl;
    }

    ~Derived()
    {
        cout << "Derived Destructor" << endl;
    }

    void func1()
    {
        cout << "Derived::func1" << endl;
    }

    void func2()
    {
        cout << "Derived::func2" << endl;
    }
};

int main()
{
    Base* base;
    base = new Derived;

    base->func1();
    base->func2();

    delete base;
}

/*
如果析构函数不是虚析构函数,那么在delete base指针的时候,只会调用Base类的析构函数,
但是在开辟Derived空间的时候,也可能会在堆上创建内存,所以也需要释放内存
*/

虚表指针

#include <iostream>
using namespace std;

#pragma pack(push) //保存对齐状态
#pragma pack(8) //设定为8字节对齐
class Base
{
public:
    virtual void func1()
    {
        cout << "Base::func1" << endl;
    }

    virtual void fun2()
    {
        cout << "Base::func2" << endl;
    }

    int baseData_;
};
#pragma pack(pop) //恢复对齐状态

class Derived : public Base
{
public:
    virtual void func2()
    {
        cout << "Derived::func2" << endl;
    }

    virtual void func3()
    {
        cout << "Derived::func3" << endl;
    }

    int derivedData_;
};

typedef void (*FUNC)();

int main()
{
    Base* basePoint;
    long long** point = (long long**)(&basePoint);
    FUNC fun = (FUNC)point[0][0];
    fun();

    return 0;
}

基类声明为虚函数之后,其派生类不管有没有virtual关键字,其函数都是虚函数。

存在虚函数的类,内存模型中前4个字节(64位系统指针是8个字节)存放虚表指针,虚表中存放的是虚函数。如果是派生类中,虚表指针的指向的虚表存放的是基类的虚函数,覆盖的虚函数,自己的虚函数。

对象切割、转换

#include <iostream>
using namespace std;

class CObject
{
public:
    virtual void func()
    {
        cout << "CObject func" << endl;
    }
};

class CDocument : public CObject
{
public:
    void normalFunc()
    {
        cout << "CDocument func" << endl;
        func();
    }

    virtual void func()
    {
        cout << "CDocument func" << endl;
    }
};

class CMyDoc : public CDocument
{
public:
    virtual void func()
    {
        cout << "CMyDoc func" << endl;
    }
};

int main()
{
    CMyDoc myDoc;
    CMyDoc* pmyDoc = new CMyDoc;

    cout << "# Test 01" << endl;
    myDoc.func();

    cout << "# Test 02" << endl;
    ((CDocument*)&myDoc)->func(); // 等同指向派生类的基类指针

    cout << "# Test 03" << endl;
    pmyDoc->func();

    cout << "# Test 04" << endl; // 向上转换,完完全全将一个派生类对象转换成一个基类对象
                                 // 虚表指针也发生了变化
    ((CDocument)myDoc).func();
    return 0;
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部