C++中类的内存偏移量问题

时间:2023-01-11 22:44:14
在程序员面试宝典上有这么一道题:

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

class A
{
public:
A(){m_a = 1; m_b = 2;}
~A(){};
void fun(){printf("%d%d",m_a,m_b);}
public:
int m_a;
int m_b;
};

class B
{
public:
B(){m_c = 3;}
~B();
void fun(){printf("%d",m_c);}
public:
int m_c;
};

int tmain(void)
{
        A a;
        B *pb = (B*)(&a);
        cout << &a << endl;            //0x22ff58
        cout << &(a.m_a) << endl;      //print the address of the a.m_a 0x22ff58
printf("%p\n",&A::m_a);        //print the offset from m_a to the beginning A object
                                       //address 00000000
printf("%p\n",&A::m_b);        //print the offset from m_a to the beginning A object
                                       //address 00000004
printf("%p\n",&B::m_cn);       //print the offset from m_c to the beginning B object
                                       //address 00000000
system("PAUSE");
return 0;
}

我的问题是:
(1)为什么内存的偏移是从成员变量开始?成员函数放在哪了呢?比如printf("%p\n",&A::fun);输出的是个
很大的偏移量,为什么?
(2)类在内存中具体是怎么保存的?

7 个解决方案

#1


引用 楼主 iverain 的回复:
在程序员面试宝典上有这么一道题:

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

class A
{
public:
A(){m_a = 1; m_b = 2;}
~A(){};
void fun(){printf("%d%d",m_a,m_b);}
public:
int m_a;
int m_b;
};

class B
{
public:
B(){m_c = 3;}
~B();
void fun(){printf("%d",m_c);}
public:
int m_c;
};

int tmain(void)
{
        A a;
        B *pb = (B*)(&a);
        cout << &a << endl;            //0x22ff58
        cout << &(a.m_a) << endl;      //print the address of the a.m_a 0x22ff58
printf("%p\n",&A::m_a);        //print the offset from m_a to the beginning A object
                                       //address 00000000
printf("%p\n",&A::m_b);        //print the offset from m_a to the beginning A object
                                       //address 00000004
printf("%p\n",&B::m_cn);       //print the offset from m_c to the beginning B object
                                       //address 00000000
system("PAUSE");
return 0;
}

我的问题是:
(1)为什么内存的偏移是从成员变量开始?成员函数放在哪了呢?比如printf("%p\n",&A::fun);输出的是个
很大的偏移量,为什么?
(2)类在内存中具体是怎么保存的?


成员函数不是类中的数据,只是一种编译约束;事实上编译后,类只是一组数据,而没有任何成员函数的,类成员函数和普通非类的成员函数是一样的只是一组程序代码,和普通非类函数不同的是,类非静态成员函数会隐含的传递this指针,程序代码使用this指针使用类数据而已,程序代码存放于程序区;

如果按照你的想法,那定义100个类对象,岂不是要要100组类代码了?

类中存放的是数据成员+虚表指针(可能没有,也可能一个或多个)

#2


太谢谢了,讲的十分清楚!
还有个问题,你说的有多个虚表指针的情况,是一个类中有多个虚函数吗?那在类对象的前面就是要相应的加这么多虚指针吗?

#3


引用 1 楼 worldy 的回复:
Quote: 引用 楼主 iverain 的回复:

在程序员面试宝典上有这么一道题:

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

class A
{
public:
A(){m_a = 1; m_b = 2;}
~A(){};
void fun(){printf("%d%d",m_a,m_b);}
public:
int m_a;
int m_b;
};

class B
{
public:
B(){m_c = 3;}
~B();
void fun(){printf("%d",m_c);}
public:
int m_c;
};

int tmain(void)
{
        A a;
        B *pb = (B*)(&a);
        cout << &a << endl;            //0x22ff58
        cout << &(a.m_a) << endl;      //print the address of the a.m_a 0x22ff58
printf("%p\n",&A::m_a);        //print the offset from m_a to the beginning A object
                                       //address 00000000
printf("%p\n",&A::m_b);        //print the offset from m_a to the beginning A object
                                       //address 00000004
printf("%p\n",&B::m_cn);       //print the offset from m_c to the beginning B object
                                       //address 00000000
system("PAUSE");
return 0;
}

我的问题是:
(1)为什么内存的偏移是从成员变量开始?成员函数放在哪了呢?比如printf("%p\n",&A::fun);输出的是个
很大的偏移量,为什么?
(2)类在内存中具体是怎么保存的?


成员函数不是类中的数据,只是一种编译约束;事实上编译后,类只是一组数据,而没有任何成员函数的,类成员函数和普通非类的成员函数是一样的只是一组程序代码,和普通非类函数不同的是,类非静态成员函数会隐含的传递this指针,程序代码使用this指针使用类数据而已,程序代码存放于程序区;

如果按照你的想法,那定义100个类对象,岂不是要要100组类代码了?

类中存放的是数据成员+虚表指针(可能没有,也可能一个或多个)





