C++ 对象地址解析

C++中,实例化一个对象,表示请求编译器分配一块固定大小的内存,大小为sizeof(object),那么问题来了,这个对象的地址&object是什么呢?

以下从6个方面考虑对象地址,测试环境:gcc编译器

1、普通类class中包含了成员函数和成员变量,对象object的地址即为该对象内所包含的第一个字段的地址。
    这个没啥好说的,类似于数组地址与数组首元素地址、结构体变量的地址与其第一个字段的地址。

#include <iostream>
#include <string>
using namespace std;

class Person
{
public:
        Person(string Name = "Tom", int Age = 10)  /*缺省的default ctor*/
        :name(Name),age(Age)
        {}

        void getAddr() const
        {
                cout << "object's this  addr: " << this << endl;
                cout << "object's first elem: " << &(this->name) << endl;
        }
		
private:
        string name;
        int age;
};

int main()
{
        Person p;
        cout << "The object addr:     " << &p << endl;
        p.getAddr();
        
        //cout << "hello...\n";
        return 0;
}

    执行结果: 对象p的地址就是对象p内首个字段name的地址。

XXX:~/Exercise$ g++ objectAddr.cpp 
XXX:~/Exercise$ ./a.out 
The object addr    : 0x7fffe857ac40
object's this  addr: 0x7fffe857ac40
object's first elem: 0x7fffe857ac40

2、那若是类class为空呢,类中什么都没有,那么一个空的类实例化一个对象object,此时对象大小等于几?它的地址又是什么呢?
    逻辑上对象的大小等于0,但实际情况下它等于1,因为C++裁定凡是独立对象必须有非零大小,既然有大小就说明编译器分配了内存,有了内存肯定就有地址啦,如下:

#include <iostream>
#include <string>
using namespace std;

class Student
{};

int main()
{
        Student s;
        cout << "The object size    : " << sizeof(s) << endl; /* sizeof(Student)也等于1 */
        cout << "The object addr    : " << &s << endl;

        return 0;
}

    执行结果:可以看到对象s大小为1,这是因为编译器为空对象内强行安插了一个char,所以s大小为1,(《Effective C++》条例39),而对象地址应该就是这个char的地址。

XXX:~/Exercise$ g++ objectAddr.cpp 
XXX:~/Exercise$ ./a.out
The object size    : 1
The object addr    : 0x7ffd7e04dbbf

3、若一个类中包含了virtual虚函数,那么具现出一个实体object的地址是什么呢,此时应该是虚指针vptr的地址。
    带有虚函数的类中,编译期间,在每一个class object中,一个额外的虚指针vptr会被编译器合成出来放在对象的开头,内含相关虚表vtbl的地址。

#include <iostream>
#include <string>
using namespace std;

class Person
{
public:
        Person(string Name = "Tom", int Age = 10)
        :name(Name),age(Age)
        {}

        virtual ~Person() {}

        void getAddr() const
        {
                cout << "object's this  addr: " << this << endl;
                cout << "object's first elem: " << &(this->name) << endl;
                cout << "object's second elem:" << &(this->age) << endl;
        }
        
private:
        string name;
        int age;
};

int main()
{
        Person p;
        cout << "The object addr    : " << &p << endl;
        p.getAddr();
        
        //cout << "hello...\n";
        return 0;
}

    执行结果:可以看出对象p的地址与p内首个字段name的地址不一样了,&p是对象内虚指针的地址,该地址向后偏移才是首个字段name的地址。(参考《Inside The C++ Object Model》)
 

XXX:~/Exercise$ g++ objectAddr.cpp 
XXX:~/Exercise$ ./a.out
The object addr    : 0x7fffddf9e860
object's this  addr: 0x7fffddf9e860
object's first elem: 0x7fffddf9e868
object's second elem:0x7fffddf9e870

    这里第一个字段name的地址与第二个字段age的地址相差8,为什么呢?因为string内有一根指针,在gcc编译器中,指针占8个字节。


