C++面向对象-9-对象模型和this指针

本篇来学习对象模型和this指针,对象模型主要是了解对象的存储模型。在C++中,类内的成员变量和成员函数是分开存储的,只有非静态成员变量才是属于类的对象上,其他都和类存在不同内存区域。

1.一个类的空对象占用内存是多大字节

这里我们先写一个代码,通过sizeof()函数来打印一个空的类对象占用内存是多少字节。

#include <iostream>
using namespace std;

class Person
{


};

void test01()
{
    Person p;
    cout << "空对象P所占内存大小为:" << sizeof(p) << endl;
}

int main()
{
    test01();
   
    system("pause");
    return 0;
}

上面定义了一个Person类,没有写成员变量和成员方法。然后直接初始化一个对象p,那么我们问题就来了,这么一个空的类对象所占用的内存大小是多少?我们可以能会猜测1 或者 0 或者 4等。

因为C++编译器会给每一个空对象分配一个空间,是为了区分位置,每一个对象都有独一无二内存空间,这个空间大小就是1字节。

 

2.一个类只定义一个int类型的变量的内存大小

在上面代码基础之上,添加非静态成员变量 int m_A, 看看这个类对象所占的内存是多少。

#include <iostream>
using namespace std;

class Person
{
    int m_A;

};

void test01()
{
    Person p;
    cout << "空对象P所占内存大小为:" << sizeof(p) << endl;
}

int main()
{
    test01();
   
    system("pause");
    return 0;
}

运行结果就是4字节,因为C++编译器检测到这个类里面定义了一个int类型的变量,所以这个类对象所占内存就是4字节。这个结果,侧面证明了非静态成员对象是属于这个类对象上的

 

3.静态成员变量不属于类对象上

通过下面代码的例子,创建一个静态成员变量,并在类外进行初始化,看看这个对象p的内存是多少。

#include <iostream>
using namespace std;

class Person
{
    int m_A;
    static int m_B;

};

int Person::m_B = 100;

void test01()
{
    Person p;
    cout << "对象P所占内存大小为:" << sizeof(p) << endl;
}

int main()
{
    test01();
   
    system("pause");
    return 0;
}

运行之后

这个结果还是4字节,说明静态成员变量m_B就不在对象p上,证明了静态成员变量和非静态成员变量是存储在不同区域。

 

4.静态成员函数和非静态成员函数也不在类对象上

接下来,我们来证明一个类的非静态成员函数也不属于类上存储。

#include <iostream>
using namespace std;

class Person
{
    int m_A;
    static int m_B;

    void func()
    {
        
    }
};

int Person::m_B = 100;

void test01()
{
    Person p;
    cout << "对象P所占内存大小为:" << sizeof(p) << endl;
}

int main()
{
    test01();
   
    system("pause");
    return 0;
}

运行得到

运行结果依然是4个字节,说明非静态成员函数也不属于类对象上。其实不管非静态函数还是静态函数都不属于类对象上存储。下面新添加一个静态成员函数,再次运行代码看看对象p的内存大小。

#include <iostream>
using namespace std;

class Person
{
    int m_A;
    static int m_B;

    void func()
    {

    }

    static void func2()
    {
        
    }
};

int Person::m_B = 100;

void test01()
{
    Person p;
    cout << "对象P所占内存大小为:" << sizeof(p) << endl;
}

int main()
{
    test01();
   
    system("pause");
    return 0;
}

结论:不管静态成员函数还是非静态成员函数,都不在类对象上存储。那边C++是如何区分不同类对象下调用同一个函数的呢,接下来就要学习this指针来回答这个问题。

 

5.this指针

C++通过this指针来区分很多对象调用同一个函数。this指针指向被调用的成员函数所属的对象,this指针是隐含每一个非静态成员函数的一种指针,this指针不需要定义,直接使用即可。

this指针的作用

  1. 当形参和成员变量同名时,可用this指针来区分。
  2. 在类的非静态成员函数中返回对象本身,可使用return *this

先用一段代码来描述this指针区分形参和成员变量同名的问题。

#include<iostream>
using namespace std;

class Person
{

public:
	
	int age;

	Person(int age)
	{
		age = age;
	}

};


void test01()
{
	Person p(18);
	cout << "p的年龄为:" << p.age << endl;

}

int main()
{
	test01();

	system("pause");
	return 0;
}

运行代码后

根据我们前面学习的知识,难道这里不是调用有参构造,年龄输出18吗?为什么输出这个。

问题就出在这个有参构造,age = age,这个时候类的变量和函数的形式参数名一样,造成C++认为这两个age是一样,并没有把类变量赋值成功。为了解决这个问题,我们可以在定义类变量的时候加上m_age 或者Age,这样来区分。第二种办法,就是使用this指针,下面来看看this指针的代码。

#include<iostream>
using namespace std;

class Person
{

public:
	
	int age;

	Person(int age)
	{
		this->age = age;
	}

};


void test01()
{
	Person p(18);
	cout << "p的年龄为:" << p.age << endl;

}

int main()
{
	test01();

	system("pause");
	return 0;
}

this是一个指针,所以这里是this->来表示。这个时候this表示当前这个被调用函数的所属的对象,也就是代码中的p对象,这句话的理解很关键,上面用红色字体标注出来。

 

使用return *this返回对象本身

有时候我们需要返回对象本身,特别是一些在链式编程的语法上。来看看下面代码。

#include<iostream>
using namespace std;

class Person
{

public:
	
	int age;

	Person(int age)
	{
		this->age = age;
	}

	//解引用的方式做一个返回
	Person& personAddAge(Person &p)
	{
		this->age += p.age;
		return *this;
	}

};

void test01()
{
	Person p1(10);
	Person p2(10);

	p2.personAddAge(p1).personAddAge(p1).personAddAge(p1);
	cout << "p2的年龄为:" << p2.age << endl;

}

int main()
{
	test01();

	system("pause");
	return 0;
}

运行结果就是40,这个不断后面调用方法就是链式编程的特点。注意上面返回的是一个解引用,并不是一个值,如果代码修改返回值,运行结果是什么呢?

#include<iostream>
using namespace std;

class Person
{

public:
	
	int age;

	Person(int age)
	{
		this->age = age;
	}

	//返回值
	Person personAddAge(Person &p)
	{
		this->age += p.age;
		return *this;
	}

};

void test01()
{
	Person p1(10);
	Person p2(10);

	p2.personAddAge(p1).personAddAge(p1).personAddAge(p1);
	cout << "p2的年龄为:" << p2.age << endl;

}

int main()
{
    test01();

	system("pause");
	return 0;
}

运行结果是20,也就是调用PersopnAddAge一次的效果。

第一次调用,age=20,这个时候需要返回p2的一个值,这个值和p2不是同一个,如果是引用就是同一个,值就是调用拷贝构造函数,新的对象默认age等于0,所以后面执行多次还是等于20.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值