类在内存中结构——虚函数,派生类

关于类的大小,请先查看:
类和结构体的内存空间占有问题

简介

C++类是由结构体发展得来的,所以他们的成员变量(C语言的结构体只有成员变量)的内存分配机制是一样的。

高字节与低字节,高地址与低地址,大端模式与小端模式

一、高地址与低地址

内存地址对应成16进制,值大的是高地址,反之为低地址。
类在内存中结构——虚函数,派生类_第1张图片

二、高字节与低字节

如int a=16777220,化为十六进制是0x01 00 00 04则04属于低字节,01属于高字节

三、大端模式与小端模式

大端模式:高字节存放在低地址
类在内存中结构——虚函数,派生类_第2张图片
小端模式:高字节存放在高地址
类在内存中结构——虚函数,派生类_第3张图片

四、存放顺序

  1. 一个整数类型内部
    低地址存储低位,高地址存储高位。比如int a=1,则存储情况为0000(高地址) 0000 0000 0001(低地址)
  2. 若干个局部变量(在栈中存储的)
    先定义的高地址,后定义的低地址
  3. 类、结构体或数组的元素
    先定义的低地址,后定义的高地址

union U {
    char cp[2];
    short sp;
};
int main(int argc, char *argv[])
{
    U temp;
    temp.cp[1] = 1;
    temp.cp[0] = 3;
    cout << temp.sp << endl;
    return 0;
}

结果:

259		// 0x0103 小端模式

int main(int argc, char *argv[])
{
    int a;
    char b;
    int c;
    short d;
    long int e = 1;
    char *p;

    cout << "int &a =  " << (size_t)&a << endl;//结果1
    cout << "char&b =  " << (size_t)&b << endl;//结果2
    cout << "int &c =  " << (size_t)&c << endl;//结果3
    cout << "short&d = " << (size_t)&d << endl;//结果4
    cout << "long &e = " << (size_t)&e << endl;//结果5
    cout << "char*&p = " << (size_t)&p << endl;//结果6

    char temp[16]={0};
    memcpy(temp, &p, 16);
    cout << (size_t)p << endl;
    for ( int i = 0; i < 16; i++) {
        cout << (int)temp[i] << " ";
    }
    cout << endl;
    return 0;
}

结果:

int &a =  140722993149544
char&b =  140722993149543
int &c =  140722993149536
short&d = 140722993149534
long &e = 140722993149520
char*&p = 140722993149512
4233981
-3 -102 64 0 0 0 0 0 1 0 0 0 0 0 0 0 

分析:
可以看见,局部变量从高地址开始分配,到低地址。

结果1 > 结果2 > 结果3 > 结果4 > 结果5 > 结果6
结果1 - 结果2 = 140722993149544 - 140722993149543 = 1B
	//一个char占一个字节的内存
结果3 + 4B = 140722993149540
	//一个字节的变量必须对齐,填充三个字节
结果5 - 结果6 = 140722993149520 - 140722993149512 = 8B
	/* 
	char *占4个字节,但是内存分配了8个字节;
	我们把内存打印出来:
	4233981
	-3 -102 64 0 0 0 0 0 1 0 0 0 0 0 0 0
	可以看见,指针后面自带了一个字节的空字符
	*/

单个指针和数组名指针有一点不同,那就是
单个指针有一个存储空间,且自带'\0'结束符(如上),它的存储内容和地址不一样的

char *p;
&p != p

数组名指针,它的指向的地址都是在数组首地址

char a[10];
&a == a;

关于数组声明后再内存中的分配问题,作者实验了很久,发现同样的代码,连续几次编译后得到的结果,都是不一样的。
尤其是当有int[]数组时,甚至出现违背第二条内存分配原则,int[]数组总是被分配在最低的地址处。
作者猜测,这应该和编译器优化挂钩的。

虚函数

有虚函数的类里,有一张虚函数表,这张表里是每个虚函数的函数指针。对,它的大小就是所有指针加起来的大小。
这些指针放在类实例地址的低地址,也就是类对象头部。
然后就是各个变量。

派生类

类在内存中结构——虚函数,派生类_第4张图片
如上图,子类实例化后的结构。
他有多少个父类每个父类的大小加起来在加上自身就是sizeof的大小。
话句话说,对于子类,最开始的内存数据记录着父类对象的拷贝(包括父类虚函数表指针和成员变量)。 之后是子类自己的成员变量数据。

你可能感兴趣的:(C++的细节,-,探讨与实践)