C++学习笔记15-类和对象-C++对象模型和this指针

2023年7月14日11:09:25

15.1 成员变量和成员函数分开存储

在C++中:

  • 类内的成员变量和成员函数分开存储。
  • 只有非静态成员变量才属于类的对象上。
  • 类对象的存储方式为字节对齐,总大小为类中最宽基本类型成员大小×非静态成员变量数量。

示例:

#include<iostream>
using namespace std;
//成员变量和成员函数的分开
class Person
{};
class Person_2
{
	int m_A;			   //非静态成员变量属于类的对象上
	static string m_Name;  //静态成员变量不属于类的对象上
	void func() {}		   //非静态函数函数不属于类的对象上
	static void func2() {} //静态函数函数不属于类的对象上
//只有非静态成员变量属于类的对象上	
};
class Person_3
{
	int m_A;
	double m_B;
	char m_C;
};
string m_Name = "zzz";
void test1_01()
{
	Person p;
	//空对象占用内存空间为:1 
	//因为编译器会为每个空对象分配一个字节空间,仅仅用来区分不同空对象,使得不同空对象都有一个独一无二的内存位置。
	cout << "size of p = " << sizeof(p) << endl;
}
void test1_02()
{
	Person_2 p;
	//非静态成员变量属于类的对象上,这里有有一个int,所以是4
	cout << "size of p = " << sizeof(p) << endl;
}
void test1_03()
{
	Person_3 p;
	//字节对齐,和最大的对齐,double为8,所以为3*8
	cout << "size of p = " << sizeof(p) << endl;
}
int main()
{
	test1_01();
	test1_02();
	test1_03();

	system("pause");
	return 0;
}

15.2 this指针概念

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

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

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

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

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

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

this指针的用途:

  • 当形参和成员变星同名时,可用this指针来区分
  • 在类的非静态成员函数中返回对象本身,可使用 return *this (*this就是解引用,将这个指针解引用,就得到对象本身)。注意要指明返回数据类型为这个类的引用的数据类型。

示例:

#include<iostream>
using namespace std;

class Person2
{
public:
	Person2(int age)
	{
		age = age;
	}
	int age;
};
class Person2_02
{
public:
	Person2_02(int age)
	{
		this->age = age;
	}

	void PersonAddAge(Person2_02& p)
	{
		this->age += p.age;
	}
	Person2_02 PersonAddAge2(Person2_02& p)   //因为返回类型是一个对象类型,如果直接用这个类的类型接收,会开辟新的内存来接收返回值
	{
		this->age += p.age;
		cout << typeid(*this).name() << endl;   //可以看到(*this)的数据类型是class Person2_02
		return *this;
	}
	Person2_02& PersonAddAge3(Person2_02& p)   //因为返回类型是一个对象类型,用引用接收,可以将本体返回。
	{
		this->age += p.age;
	
		return *this;
	}
	int age;
};

void test2_01()
{
	Person2 p(5);
	cout << "p的年龄为:" << p.age << endl;
	Person2_02 p1(5);
	cout << "p1的年龄为:" << p1.age << endl;
	Person2_02 p2(10);
	cout << "p2的年龄为:" << p2.age << endl;
	p2.PersonAddAge(p1);
	cout << "改变后p2的年龄为:" << p2.age << endl;

	//如果我想多次调用p2的函数,那么需要每次将对象返回。
	//链式编程思想
	p2.PersonAddAge2(p1).PersonAddAge2(p1).PersonAddAge2(p1);
	//理论上应该是15+5+5+5 = 30,但是结果是15+5=20
	//因为每次都是另开辟内存来接收返回的对象,导致不能在原对象上做运算。 
	cout << "再后来改变后p2的年龄为:" << p2.age << endl;

	p2.PersonAddAge3(p1).PersonAddAge3(p1).PersonAddAge3(p1);//20+5+5+5
	cout << "最后改变后p2的年龄为:" << p2.age << endl;
}

int main()
{
	test2_01();

	system("pause");
	return 0;
}

15.3 空指针访问成员函数

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

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

#include<iostream>
using namespace std;

class Person3
{
public:
	void showClassName()
	{
		cout << "this is Person3 class" << endl;
	}
	void showPerson3Age()
	{
		if (this == NULL)
		{
			return;
		}
		//报错原因是因为传入的指针为NULL,  
		cout << "age = " << m_Age << endl; //调用m_Age时,其实是这个代码:this->m_Age,现在this为空,所以报错。
	}
	int m_Age;
};

void test3_01()
{
	Person3* p = NULL;
	p->showClassName();
	p->showPerson3Age();
}

int main()
{
	test3_01();

	system("pause");
	return 0;
}

15.4 const修饰成员函数

常函数:

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

语法:

//常函数
返回值类型 函数名() const {}

//mutable
mutable 数据类型 变量名;

常对象:

  • 常对象的所有成员变量都不可修改。
  • 成员属性声明时加关键字mutable后,依然可以修改。
  • 声明对象前加const称该对象为常对象。
  • 常对象只能调用常函数
//常对象
const 对象名 对象;

示例

#include<iostream>
using namespace std;

class Person4
{
public:
	//this指针本质就是一个指针常量(指针的指向不可更改)  类似于Person* const this;
	//加上const后,就相当于const Person *const this,即指针指向的值也不可修改。
	void showPerson4() const
	{ 
		//this = NULL; this指针是不可修改的,
		//this->m_A = 100;
		this->m_B = 200;
	}

	void func()
	{
		m_A = 100;
	}

	int m_A;
	mutable int m_B;  //变量加上关键字mutable后,就仍旧是可以更改的。
};

void test4_01()
{
	Person4 p;
	p.showPerson4();
}
void test4_02()
{
	const Person4 p;  //变为常对象
	//p.m_A = 100;
	p.m_B = 200;      //m_B加了mutable,在常对象下也是可以修改的。
	
	//常对象只能调用常函数
	p.showPerson4();
	//p.func();//非常函数不可调用
	//因为非常函数内可以修改成员变量,但是常对象已经被规定它的成员变量是不可修改的,所以会报错。
}

int main()
{
	test4_01();

	system("pause");
	return 0;
}

  • 作者:拒绝省略号
  • 原文链接:https://blog.csdn.net/qq_49030008/article/details/123218674
    更新时间:2023年7月14日11:09:25 ,共 3460 字。