目的模型,第四周作业

如果类中有虚函数和成员变量

class Test{ public: char a[2]; virtual void fun(){}};

188金宝搏 1TestSizeVirtualChar.png

  • 按理说sizeof应该是2+8=10,但是却是16,这是因为,此时会发生内存对齐,为了效率,会让内存的大小按照最大的字段的整数倍进行对齐。

 

首先看这样一个类

class Test{};

188金宝搏 2TestSize.png

  • 在c++中,对于一个空类,c++不允许什么都不存在,会有一个字节的占位空间。

 

如果类中有虚函数

class Test{ public: virtual void fun() { }};

188金宝搏 3TestSizeVirtual.png

  • 此时,c++会在类的中产生一个指针,这是一个函数指针,指向虚函数--虚表,因为虚函数要实现一种动态绑定,而其他函数不需要,所以,有虚函数存在的时候,类的对象中会有一个指针来指向所有虚函数。

 

如果类中有函数

class Test{ public: void fun() { }};

188金宝搏 4TestSize.png

  4.内存分配结束后,需要将当前内存空间补充为最大的基本类型变量的倍数。

验证虚表

class TestModel{ public: virtual void test(){ cout<<"this="<<this<<endl; cout<<"test"<<endl; my(); } virtual void test1(){ cout<<"this="<<this<<endl; cout<<"test1"<<endl; myTest(); } TestModel(){ cout<<"构造"<<endl; } virtual ~TestModel(){ cout<<"析构"<<endl; } int i; private: void myTest(){ cout<<"myTest"<<endl; } void my(){ cout<<"my"<<i<<endl; }};

对于上面这样一个类,他的内存分布情况如下

+---------+| other |---> 其他字段|---------|| vptr |---> 虚表 -------> +---------+ +-----------------------------+ 0| test(TestModel* this) | |-----------------------------| 1| test1(TestModel* this) | |-----------------------------| 2| ~TestModel(TestModel* this)| +-----------------------------+

测试代码

#include <iostream>#include <stdio.h>using namespace std;class TestModel{ public: virtual void test(){ cout<<"this="<<this<<endl; cout<<"test"<<endl; my(); } virtual void test1(){ cout<<"this="<<this<<endl; cout<<"test1"<<endl; myTest(); } TestModel(){ cout<<"构造"<<endl; } virtual ~TestModel(){ cout<<"析构"<<endl; } int i; private: void myTest(){ cout<<"myTest"<<endl; } void my(){ cout<<"my"<<i<<endl; }};typedef void (void* self);void fun(){ cout<<"fun"<<endl;}int main(int argc, char const *argv[]){ TestModel a; TestModel b; a.i=0; b.i=1; int64_t* pa = &a; int64_t* pb = &b; void* p1; printf("指针大小%d\n",sizeof; printf("a的地址%p\n",pa); printf("a的虚表地址%p\n",*pa); printf("b的地址%p\n",pb); printf("b的虚表地址%p\n",*pa); Fun funp; funp = (*(; funp; funp = (*(); funp; funp = (*(); funp; return 0;}

188金宝搏 5TestSizeMain.png

+---------+| vptr |---> 虚表 -------> <---*pa==*pb|---------| +-----------------------------+| other | 0| test(TestModel* this) | *(+---------+ |-----------------------------| 1| test1(TestModel* this) | *( |-----------------------------| 2| ~TestModel(TestModel* this)| *( +-----------------------------+
  • 测试代码中,用一个函数指针指向虚表的各个函数,就能调用到对应的函数,说明正确的找到了函数
  • 并且通过传入的函数的指针值不同,调用的函数中打印出来的i不同,可以说明this指针是在函数调用的时候通过参数传入的

  测试代码如下:

如果类中有成员变量

class Test{ char a[2];};

188金宝搏 6TestSizeChar.png

  • 现在看似很正常

 

Apple和Fruit对象内存分配:

  
分别给出下面的类型Fruit和Apple的类型大小(即对象size),并通过画出二者对象模型的方式来解释该size的构成原因。

  2.若类中存在虚函数在对象起始处会存在虚指针。

*注意点.编译器最终分配内存大小需要考虑"位对齐",规则如下:

 

 

#188金宝搏,对象模型:

  根据叶卡林娜的考虑方法,进行试验验证。

   
1.首先按照声明次序依次保存类中数据对象。

 

win10
vs2017 运行结果如下:

  思路整理:首先验证虚指针所存放在内存中的位置,及其占有内存单元。其次验证各个数据对象所在内存及其补位对齐方式。

*补充:类中若存在虚函数(包括继承)则一定存在且仅存在一个虚函数指针指向虚表,虚表中存放虚函数地址。

#作业发布:

188金宝搏 7

#补充,无论堆中或者栈中构建的对象其内存大小均相同。

*补充:在vs编译环境中,数据成员的起始地址必须为内部最大数据类型的整数倍。则存在虚指针时需要考虑补位对齐。

  根据上述摘要及测试代码整理,对象模型如下:

需要注意,继承关系中虚指针是否单元新开辟的内存。

 

#题目说明:

#include <iostream>using namespace std;class Fruit {public: int no; double weight; int key; public: void print() { } virtual void process() {}};class Apple : public Fruit {public: int size; int type;public: void save() { } virtual void process() { }};int main() { cout << "sizeof(Fruit) = " << sizeof(Fruit) << endl; cout << "sizeof(Apple) = " << sizeof(Apple) << endl; Fruit fruit; Apple apple; cout << "Fruit = " << &fruit << endl; cout << "Fruit.no = " << &fruit.no << endl; cout << "Fruit.weight = " << &fruit.weight << endl; cout << "Fruit.key = " << &fruit.key << endl; cout << "Apple = " << &apple << endl; cout << "Apple.no = " << &apple.no << endl; cout << "Apple.weight = " << &apple.weight << endl; cout << "Apple.key = " << &apple.key << endl; cout << "Apple.size = " << &apple.size << endl; cout << "Apple.type = " << &apple.type << endl; system("pause"); return 0;}
class Fruit { int no; double weight; char key;public: void print() { } virtual void process() { }};class Apple: public Fruit { int size; char type;public: void save() { } virtual void process() { }};

#资料整理:  

sizeof(Fruit) = 32sizeof(Apple) = 40Fruit = 003DF8D4Fruit.no = 003DF8DCFruit.weight = 003DF8E4Fruit.key = 003DF8ECApple = 003DF8A4Apple.no = 003DF8ACApple.weight = 003DF8B4Apple.key = 003DF8BCApple.size = 003DF8C4Apple.type = 003DF8C8

  3.变量的起始偏移位置设定为自身字节大小的整数倍,以便读取变量时使得cache速度更快。

 

 

相关文章

Comment ()
评论是一种美德,说点什么吧,否则我会恨你的。。。