【C++漂流记】C++对象模型和this指针

发布时间:2023年12月18日

C++中对象模型和this指针是面向对象编程中的重要概念。对象模型描述了对象在内存中的布局和行为,包括成员变量和成员函数的存储方式和访问权限。this指针是一个隐含的指针,指向当前对象的地址,用于在成员函数中引用当前对象的成员变量和成员函数。对象模型和this指针的理解和应用,对于深入理解C++的面向对象特性和实现细节至关重要。
在这里插入图片描述



1. 成员变量和成员函数分开存储

在C++中,类内的成员变量和成员函数分开存储

只有非静态成员变量才属于类的对象上

class Person {
public:
	Person() {
		mA = 0;
	}
	//非静态成员变量占对象空间
	int mA;
	//静态成员变量不占对象空间
	static int mB; 
	//函数也不占对象空间,所有函数共享一个函数实例
	void func() {
		cout << "mA:" << this->mA << endl;
	}
	//静态成员函数也不占对象空间
	static void sfunc() {
	}
};

int main() {

	cout << sizeof(Person) << endl;

	system("pause");

	return 0;
}

上面的代码定义了一个名为Person的类。Person类有一个默认构造函数,用于初始化非静态成员变量mA为0。Person类还有一个非静态成员变量mA和一个静态成员变量mB。静态成员变量mB不占用对象的空间,而是在全局数据区分配内存。Person类还有一个成员函数func(),用于输出非静态成员变量mA的值。成员函数也不占用对象的空间,所有对象共享一个函数实例。Person类还有一个静态成员函数sfunc(),也不占用对象的空间。在main函数中,使用sizeof运算符输出Person类的大小。最后调用system("pause")暂停程序的执行,返回0表示程序正常结束。


2. this指针概念

通过前面我们知道在C++中成员变量和成员函数是分开存储的

每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码

那么问题是:这一块代码是如何区分那个对象调用自己的呢?

c++通过提供特殊的对象指针,this指针,解决上述问题。this指针指向被调用的成员函数所属的对象

this指针是隐含每一个非静态成员函数内的一种指针

this指针不需要定义,直接使用即可

this指针的用途:

  • 当形参和成员变量同名时,可用this指针来区分
  • 在类的非静态成员函数中返回对象本身,可使用return *this
class Person
{
public:

	Person(int age)
	{
		//1、当形参和成员变量同名时,可用this指针来区分
		this->age = age;
	}

	Person& PersonAddPerson(Person p)
	{
		this->age += p.age;
		//返回对象本身
		return *this;
	}

	int age;
};

void test01()
{
	Person p1(10);
	cout << "p1.age = " << p1.age << endl;

	Person p2(10);
	p2.PersonAddPerson(p1).PersonAddPerson(p1).PersonAddPerson(p1);
	cout << "p2.age = " << p2.age << endl;
}

int main() {

	test01();

	system("pause");

	return 0;
}

这段代码定义了一个Person类,其中包含一个构造函数和一个成员函数PersonAddPersontest01函数创建了两个Person对象p1p2,并测试了PersonAddPerson函数的功能。

在构造函数中,使用了this指针来区分形参和成员变量。this指针指向当前对象,可以通过this->age来访问成员变量age

PersonAddPerson函数接受一个Person对象作为参数,将该对象的age加到当前对象的age上,并返回当前对象的引用。

test01函数中,首先创建了一个age为10的Person对象p1,并输出其age值。然后创建了另一个age为10的Person对象p2,并连续三次调用PersonAddPerson函数,每次传入p1作为参数。最后输出p2age值。

由于PersonAddPerson函数返回的是当前对象的引用,所以可以连续调用该函数。因此,p2age值会依次增加30,最终输出为40。


3. 空指针访问成员函数

C++中空指针也是可以调用成员函数的,但是也要注意有没有用到this指针

如果用到this指针,需要加以判断保证代码的健壮性

示例:

//空指针访问成员函数
class Person {
public:

	void ShowClassName() {
		cout << "我是Person类!" << endl;
	}

	void ShowPerson() {
		if (this == NULL) {
			return;
		}
		cout << mAge << endl;
	}

public:
	int mAge;
};

void test01()
{
	Person * p = NULL;
	p->ShowClassName(); //空指针,可以调用成员函数
	p->ShowPerson();  //但是如果成员函数中用到了this指针,就不可以了
}

int main() {

	test01();

	system("pause");

	return 0;
}

这段代码定义了一个Person类,其中包含两个成员函数ShowClassNameShowPerson,以及一个成员变量mAgetest01函数创建了一个空指针p,并尝试调用p的成员函数。

在C++中,空指针是指向任何对象的指针,因此可以通过空指针调用成员函数。在ShowClassName函数中,没有使用this指针,所以可以正常调用,输出结果为"我是Person类!"。

但是在ShowPerson函数中,使用了this指针来访问成员变量mAge。当空指针调用该函数时,this指针为NULL,因此访问成员变量时会出现错误。为了避免空指针访问,可以在函数体内通过判断this是否为NULL来提前返回,不执行后续代码。

总结:空指针可以调用成员函数,但是如果成员函数中使用了this指针来访问成员变量,需要注意空指针的处理,避免出现错误。


4. const修饰成员函数

常函数:

  • 成员函数后加const后我们称为这个函数为常函数
  • 常函数内不可以修改成员属性
  • 成员属性声明时加关键字mutable后,在常函数中依然可以修改

常对象:

  • 声明对象前加const称该对象为常对象
  • 常对象只能调用常函数

示例:

class Person {
public:
	Person() {
		m_A = 0;
		m_B = 0;
	}

	//this指针的本质是一个指针常量,指针的指向不可修改
	//如果想让指针指向的值也不可以修改,需要声明常函数
	void ShowPerson() const {
		//const Type* const pointer;
		//this = NULL; //不能修改指针的指向 Person* const this;
		//this->mA = 100; //但是this指针指向的对象的数据是可以修改的

		//const修饰成员函数,表示指针指向的内存空间的数据不能修改,除了mutable修饰的变量
		this->m_B = 100;
	}

	void MyFunc() const {
		//mA = 10000;
	}

public:
	int m_A;
	mutable int m_B; //可修改 可变的
};


//const修饰对象  常对象
void test01() {

	const Person person; //常量对象  
	cout << person.m_A << endl;
	//person.mA = 100; //常对象不能修改成员变量的值,但是可以访问
	person.m_B = 100; //但是常对象可以修改mutable修饰成员变量

	//常对象访问成员函数
	person.MyFunc(); //常对象不能调用const的函数

}

int main() {

	test01();

	system("pause");

	return 0;
}

这段代码定义了一个名为Person的类。Person类有一个默认构造函数,用于初始化成员变量m_Am_B为0。Person类还有一个成员函数ShowPerson(),使用const修饰,表示该函数是一个常函数。常函数中的this指针是一个指针常量,指针的指向不可修改。但是,常函数可以修改this指针指向的对象的mutable修饰的成员变量m_B的值。Person类还有一个成员函数MyFunc(),同样使用const修饰,但该函数尝试修改成员变量m_A的值,因此会导致编译错误。

main函数中,定义了一个常量对象person,使用const修饰。常量对象不能修改成员变量的值,但可以访问成员变量的值。常量对象可以修改mutable修饰的成员变量m_B的值。常量对象也可以调用常函数ShowPerson(),但无法调用MyFunc()

最后调用system("pause")暂停程序的执行,返回0表示程序正常结束。

文章来源:https://blog.csdn.net/Goforyouqp/article/details/133470535
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。