面向对象-指针访问的本质
一道题,彻底了解指针间接访问所指向对象的成员变量的本质
首先定义一个类
class Person
{
public:
int m_id;
int m_age;
int m_height;
void display()
{
cout << "m_id=" << m_id << endl;
cout << "m_age=" << m_age << endl;
cout << "m_height=" << m_height << endl;
}
};
下方print结果毋庸置疑
int main(int argc, char **argv)
{
Person person;
Person *p = &person;//定义一个指向对象的指针,可以达到间接访问其成员变量的目的
p->m_id= 10;
p->m_age= 20;
p->m_height= 30;
p->display();
//--------------print-------------------
// m_id=10
// m_age=20
// m_height=30
//--------------print-------------------
getchar();
return 0;
}
如何利用指针间接访问所指向对象的成员变量呢?
- 从指针中取出对象的地址
- 利用对象的地址+ 成员变量在对象内存空间的偏移量 从而计算出成员变量的地址
- 根据成员变量的地址,访问成员变量的存储空间
当对象被创建之后,就会把所有的成员变量放在对象所在的存储空间内,顺序按照代码中的顺序依次排放
这句话非常重要:我们在外部通过指针访问成员变量的表达式p->m_id= 10;其实并不是访问的m_id,而是访问person存储空间中的第一个偏移,恰好,这个偏移是m_id这个变量。
也就是意味着p->m_id这句代码,表达的是p的地址+0偏移所得到的的地址中的内容。(这个0偏移是创建对象时,被自动规定的)
题目出现了:下方代码会打印出什么样的结果,即m_id、m_age、m_height分别是多少??
int main(int argc, char **argv)
{
Person person;
person.m_id = 10;
person.m_age = 20;
person.m_height = 30;
person.display();
//--------------print-------------------
// m_id=10
// m_age=20
// m_height=30
//--------------print-------------------
Person *p1 = (Person *) &person.m_age;
p1->m_id = 40;
p1->m_age = 50;
person.display();
//--------------print-------------------
//m_id=10
//m_age=40
//m_height=50
//--------------print-------------------
getchar();
return 0;
}
解题
我们有了上面的原理铺垫,知道指针间接访问成员变量是靠已经规定好的偏移量,那这个题就可以解答了。
- 首先指针p已经不是对象的首地址了,而是存在对象中的m_age的地址。还要注意的一点就是p->m_id不是指针p指向m_id变量,而是指针p指向偏移量为0的变量(创建对象时,成员变量会存放在对象内存空间,偏移量就是在这时被规定的,后续访问都是访问偏移量,而不是真正的访问变量本身)
- p->m_id就相当于&person.m_age->m_id,也就是m_age的地址+0偏移量,那就是m_age的位置啊,所以此时m_age变成了40;
- p->m_age就相当于&person.m_age->m_age,也就是m_age的地址+4偏移量,那就是m_height的位置啊,所以此时把50赋值给了m_height
- 而m_id没有被赋值,那就是原来的值10
所以结果为:
m_id=10
m_age=40
m_height=50
注意:这种偏移量的访问形式,只出现在面向对象的时候,普通的指针访问,还是访问地址那种
为什么面向对象,会出现偏移量的问题呢?
因为创建对象,会把所有的成员变量连续的放在对象所在的存储空间,所以C++就规定通过对象地址+偏移量的结果访问成员变量,这样的话效率回高一点