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

标签 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";
}

Output:

size of Person 1

size of Faculty 8
size of Student 8
size of TA 16

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

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

最佳答案

在 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。对于继承的类。

如果您删除类(class)成员,您最终会得到 VMT 指针,并且类(class)人数将与您在问题中列出的人数相同。

关于如果类是虚拟继承的,C++ 内部会发生什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41170864/

相关文章:

c++ - 文件意外结束

c++ - 用宏循环

c++ - 何时在 C++ 中创建 vtable?

c++ - 为虚拟方法实现组合行为

c++ - 为什么具有虚函数的类与没有虚函数的类对齐方式不同?

c++ - 无条件地从 T 构造函数调用类 T 的纯虚实现?

类属性中的 C++ 指针

c++ - 读取RAW音频文件

c++ - C++中如何同时使用自动引用计数和虚函数?

c++ - 安装使用 Bazel 构建的库