C++ 对象模型分析(上)

回归本质

class是一种特殊的struct

  • 在内存中 class 依旧可以看作变量的集合
  • class 与 struct 遵循相同的内存对齐规则
  • class 中的成员函数与成员变量是分开存放的

    • 每个对象有独立的成员变量
    • 所有对象共享类中的成员函数

成员函数也是函数,只要时函数,编译之后就是放在代码段中的

值得思考的问题

class A
{
    int i;
    int j;
    char c;
    double d;
};

sizeof(A) = ?
class B
{
    int i;
    int j;
    char c;
    double d;
};

sizeof(B) = ?

对象内存布局初探

#include <iostream>
#include <string>
#include <math.h>
#include <stdio.h>


using namespace std; 

#pragma pack(4)
class A
{
    int a;
    int b;
    char c;
    double d;
    
public:
    void print()
    {
        cout << "a =" << a << ", "
             << "b =" << b << ", "
             << "c =" << c << ", "
             << "d =" << d << endl;
     }
    
};
#pragma pack()

#pragma pack(4)
struct B
{
    int a;
    int b;
    char c;
    double d;
    
};

#pragma pack()



int main()
{
    
    A a;
    struct B b;
    
    
    printf("sizeof(A) = %lu\n", sizeof(a));
    printf("sizeof(struc B) = %lu\n", sizeof(struct B));
    a.print();
    
    struct B *p = reinterpret_cast<struct B* > (&a);
    
    p->a = 10;
    p->b = 20;
    p->c = 'a';
    p->d = 1.011;
    
    a.print();
    
    
    return 0;
}

对象就是一个特殊的结构体。可以重新解释对象内存,指针修改对象内部的私有成员
struct B *p = reinterpret_cast<struct B* > (&a)

运行时的对象退化为结构体形式

  • 所有程序变量在内存中依次排布
  • 成员变量间可能存在内存空隙
  • 可以通过内存地址直接访问成员变量
  • 访问权限关键字(private),在编译的时候有效,在运行的时候就失效了

问题1

如何调用一个成员函数?
答:
点 操作符。编译器在背后做了一个操作,将一个地址(这个地址就是对象的地址)传递到成员函数内部。

问题2

成员变量和成员函数时在内存中分开存放的,为啥成员函数就可以访问成员变量?
答:
this指针。this 指针只能在成员函数内部使用,代表当前对象,保存了当前对象的地址

  • 类中成员函数位于代码段中
  • 调用成员函数时**对象地址作为参数隐式传递
  • 成员函数通过对象地址访问成员变量
  • C++ 语法规则隐藏了对象地址传递过程

编程实验:对象本质分析

// 50—2.h  
#ifndef __50_2_H__
#define __50_2_H__


typedef void Demo;

Demo *DemoCreate(int i, int j);
int GetI(Demo *pthis);
int GetJ(Demo *pthis);
int AddValue(Demo *pthis, int value);
void DemoFree(Demo *pthis);

#endif


// 50-2.c  

#include <stdio.h>
#include <stdlib.h>

#include "50-2.h" 


struct ClassDemo
{
    int mi;
    int mj;
    
};

Demo  *DemoCreate(int i, int j)
{
    struct ClassDemo *ret = (struct ClassDemo*)malloc(sizeof(struct ClassDemo));
    
    if(ret != NULL)
    {
        ret->mi = i;
        ret->mj = j;        
    }
    
    return ret;
    
}


int GetI(Demo *pthis)
{
    if(pthis != NULL)
    {
        return ((struct ClassDemo*)pthis)->mi;
    }
        
}

int GetJ(Demo *pthis)
{
    if(pthis != NULL)
    {
        return ((struct ClassDemo*)pthis)->mj;
    }    
}

int AddValue(Demo *pthis, int value)
{
    if(pthis != NULL)
    {
        return ((struct ClassDemo*)pthis)->mj + ((struct ClassDemo*)pthis)->mi + value;
    }        
}

void DemoFree(Demo *pthis)
{
    free (pthis);
}

// test.c  
#include <stdio.h>
#include "50-2.h"

int main()
{
     Demo *d = DemoCreate(1, 2);
     printf("%d\n", GetI(d));
     printf("%d\n", GetJ(d));
     printf("%d\n", AddValue(d, 10));
     DemoFree(d);    
}

输出  
1
2
13

小结

  • C++ 中的类对象在内存布局上与结构体相同
  • 成员变量和成员函数在内存中分开存放
  • 访问权限关键字在运行时失效
  • 调用成员函数时对象地址作为参数隐式传递

查子木
4 声望1 粉丝

学习 交流 一起进步