C ++如果类被虚拟继承,内部会发生什么?

时间:2016-12-15 18:21:33

标签: c++ virtual-functions

#include<iostream>
using namespace std;
class Person {
public:
    Person(int x) { cout << "Person::Person(int ) called" << endl; }
    //Person()   { cout << "Person::Person() called" << endl; }
};

class Faculty : virtual public Person {
public:
    Faculty(int x):Person(x) {
    cout<<"Faculty::Faculty(int ) called"<< endl;
    }
};

class Student : virtual public Person {
public:
    Student(int x):Person(x) {
        cout<<"Student::Student(int ) called"<< endl;
    }
};

class TA : public Faculty, public Student {
public:
    TA(int x):Student(x), Faculty(x),Person(x) {
        cout<<"TA::TA(int ) called"<< endl;
    }
};

int main() {
    cout<<"size Person "<<sizeof(Person)<<"\n";
    cout<<"size Faculty "<<sizeof(Faculty)<<"\n";
    cout<<"size Student "<<sizeof(Student)<<"\n";
    cout<<"size TA "<<sizeof(TA)<<"\n";
}

输出:

大小人1 规模教师8 规模学生8 大小TA 16

编译器内部发生了什么?我认为编译器肯定会添加VPTR,如果它添加VPTR然后它分配给NULL?

对于虚拟析构函数,编译器还会添加VPTR,编译器如何在内部解析所有内容?

1 个答案:

答案 0 :(得分:1)

在C ++中,对象是可寻址的,因此必须具有与之关联的大小。在Person的情况下,没有成员变量,因此不需要为实例化对象分配任何空间。但是,因为它必须具有一个大小,编译器给它的大小为1.

如果我向每个类添加成员,我们就可以在每个对象中打印数据,看看发生了什么:

class Person {
public:
    Person(int x) {
        cout << "Person::Person(int ) called" << endl;
        y = 0xAAAAAAAAAAAAAAAA;
    }

    volatile unsigned long long int y;
};

class Faculty : virtual public Person {
public:
    Faculty(int x):Person(x) {
        cout<<"Faculty::Faculty(int ) called"<< endl;
        y = 0xBBBBBBBBBBBBBBBB;
    }

    volatile unsigned long long int y;
};

class Student : virtual public Person {
public:
    Student(int x):Person(x) {
        cout<<"Student::Student(int ) called"<< endl;
        y = 0xCCCCCCCCCCCCCCCC;
    }

    volatile unsigned long long int y;
};

class TA : public Faculty, public Student {
public:
    TA(int x):Person(x), Student(x), Faculty(x) {
        cout<<"TA::TA(int ) called"<< endl;
        y = 0xDDDDDDDDDDDDDDDD;
    }

    volatile unsigned long long int y;
};

通过使用以下函数打印分配给每个类的实例化对象的数据:

void print_obj(void* obj, unsigned size) {
    unsigned char * ptr = (unsigned char *)obj;
    for(unsigned i = 0; i < size; i++)
        printf("%02X", ptr[i]);
}

这是输出(gcc版本4.9.2):

Printing Person
AAAAAAAAAAAAAAAA

Printing Faculty
9814400000000000BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA

Printing Student
7814400000000000CCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAA

Printing TA
D813400000000000BBBBBBBBBBBBBBBBF013400000000000CCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDAAAAAAAAAAAAAAAA

您可以看到每个继承类的成员以及每个继承类的指针(字节乱序,因为内存是小端)。我认为可以安全地假设指针指向继承类的virtual method table

如果删除类成员,最终会得到VMT指针,类大小将与您在问题中列出的类相同。