太谢谢了,讲的十分清楚!
还有个问题,你说的有多个虚表指针的情况,是一个类中有多个虚函数吗?那在类对象的前面就是要相应的加这么多虚指针吗?

#4


如果没有虚函数, class的内存和c中的struct一样的, 成员函数只是给编译器看的, 在空间上和普通函数没什么区别.
如果有虚函数, 在class的开头会多一个虚表指针, 这个指针指向的区域保存着每一个虚成员函数的地址

#5


去看一下我的博客,刚转了一篇虚表的文章,讲的很清楚

#6


《深度探索C++对象模型》
《C++反汇编与逆向分析技术揭秘》

#7


学习了,赞一个 C++中类的内存偏移量问题

#1


引用 楼主 iverain 的回复:
在程序员面试宝典上有这么一道题:

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

class A
{
public:
A(){m_a = 1; m_b = 2;}
~A(){};
void fun(){printf("%d%d",m_a,m_b);}
public:
int m_a;
int m_b;
};

class B
{
public:
B(){m_c = 3;}
~B();
void fun(){printf("%d",m_c);}
public:
int m_c;
};

int tmain(void)
{
        A a;
        B *pb = (B*)(&a);
        cout << &a << endl;            //0x22ff58
        cout << &(a.m_a) << endl;      //print the address of the a.m_a 0x22ff58
printf("%p\n",&A::m_a);        //print the offset from m_a to the beginning A object
                                       //address 00000000
printf("%p\n",&A::m_b);        //print the offset from m_a to the beginning A object
                                       //address 00000004
printf("%p\n",&B::m_cn);       //print the offset from m_c to the beginning B object
                                       //address 00000000
system("PAUSE");
return 0;
}

我的问题是:
(1)为什么内存的偏移是从成员变量开始?成员函数放在哪了呢?比如printf("%p\n",&A::fun);输出的是个
很大的偏移量,为什么?
(2)类在内存中具体是怎么保存的?


成员函数不是类中的数据,只是一种编译约束;事实上编译后,类只是一组数据,而没有任何成员函数的,类成员函数和普通非类的成员函数是一样的只是一组程序代码,和普通非类函数不同的是,类非静态成员函数会隐含的传递this指针,程序代码使用this指针使用类数据而已,程序代码存放于程序区;

如果按照你的想法,那定义100个类对象,岂不是要要100组类代码了?

类中存放的是数据成员+虚表指针(可能没有,也可能一个或多个)

#2


太谢谢了,讲的十分清楚!
还有个问题,你说的有多个虚表指针的情况,是一个类中有多个虚函数吗?那在类对象的前面就是要相应的加这么多虚指针吗?

#3


引用 1 楼 worldy 的回复:
Quote: 引用 楼主 iverain 的回复:

在程序员面试宝典上有这么一道题:

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

class A
{
public:
A(){m_a = 1; m_b = 2;}
~A(){};
void fun(){printf("%d%d",m_a,m_b);}
public:
int m_a;
int m_b;
};

class B
{
public:
B(){m_c = 3;}
~B();
void fun(){printf("%d",m_c);}
public:
int m_c;
};

int tmain(void)
{
        A a;
        B *pb = (B*)(&a);
        cout << &a << endl;            //0x22ff58
        cout << &(a.m_a) << endl;      //print the address of the a.m_a 0x22ff58
printf("%p\n",&A::m_a);        //print the offset from m_a to the beginning A object
                                       //address 00000000
printf("%p\n",&A::m_b);        //print the offset from m_a to the beginning A object
                                       //address 00000004
printf("%p\n",&B::m_cn);       //print the offset from m_c to the beginning B object
                                       //address 00000000
system("PAUSE");
return 0;
}

我的问题是:
(1)为什么内存的偏移是从成员变量开始?成员函数放在哪了呢?比如printf("%p\n",&A::fun);输出的是个
很大的偏移量,为什么?
(2)类在内存中具体是怎么保存的?


成员函数不是类中的数据,只是一种编译约束;事实上编译后,类只是一组数据,而没有任何成员函数的,类成员函数和普通非类的成员函数是一样的只是一组程序代码,和普通非类函数不同的是,类非静态成员函数会隐含的传递this指针,程序代码使用this指针使用类数据而已,程序代码存放于程序区;

如果按照你的想法,那定义100个类对象,岂不是要要100组类代码了?

类中存放的是数据成员+虚表指针(可能没有,也可能一个或多个)





太谢谢了,讲的十分清楚!
还有个问题,你说的有多个虚表指针的情况,是一个类中有多个虚函数吗?那在类对象的前面就是要相应的加这么多虚指针吗?

#4


如果没有虚函数, class的内存和c中的struct一样的, 成员函数只是给编译器看的, 在空间上和普通函数没什么区别.
如果有虚函数, 在class的开头会多一个虚表指针, 这个指针指向的区域保存着每一个虚成员函数的地址

#5


去看一下我的博客,刚转了一篇虚表的文章,讲的很清楚

#6


《深度探索C++对象模型》
《C++反汇编与逆向分析技术揭秘》

#7


学习了,赞一个 C++中类的内存偏移量问题