4、若是在继承体系中,一个派生类对象的地址会是什么?
    派生类对象object的组成包含了基类的成员变量和派生类自己新增的成员变量,该对象的地址是派生类对象中所包含的基类成员中的首个字段的地址,而不是派生类自己新增的第一个字段成员的地址。

#include <iostream>
#include <string>
using namespace std;

class Person
{
public:
        Person(string Name = "Tom", int Age = 10)
        :name(Name),age(Age)
        {}

protected:
        string name;
        int age;
};

class Student : public Person
{
public:
        Student(string Name = "Tom", int Age = 10, int Grade = 100)
        :Person(Name,Age),grade(Grade)
        {}

        void getAddr() const
        {
                cout << "object's this  addr: " << this << endl;
                cout << "object's first elem: " << &(this->name) << endl;
                cout << "object's second elem:" << &(this->age) << endl;
                cout << "object's third elem: " << &(this->grade) << endl;
        }

private:
        int grade;
};

int main()
{
        Student s;
        cout << "The object addr    : " << &s << endl;
        s.getAddr();
        
        //cout << "hello...\n";
        return 0;
}

    执行结果:对象s的地址即为对象s中首个字段name的地址,这里注意新增字段grade的地址,可以看出三个成员变量所占内存是连续的,但在一个对象中,继承自基类的部分和派生类自定义的部分不一定是连续存储的。(《C++ Primer》15.2.2)

XXX:~/Exercise$ g++ objectAddr.cpp 
XXX:~/Exercise$ ./a.out
The object addr    : 0x7ffe6b3f5be0
object's this  addr: 0x7ffe6b3f5be0
object's first elem: 0x7ffe6b3f5be0
object's second elem:0x7ffe6b3f5be8
object's third elem: 0x7ffe6b3f5bec

5、若在继承体系中加入了虚函数,派生类对象的地址又是什么?
    该地址是派生类对象object虚指针vptr的地址。

#include <iostream>
#include <string>
using namespace std;

class Person
{
public:
        Person(string Name = "Tom", int Age = 10)
        :name(Name),age(Age)
        {}

        virtual ~Person() {}

protected:
        string name;
        int age;
};

class Student : public Person
{
public:
        Student(string Name = "Tom", int Age = 10, int Grade = 100)
        :Person(Name,Age),grade(Grade)
        {}

        virtual ~Student() {}

        void getAddr() const
        {
                cout << "object's this  addr: " << this << endl;
                cout << "object's first elem: " << &(this->name) << endl;
                cout << "object's second elem:" << &(this->age) << endl;
                cout << "object's third elem: " << &(this->grade) << endl;
        }

private:
        int grade;
};

int main()
{
        Student s;
        cout << "The object addr    : " << &s << endl;
        s.getAddr();
        
        //cout << "hello...\n";
        return 0;
}    

    执行结果:此时对象s的地址是虚指针vptr的地址,与第三个差不多,但是这个虚指针vptr是派生类对象自己的,而不属于派生类对象包含的基类成员的那部分,
    若是具现一个Person实体 Person p; 这里p的地址才是基类对象自己的专属的虚指针的地址,多态性的体现正是靠这根虚指针vptr。
        用一句话表示多态性: (*(this->vptr)[n])(this)

XXX:~/Exercise$ g++ objectAddr.cpp 
XXX:~/Exercise$ ./a.out
The object addr    : 0x7ffe61d5fbd0
object's this  addr: 0x7ffe61d5fbd0
object's first elem: 0x7ffe61d5fbd8
object's second elem:0x7ffe61d5fbe0
object's third elem: 0x7ffe61d5fbe4

6、继承抽象基类的派生对象地址?
    这个地址肯定就是派生类对象object自己的虚指针vptr的地址,因抽象基类不可具现实体。

7、若类中包含静态成员变量,该静态成员变量是属于类的,其存储在进程空间中的全局区,由该类的所有对象共享,静态成员变量不存储在对象本身占用的空间内。

注:对象内存大小组成如下:

(1)基本字段(成员变量);

(2)对齐;

(3)由vritual带来的额外的负担,例如虚指针vptr。

若有说错的,请走过路过的大佬们给个建议,谢谢。

  • 10
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值