理解虚函数有困难

use*_*730 3 c++

#include<iostream>

using namespace std;

class X
{
    int a;
    int b;
    public:
    void f(int a)
    {
        cout<<"\nInside X";
    }


    virtual void abc ()
    {
        cout<<"\nHello X";
    }

};


class Y : public X
{
    int a;
    public:

    void f(int a, int b)
    {
        cout<<"\nInside Y";
    }


    void abc()
    {
        cout<<"\nHello Y";
    }

};



int main()
{

    X a;

    cout<<sizeof(X);

    Y b;

    cout<<sizeof(Y);

    X *h = new Y;

    h->abc();
}
Run Code Online (Sandbox Code Playgroud)

我理解类X的大小是12个字节的原因是因为它包含一个到虚拟表的vptr(虚拟指针).无论如何我可以读取这个虚拟表,如果没有,至少可以访问虚拟指针.我尝试过使用工会,但它给了我一些错误.

另外,当我调用h-> abc()时,它如何知道类的对象,h指向?我认为大部分都是在编译时完成的.但是当你有一个指向派生类的基类指针时,它如何知道要执行哪个类函数.考虑这两种情况

X *h = new X;
h->abc();/* This would call the abc function in X */
Run Code Online (Sandbox Code Playgroud)

X *h = new Y;
h->abc();/* This would call the abc function in Y*/
Run Code Online (Sandbox Code Playgroud)

我读过,h指针会转到它指向的对象的vtable,因此会调用该函数吗?但是如何在运行时实现?

min*_*ain 6

好的,第一个问题:我举一个可能更好理解的例子! 在此输入图像描述

#include<iostream>
using namespace std;
class Base1 {

    public:

        int ibase1;

        Base1():ibase1(10) {}

        virtual void f() { cout << "Base1::f()" << endl; }

        virtual void g() { cout << "Base1::g()" << endl; }

        virtual void h() { cout << "Base1::h()" << endl; }
};

class Base2 {

    public:

        int ibase2;

        Base2():ibase2(20) {}

        virtual void f() { cout << "Base2::f()" << endl; }

        virtual void g() { cout << "Base2::g()" << endl; }

        virtual void h() { cout << "Base2::h()" << endl; }

};

class Base3 {

    public:

        int ibase3;

        Base3():ibase3(30) {}

        virtual void f() { cout << "Base3::f()" << endl; }

        virtual void g() { cout << "Base3::g()" << endl; }

        virtual void h() { cout << "Base3::h()" << endl; }
};

class Derive : public Base1, public Base2, public Base3 {

    public:

        int iderive;

        Derive():iderive(100) {}

        virtual void f() { cout << "Derive::f()" << endl; }

        virtual void g1() { cout << "Derive::g1()" << endl; }

};
Run Code Online (Sandbox Code Playgroud)

这是一个派生类的内存等级,它实现了三个基类base1,base2,base3,你在其中:

Base1 *p1 = new Derive();
Base2 *p2 = new Derive();
Base3 *p3 = new Derive();
Run Code Online (Sandbox Code Playgroud)

p1将指向vtale1,p2将指向vtable2,p3将指向vtable3,如果调用某个虚函数,它将找到非常虚拟的表并获取地址!

在你的代码中:

X *h = new Y;
Run Code Online (Sandbox Code Playgroud)

h将指向Y的内存的开始位置,这是X的虚拟表,他将找到abc()在Y中实现的地址!

你的第二个问题:

编译器会将成员函数视为普通函数,因此它将成员函数的地址放入其中code section,因此它不会占用内存!

如果你想阅读虚拟表,你可以尝试这样:我在gcc4.7的例子中尝试过

typedef void(*Func)(void);
    Derive d;
    int **pd = (int **)(&d);
    int i = 0;
    while(i < 4)
    {
        Func f = (Func)pd[0][i];
        f();
        i++;
    }
    int s = (int)(pd[1]);
    cout << s << endl;
    i = 0;
    cout << "===============================================" << endl;
    while(i < 3)
    {
        Func f = (Func)pd[2][i];
        f();
        i++;
    }
    s = (int)(pd[3]);
    cout << s << endl;
    cout << "===============================================" << endl;
    i = 0;
    while(i < 3)
    {
        Func f = (Func)pd[4][i];
        f();
        i++;
    }
    s = (int)(pd[5]);
    cout << s << endl;
    s = (int)(pd[6]);
cout << s << endl;
Run Code Online (Sandbox Code Playgroud)

你会得到如下结果:

 Derive::f()
Base1::g()
Base1::h()
Derive::g1()
10
===============================================
Derive::f()
Base2::g()
Base2::h()
20
===============================================
Derive::f()
Base3::g()
Base3::h()
30
100
Run Code Online (Sandbox Code Playgroud)