第十一章 类和对象——第3节 C++对象模型与this指针

11.3 C++对象模型和this指针

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

1.空对象占1Byte空间,用于区分不同对象所在地址的不同

class Person {		// 空类

};

void test01() {
	Person p1;		// 空对象
	cout << sizeof(p1) << endl;		// 结果为1
}

2.非静态成员变量 属于 类的实例化对象中的一部分

3.静态成员变量 不属于 类的实例化对象中的一部分

4.非静态成员函数 不属于 类的实例化对象中的一部分

5.静态成员函数 不属于 类的实例化对象中的一部分

class Person {
public:
	int m_age;					// 属于Person类的实例化对象p1中	占4Byte
	static string m_name;		// 不属于Person类的实例化对象p1中	占0Byte 
	int getAge() {				// 不属于Person类的实例化对象p1中	占0Byte
	}
	static string getName() {	// 不属于Person类的实例化对象p1中	占0Byte
	}
};

void test01() {
	Person p1;		// 空对象
	cout << sizeof(p1) << endl;	// 结果为4
}
11.3.2 this指针

this指针隐含在每一个非静态成员函数中,指向 调用该成员函数的 对象

this指针的本质:指针常量,其指向不可修改

用途1:解决形参与成员变量名冲突的问题,this指向调用成员函数的对象

class Person {
public:
	Person(int age) {		// 形参age与成员变量age冲突
		// age = age;		// 此处编译器认为是:传入的age=传入的age,导致输出脏值	
        this -> age = age;	// 此处this会指向调用该函数的对象,即p1,此时该行代码等价于:p1.age = age,完成了对成员变量的赋值
	}
	int age;
};

void test() {
	Person p1(18);
	cout << p1.age << endl;
}

用途2:返回对象本身用*this

/*想要实现的功能:对象p1可连续调用PersonAddAge函数,不断将对象p2的age值累加到自身的age属性中*/
class Person {
public:
	Person(int age) {		// 构造函数,初始化age属性值
		this -> age = age;
	}
	int age;
    
	Person& PersonAddAge(Person p) {	// 作用:调用后使本对象的age变量与传入的p对象的age变量相加
		this->age += p.age;
		return *this;
	}
};

void test() {
	Person p1(18) ,p2(20);
	p1.PersonAddAge(p2).PersonAddAge(p2);	// 链式编程
	cout << p1.age << endl;
}

下面对关键的PersonAddAge()函数进行解释

(1)为什么返回值不是 return this->age

​ 因为this->age的含义是对象自身的age属性,是个int类型的值,而在第17行想要实现的效果是p1.PersonAddAge(p2)p1.PersonAddAge(p2)可作为p1本身再次调用PersonAddAge()函数,即p1.PersonAddAge(p2).PersonAddAge(p2)。那么返回值应该是对象本身,this作为指向对象的指针,*this自然代表对象本身,在本文中即为p1

(2)为什么函数返回类型不是Person

​ 若返回类型设置为Person,此时为值返回,那么系统会在return *this时调用拷贝构造函数,创建一个临时对象去接收返回值,类似于Person Temp = p1.PersonAddAge(p2),这样继续进行累加时,会产生Temp.PersonAddAge(p2)的效果,修改的是临时对象的age属性,且无法确定Temp对象的位置。经过代码验证,在返回类型为Person时,p1.PersonAddAge(p2).PersonAddAge(p2)的结果为38,即只有第一次调用PersonAddAge(p2)有效果,第二次调用将p2.age加到了Temp对象上,虽然代码不报错但是结果不正确。

​ 所以需要设置返回类型为Person&,此时为引用返回,返回的是*this的引用,那么连续调用PersonAddAge()函数都可以正常修改p1的age属性值

11.3.3 空指针访问成员函数

C++中空指针可以调用成员函数,但是要注意是否使用了this指针,若用到this指针,则需要加判断语句保证代码的健壮性

class Person {
public:
	void showAge() {
        cout << "Hello World" <<endl;	// 这句可以正常运行,因为只是打印一段现成的字符串
		cout << m_age << endl;			// 这句无法正常运行,因为m_age前会默认加this指针
	}
	int m_age;
};

void test() {
	Person* p1 = NULL;
	p1->showAge();
}

在C++中,成员函数中对属性的操作都会在属性前默认添加this指针,例如cout << m_age << endl; 实际上是 cout << this->m_age << endl;,test函数中对实例化对象的指针赋空,调用成员函数showAge()this指针指向空地址,自然无法探知其中的属性值。可在成员函数中添加if(this==NULL) return 0;规避风险。

11.3.4 const修饰成员函数

常函数

  • 成员函数const,称该函数为常函数

  • 常函数内不可修改成员属性

  • 成员属性声明时加关键字mutable后,在常函数中可被修改

    class Person {
    public:
    	void changeClass() const{	// 常函数
    		classname = "People";	// 修改的是带关键字“mutable”的成员属性
    	}
    	mutable string classname;
    };
    
    void test() {
    	Person p1;
    	p1.classname = "Person";
    	p1.changeClass();
    }
    

    实质:

    • 未加const时:相当于Person* const this,此时const修饰this指针,使其指向的地址不能发生改变,即this的值不能变
    • 添加const时:相当于const Person* const this,在上述的基础上,新增的const修饰this指针指向的空间,使得this指向的地址上的数值不能变

常对象

  • 声明对象const,称该对象为常对象

  • 常对象除被mutable修饰的属性之外,都不允许被修改

  • 常对象只能调用常函数

    class Person {
    public:
    	void changeClass() const{	// 常函数
    		classname = "People";	
    	}
    	mutable string classname;	// 被修饰的属性
    };
    
    void test() {
    	const Person p1;			// 常对象
    	p1.classname = "Person";	// 只 可修改被修饰的属性
    	p1.changeClass();			// 只可调用常函数
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值