单类单继承虚函数下的数据成员布局
-
-
- [1. 单一类带虚函数的数据成员布局](#1. 单一类带虚函数的数据成员布局)
- [2. 单一继承父类带虚函数的数据成员布局](#2. 单一继承父类带虚函数的数据成员布局)
- [3. 单一继承父类不带虚函数的数据成员布局](#3. 单一继承父类不带虚函数的数据成员布局)
-
在单类单继承的情况下,虚函数的存在会影响数据成员的布局。虚函数表(vtable)和虚指针(vptr)是实现多态性的重要机制。
1. 单一类带虚函数的数据成员布局
当一个类包含虚函数时,编译器会为该类生成一个虚函数表(vtable),并在每个对象中添加一个指向该表的指针(vptr)。虚指针通常是对象内存布局中的第一个成员。
示例代码:
cpp
#include <iostream>
class MyClass {
public:
int var1;
double var2;
virtual void myVirtualFunction() {
std::cout << "MyClass virtual function" << std::endl;
}
};
int main() {
MyClass obj;
std::cout << "Address of obj: " << &obj << std::endl;
std::cout << "Address of vptr: " << reinterpret_cast<void**>(&obj) << std::endl;
std::cout << "Address of var1: " << &obj.var1 << std::endl;
std::cout << "Address of var2: " << &obj.var2 << std::endl;
return 0;
}
运行结果(地址可能因系统和编译器不同而有所不同):
Address of obj: 0x71fe30
Address of vptr: 0x71fe30
Address of var1: 0x71fe38
Address of var2: 0x71fe40
在上面的代码中:
MyClass包含一个虚函数myVirtualFunction。obj对象的内存布局中包含一个虚指针vptr,指向虚函数表。vptr通常是对象内存布局中的第一个成员,紧接着是var1和var2。
2. 单一继承父类带虚函数的数据成员布局
当子类继承一个带有虚函数的父类时,子类对象的内存布局包含父类的虚指针和数据成员,以及子类自己的数据成员。
示例代码:
cpp
#include <iostream>
class Base {
public:
int baseVar;
virtual void baseVirtualFunction() {
std::cout << "Base virtual function" << std::endl;
}
};
class Derived : public Base {
public:
char derivedVar;
void baseVirtualFunction() override {
std::cout << "Derived override function" << std::endl;
}
};
int main() {
Derived obj;
std::cout << "Address of obj: " << &obj << std::endl;
std::cout << "Address of vptr: " << reinterpret_cast<void**>(&obj) << std::endl;
std::cout << "Address of baseVar: " << &obj.baseVar << std::endl;
std::cout << "Address of derivedVar: " << static_cast<void*>(&obj.derivedVar) << std::endl;
return 0;
}
运行结果(地址可能因系统和编译器不同而有所不同):
Address of obj: 0x71fe40
Address of vptr: 0x71fe40
Address of baseVar: 0x71fe48
Address of derivedVar: 0x71fe4c
在上面的代码中:
Base类包含一个虚函数baseVirtualFunction。Derived类继承自Base类,并重写了baseVirtualFunction。Derived类对象obj的内存布局包含父类的虚指针vptr和数据成员baseVar,以及子类的成员derivedVar。
3. 单一继承父类不带虚函数的数据成员布局
当子类继承一个不带虚函数的父类时,子类对象的内存布局仅包含父类和子类的成员变量,不包含虚指针。
示例代码:
cpp
#include <iostream>
class Base {
public:
int baseVar;
};
class Derived : public Base {
public:
char derivedVar;
};
int main() {
Derived obj;
std::cout << "Address of obj: " << &obj << std::endl;
std::cout << "Address of baseVar: " << &obj.baseVar << std::endl;
std::cout << "Address of derivedVar: " << static_cast<void*>(&obj.derivedVar) << std::endl;
return 0;
}
运行结果(地址可能因系统和编译器不同而有所不同):
Address of obj: 0x71fe48
Address of baseVar: 0x71fe48
Address of derivedVar: 0x71fe4c
在上面的代码中:
Base类不包含虚函数。Derived类继承自Base类。Derived类对象obj的内存布局仅包含父类的成员baseVar和子类的成员derivedVar,不包含虚指针。