类成员空间布局

一.类的数据成员绑定时机

a.研究成员函数的返回值

string myvar;//全局变量,字符串型

class A
{
public:
    int myfunc()
    {
        cout << ::myvar.c_str() << endl;//全局变量;
        cout << myvar << endl;// 成员函数;
        return  myvar;//int类型的;
    }
    int myfunc2();
private:
    int myvar; //同全局变量名相同,但类型不同;
};
int A::myfunc2()
{
    return myvar;// int类型
}
string func()
{
    cout << myvar << endl;//string类型的;
    return myvar;//string类型;
}

编译器对成员函数myfunc的解析,是在整个类A定义完毕之后才开始的。当在内类找不到才会去类外找;所以无论是myfunc()还是myfunc2()这个成员函数的返回类型都是我们在类内定义的int型的myvar;类外的普通全局函数的返回类型也自然是在类外定义的string类型的myvar。

b.研究成员函数的参数问题

typedef string mytype;// 定义mytype为string类型

class B
{
public:
    void myfunc(mytype temp)//string
    {
        //m_value = temp;// int=string 肯定报错;
    }
    void myfunc1(mytype t);// string 
private:
    mytype a;// string
    typedef int mytype; //定义mytype为int类型;
    mytype m_value; // int
};
void B::myfunc1(mytype t)//在类外写成员函数的时候 mytype被认为是int类型;这里会报错,
{
    m_value = t;
}
void myfunc(mytype tmpvalue)
{
    string m_value = tmpvalue;
}

对于成员函数的参数,是在编译器最近一次确定mytype类型的时候被决定的,

如果类内有typedef这种定义的话,放在类的最开头位置,让类成员可以尽早的看见;

二.进程内存空间布局(不同的数据在内存中会有不同的保存位置)

class  A
{
public:
    int m_i;
    static int m_si;// 声明,编译器并不会分配空间;
    int m_j;
    static int m_sj;
    int m_k;
    static int m_sk;
};
int A::m_si = 0;
int A::m_sj = 0;
int A::m_sk = 0;
int main()
{
    A a;                                //         栈。
    cout << sizeof(a) << endl;
    
    printf("m_i的地址=%p\n", &a.m_i);//003C FA58    栈。
    printf("m_j的地址=%p\n", &a.m_j);//003C FA5C
    printf("m_k的地址=%p\n", &a.m_k);//003C FA60
    // 普通成员变量的储存顺序,是按照在类中定义顺序从上到下来的;
    // 比较晚出现的变量在内存中有更高的地址;

    printf("m_si的地址=%p\n", &a.m_si);//00C0 A3D0 在编译的时候就确定下来了;
    printf("m_sj的地址=%p\n", &a.m_sj);//00C0 A3D4   数据段
    printf("m_sk的地址=%p\n", &a.m_sk);//00C0 A3D8

    A* p = new A();
    printf("p的地址=%p\n", &p);//003 CFA4C          栈。

    printf("m_i的地址=%p\n", &p->m_i);//0087 FC40   堆。
    printf("m_j的地址=%p\n", &p->m_j);//0087 FC44
    printf("m_k的地址=%p\n", &p->m_k);//0087 FC48

    printf("m_si的地址=%p\n", &p->m_si);//00C0 A3D0   数据段
    printf("m_sj的地址=%p\n", &p->m_sj);//00C0 A3D4
    printf("m_sk的地址=%p\n", &p->m_sk);//00C0 A3D8

    return 0;
}

三.边界调整(内存对齐)

class  A
{
public:
    int m_i;
    int m_j;
    int m_k;
    char c;
};
int main()
{
    cout<<sizeof(A) << endl;//,内存四字节对齐,结果为16
    return 0;
}
#pragma pack(1) // 设置为1字节对齐;
class  A
{
public:
    int m_i;
    int m_j;
    int m_k;
    char c;
};
#pragma pack() //回复原来的字节对齐;

int main()
{
    cout<<sizeof(A) << endl; // 内存不对齐,结果为13;
    return 0;
}

四.成员偏移量值的打印

#define GET(A,m) (int)(&((A*)0)->m)
class  A
{
public:
    int m_i;
    int m_j;
    int m_k;
    char c;
    void printf1()// 方法1;
    {
        cout << "打印成员变量偏移量-------" << endl;
        printf("m_i=%p\n", &A::m_i);
        printf("m_j=%p\n", &A::m_j);
        printf("m_k=%p\n", &A::m_k);
        printf("c=%p\n", &A::c);
    }
    
    void printf2()// 方法2;
    {
        cout << "打印成员变量偏移量-------" << endl;
        cout << GET(A, m_i) << endl;
        cout << GET(A, m_j) << endl;
        cout << GET(A, m_k) << endl;
        cout << GET(A, c) << endl;
    }
    virtual void func() {}// 在所有成员变量的最前面增加了一个虚函数表指针;
};
int main()
{
    A a;
    a.printf1();
    a.printf2();

    // 方法3:
    // 成员变量指针:
    int A::* p = &A::m_i;
    printf("m_i的偏移量=%d\n", p);
    
    return 0;
}

我的内容可能写的比较潦草,如果需要笔记内容相对应的课程,请关注并私信我。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值