首页 > 代码库 > 第五十课、c++对象模型分析(上)

第五十课、c++对象模型分析(上)

一、c++对象模型之成员变量

1、class是一种特殊的struct

(1)、在内存中class依旧可以看做是变量的集合

(2)、class与struct遵循相同的内存对齐规则

(3)、class中的成员函数和成员变量是分开存储

A、每个对象有独立的成员变量

B、所有对象共享类中的成员函数

 

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

(1)、所有成员变量在内存中依次分布

(2)、成员变量间可能存在内存间隙

(3)、可以通过内存地址直接访问成员变量

(4)、访问权限关键字在运行时失效

#include<iostream>

using namespace std;

class A
{
private:
    int i;
    int j;
    char c;
    double d;
public:
    void print()//保存在代码段中
    {
        cout << "i = " << i << ","
             << "j = " << j << ","
             << "c = " << c << ","
             << "d = " << d << endl;     
    }
};

struct B
{
    int i;
    int j;
    char c;
    double d;
};
int main()
{
    A a;

    cout << "sizeof(A) = " << sizeof(A) << endl;//4+4+4+8=20
    cout << "sizeof(a) = " << sizeof(a) << endl;//20
    cout << "sizeof(B) = " << sizeof(B) << endl;//20
    a.print();

    B *p = reinterpret_cast<B*>(&a);//强制转换成结构体,重新解释这片内存空间
    p->i = 10;
    p->j = 20;
    p->c = a;
    p->d = 3.15;//成功改变private的值,说明private只在编译期起作用,运行时失效
    
    a.print();

    return 0;
}

//输出结果
/*
sizeof(A) = 20
sizeof(a) = 20
sizeof(B) = 20
i = -1075365380,j = -1219354059,c = p,d = 4.85915e-270
i = 10,j = 20,c = a,d = 3.15
*/

二、c++的对象模型之成员函数

1、类中的成员函数位于代码段中

2、调用成员函数时对象地址作为参数隐式传递this指针保存了对象的地址,所以即使成员函数和成员变量分开存储,成员函数也可以通过对象的地址访问成员变量

3、成员函数通过对象地址访问成员变量

4、c++语法规则隐藏了对象地址的传递过程

#include <iostream>
#include <string>

using namespace std;

class Demo
{
    int mi;
    int mj;
public:
    Demo(int i, int j)
    {
        mi = i;
        mj = j;
    }
    
    int getI()
    {
        return mi;
    }
    
    int getJ()
    {
        return mj;
    }
    
    int add(int value)
    {
        return mi + mj + value;
    }
};

int main()
{
    Demo d(1, 2);
    
    cout << "sizeof(d) = " << sizeof(d) << endl;//8
    cout << "d.getI() = " << d.getI() << endl;//1
    cout << "d.getJ() = " << d.getJ() << endl;//2
    cout << "d.add(3) = " << d.add(3) << endl;//6
    
    return 0;
}

用C语言来模拟从而探寻对象的本质:实际上就是函数与变量分开,变量在类中

//add.h:

#ifndef _ADD_H_
#define _ADD_H_

typedef void Demo;
Demo* Demo_create(int i, int j);//构造函数,返回的返回值是void*的原因是为了数据隐藏,外界无法访问,内部需要访问时再进行强制类型转换回来即可
int Demo_GetI(Demo* pThis);//C语言不像c++会隐式传递对象指针,所以调用成员函数时要显示传递对象地址
int Demo_GetJ(Demo* pThis);
int Demo_add(Demo* pThis, int value);
void Demo_free(Demo* pThis);//析构函数

#endif

//add.c

#include"add.h"
#include<malloc.h>

struct ClassDemo//定义一个类
{
    int mi;
    int mj;
};

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

    return ret;
}

int Demo_GetI(Demo* pThis)
{
    struct ClassDemo* ret = (struct ClassDemo *)(pThis);
    
    return ret->mi;
}

int Demo_GetJ(Demo* pThis)
{
    struct ClassDemo* ret = (struct ClassDemo *)(pThis);

    return ret->mj;
}

int Demo_add(Demo* pThis, int value)
{
    struct ClassDemo* ret = (struct ClassDemo *)(pThis);

    return (ret->mi + ret->mj + value);
}

void Demo_free(Demo* pThis)
{
    free(pThis);
}

//main.c

#include<stdio.h>
#include<malloc.h>
#include"add.h"

int main()
{
    Demo* d = Demo_create(1, 2);//相当于c++的 Demo* d = new Demo(1, 2)

    printf("Demo_GetI(d) = %d\n", Demo_GetI(d));//1, 相当于d->GetI();
    printf("Demo_GetJ(d) = %d\n", Demo_GetJ(d));//2
    printf("Demo_add(d,3) = %d\n", Demo_add(d, 3));//6


  //d->mi = 100;//无法访问, d再这里是void*型的,不是类类型,需要在类实现那里进行强制类型转换,所以这里很好达到了封装的目的 Demo_free(d); return 0; }

三、小结

1、c++中的类对象在内存布局上与结构体相同

2、成员变量和成员函数在内存中分开存放(本质)

4、访问权限关键字在运行时失效

3、调用成员函数时对象地址作为参数隐式传递

 

 

 

第五十课、c++对象模型分析(上)