c++类开发的第三篇(讲明白友元函数和this指针)

这篇具有很好参考价值的文章主要介绍了c++类开发的第三篇(讲明白友元函数和this指针)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

friend_function

成员变量和函数的存储

c++实现了封装数据处理数据的操作(函数)是分开存储的。

  1. c++中的非静态数据成员直接内含在类对象中,就像c语言的struct一样。

  2. 成员函数并不会出现在对象中,而是作为类的一部分存储在代码段中,需要通过对象或对象指针进行调用。成员函数可以访问类的所有成员变量和成员函数,包括私有成员,但不能直接访问静态变量,需要使用类名或对象来访问。

  3. 每一个非内联成员函数(non-inline member function)只会诞生一份函数实例.

class Regina02 {
public:
	int a;
};

class Regina03 {
public:
	int mA;
	static int sB;
};

class Regina04 {
public:
	void printMyClass() {
		cout << "Regina04 void printMyClass()" << endl;
	}
public:
	int mA;
	static int sB;

};

class Regina05 {
public:
	void printMyClass() {
		cout << "Regina05 void printMyClass()" << endl;
	}
	static void ShowMyClass() {
		cout << "Regina05 static void ShowMyClass()" << endl;
	}

在这四个类里面,后面一个类分别比前面一个类多一个成分,为了证实C++类对象中的变量和函数是分开存储,我们分别实例化四个对象打印大小

int main() {
	Regina02 regina02;
	Regina03 regina03;
	Regina04 regina04;
	Regina05 regina05;
	cout << "Regina02:" << sizeof(regina02) << endl; //4
	//静态数据成员并不保存在类对象中
	cout << "Regina03:" << sizeof(regina03) << endl; //4
	//非静态成员函数不保存在类对象中
	cout << "Regina04:" << sizeof(regina04) << endl; //4
	//静态成员函数也不保存在类对象中
	cout << "Regina05:" << sizeof(regina05) << endl; //4
	return 0;

c++类开发的第三篇(讲明白友元函数和this指针)

发现所有的类对象大小都一样,对于静态成员变量和静态成员函数,它们并不属于类的对象,而是属于整个类本身。它们存储在静态数据区,而不是存储在类的对象中。静态成员变量在程序运行期间只有一份实体,不随类的对象的创建而分配内存,而静态成员函数也不依赖于特定的类对象。

this指针

通过上例我们知道,c++的数据和操作也是分开存储,并且每一个非内联成员函数(non-inline member function)只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码

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

c++类开发的第三篇(讲明白友元函数和this指针)

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

c++规定,this指针是隐含在对象成员函数内的一种指针。当一个对象被创建后,它的每一个成员函数都含有一个系统自动生成的隐含指针this,用以保存这个对象的地址,也就是说虽然我们没有写上this指针,编译器在编译的时候也是会加上的。因此this也称为“指向本对象的指针”,this指针并不是对象的一部分,不会影响sizeof(对象)的结果。

 this指针是C++实现封装的一种机制,它将对象和该对象调用的成员函数连接在一起,在外部看来,每一个对象都拥有自己的函数成员。一般情况下,并不写this,而是让系统进行默认设置。

this指针使用

  • 当形参和成员变量同名时,可用this指针来区分

  • 在类的非静态成员函数中返回对象本身,可使用return *this.


class Use_this {
private:
	string name;
	int age;
public:
	/*当形参名字和成员变量名字一样时,this指针可以区分*/
	Use_this(string name, int age) {
		// name = name; false 
		this->name = name;
		this-> age = age;
	}
	//返回对象本身的引用
	//重载赋值操作符
	//其实也是两个参数,其中隐藏了一个this指针
	Use_this personAdd(Use_this& person) {
		string newname = this->name + person.name;
		int newage = person.age + this->age;
		Use_this newperson(newname, newage);
		return Use_this(newname, newage); 

	}
	void showPerson() {
		cout << "name: " << name << "\n" << "age: " << age << endl;
	}

};

int main(){
	Use_this person1 = Use_this("regina ", 13);
	Use_this person2 = Use_this("love Ivanlee", 14);

	person1.showPerson();
	Use_this person3 = person1.personAdd(person2);
	person3.showPerson();
	return 0;
}

c++类开发的第三篇(讲明白友元函数和this指针)

const

const 关键字用于修饰成员函数时,它表示该成员函数是一个常量成员函数,也称为常成员函数。常成员函数有以下特点:

  1. 常成员函数不会修改对象的状态:常成员函数承诺不会修改类的任何非静态成员变量。这意味着在常成员函数内部,不能修改成员变量的值,除非该成员变量被声明为 mutable
  2. 常成员函数可以读取对象的状态:常成员函数可以访问和读取类的所有成员变量,包括非 const 成员变量。
  3. 常成员函数可以调用其他常成员函数:常成员函数可以调用其他常成员函数,因为它们都遵守不修改对象状态的承诺。

在 C++ 中,mutable 是一个关键字,用于声明类的成员变量可以在常成员函数中被修改。通常情况下,常成员函数(被 const 修饰的成员函数)不能修改类的成员变量,因为它们承诺不会改变对象的状态。然而,有时候我们可能需要在常成员函数中修改某些变量,这时就可以使用 mutable 关键字。

当一个成员变量被声明为 mutable 时,即使在常成员函数中,该成员变量仍然可以被修改。这样做的目的是为了允许在逻辑上不改变对象状态的情况下,修改一些与对象状态无关的数据。

c++类开发的第三篇(讲明白友元函数和this指针)在ida里面写代码的时候就能看到,当我们定义好了const成员函数时,没有定义过的mutable的变量是不可以修改的。

友元函数

友元函数存在的主要原因是为了提供更灵活的设计和实现方式,同时在某些特定情况下确实需要直接访问类的私有成员或保护成员。以下是一些使用友元函数的情况和原因:

  1. 访问私有成员:有时候在类的外部需要访问类的私有成员数据,但又不希望通过公有成员函数来实现。这种情况下,可以使用友元函数来实现对私有成员的直接访问,提高代码的封装性和安全性。
  2. 提高效率:有些操作可能需要直接访问类的私有数据,如果通过公有接口来访问可能会降低效率。通过友元函数可以避免频繁调用公有接口,提高程序执行效率。
  3. 实现非成员函数:某些操作与类密切相关,但又不属于类的成员函数的范畴,这时候可以使用友元函数来实现这样的操作。
  4. 重载运算符:在C++中,一些运算符如 <<>>+ 等是可以重载的,如果想要对类进行运算符重载,并且需要直接访问类的私有数据,可以使用友元函数来实现。(后续会解释)
  5. 类之间的协作:有时候多个类之间需要相互访问对方的私有成员,可以使用友元函数来实现类之间的协作。

友元语法

friend关键字只出现在声明处

其他类、类成员函数、全局函数都可声明为友元

友元函数不是类的成员,不带this指针

友元函数可访问对象任意成员属性,包括私有属性

#include<iostream>
using namespace std;

class Home;// 前向声明 Myfriend 类
class Myfriend {
public:
	void PlayinBedroom(Home& home);
	void Eatindinningroom(Home& home);
};

class Home {
private:
	string bedroom;
	string dinningroom;
public:
	string sittingroom;
	Home() {
		bedroom = "bedroom";
		dinningroom = "dinning room";
	}
	friend void CleanMyhome(Home &home) {
		cout << "友元全局函数访问" << home.bedroom << endl;
	}
	//成员函数做友元函数
	friend void Myfriend::PlayinBedroom(Home& home); //必须把函数内容写在类外面
	friend void Myfriend::Eatindinningroom(Home& home);//类内只做声明
};

void Myfriend::PlayinBedroom(Home& home) {
	std::cout << "我的朋友正在" << home.bedroom << "里玩" << std::endl;
}

void Myfriend::Eatindinningroom(Home& home) {
	std::cout << "我的朋友正在" << home.dinningroom << "里吃饭" << std::endl;
}

int main() {
	Home myHome;
	CleanMyhome(myHome); // 调用全局友元函数
	Myfriend myFriend;
	myFriend.PlayinBedroom(myHome); // 调用 Myfriend 的成员函数作为友元函数
	myFriend.Eatindinningroom(myHome); // 调用 Myfriend 的成员函数作为友元函数

	return 0;
}

c++类开发的第三篇(讲明白友元函数和this指针)

[友元类注意]

1.友元关系不能被继承。

2.友元关系是单向的,类A是类B的朋友,但类B不一定是类A的朋友。

友元关系不具有传递性。类B是类A的朋友,类C是类B的朋友,但类C不一定是类A的朋友。

练习题

请编写电视机类,电视机有开机和关机状态,有音量,有频道,提供音量操作的方法,频道操作的方法。由于电视机只能逐一调整频道,不能指定频道,增加遥控类,遥控类除了拥有电视机已有的功能,再增加根据输入调台功能。

首先我们要写一下电视的功能

class TV {
	friend class Remote;
private:
	int mState; //电视状态,开机,还是关机
	int mVolume; //电视机音量
	int mChannel; //电视频道

public:
	enum {On,Off};
	enum {minVol, maxVol = 100};
	enum{ minChannel = 0, maxChannel = 255};
	TV() {
		mState = Off;
		mVolume = minVol;
		mChannel = minChannel;

	}
	void TurnOnorOff() {
		this->mState = (this->mState == Off ? On : Off);
	}

	//调高音量
	void VolumeUp() {
		if (this->mVolume >= maxVol) {
			return;
		}
		this->mVolume++;
	}
	void VolumeDown() {
		if (this->mVolume == minVol) {
			return;
		}
		this->mVolume--;
	}
	//更换电视频道
	void ChannelUp() {
		if (this->mChannel >= maxChannel) {
			return;
		}
		this->mChannel++;
	}
	void ChannelDown() {
		if (this->mChannel <= minChannel) {
			return;
		}
		this->mChannel--;
	}
	//展示当前电视状态信息
	void ShowTeleState() {
		cout << "当前电视" << (mState == On ? "已开机":"已关机") << endl;
		if (mState == On) {
			cout << "当前音量:" << mVolume << endl;
			cout << "当前频道:" << mChannel << endl;
		}
		cout << "-------------" << endl;

	}
class Remote {
private:
	TV tv;
public:
	Remote(TV& tv) {

		this->tv = tv;
	}
	void OnOrOff() {
		tv.TurnOnorOff();
	}
	//调高音量
	void VolumeUp() {
		tv.VolumeUp();
	}
	//调低音量
	void VolumeDown() {
		tv.VolumeDown();
	}
	//更换电视频道
	void ChannelUp() {
		tv.ChannelUp();
	}
	void ChannelDown() {
		tv.ChannelDown();
	}
	//设置频道 遥控新增功能
	void setChannel(int chan) {
		if (chan < tv.minChannel || chan > tv.maxChannel) {
			return;
		}
		tv.mChannel = chan;
	}

	//展示电视信息
	void showTV() {
		tv.ShowTeleState();
	}
};
//直接操作电视
void test01() {

	TV television;
	television.ShowTeleState();
	television.TurnOnorOff(); //开机
	television.VolumeUp(); //增加音量+1
	television.VolumeUp(); //增加音量+1
	television.VolumeUp(); //增加音量+1
	television.VolumeUp(); //增加音量+1
	television.ChannelUp(); //频道+1
	television.ChannelUp(); //频道+1
	television.ShowTeleState();
}//通过遥控操作电视

void test02() {
	//创建电视
	TV television;
	//创建遥控
	Remote remote(television);
	remote.OnOrOff();
	remote.ChannelUp();//频道+1
	remote.ChannelUp();//频道+1
	remote.ChannelUp();//频道+1
	remote.VolumeUp();//音量+1
	remote.VolumeUp();//音量+1
	remote.VolumeUp();//音量+1
	remote.VolumeUp();//音量+1
	remote.showTV();
}

c++类开发的第三篇(讲明白友元函数和this指针)文章来源地址https://www.toymoban.com/news/detail-833827.html

到了这里,关于c++类开发的第三篇(讲明白友元函数和this指针)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 从零开始c++精讲:第三篇——内存管理

    为什么要有内存区域的划分呢? 因为不同数据有不同的存储需求,各区域满足不同的需求。 栈(堆栈) :一般存放临时用的,比如非静态局部变量/函数参数/返回值等,栈是向下增长的。 堆 :有动态使用的需求,需要的时候你给我,不需要的时候你释放。也就是出了函数作

    2024年01月21日
    浏览(46)
  • SYSU程设c++(第九周)函数对象、友元函数、友元类

    函数对象:         如果一个类 定义了operator()运算符函数 ,则 可以使用该类的对象名为函数名 调用这个函数.          函数对象是一个对象, 但 调用形式和普通函数调用一样 ,因此取名叫函数对象 (注意operator()先有个括号,接着才是括号(参数列表)) 友元函数:  f

    2023年04月23日
    浏览(33)
  • C++友元函数

    友元——让函数或者类作为另外一个类的朋友,则可以访问当前类的private或者protected 友元friend机制允许一个类授权其他的函数访问它的非公有成员 友元声明以friend开头,它只能出现在类的声明中,它们不受其在类体中的public、private和protected区的影响 1、外部函数友元

    2024年02月06日
    浏览(46)
  • 波奇学C++:友元函数,友元类,内部类,匿名对象,优化构造

    这个代码会报错,原因是_a是a._a的私有成员,fun()是类外函数不能访问。 加上友元就可以突破限制 关于友元的知识 友元函数是一种声明,表明这个函数可以访问私有变量。 友元函数本质上不属于类函数,所以这个声明是不受访问限定符限制的,可以定义在public或者private中。

    2024年02月05日
    浏览(42)
  • C++之类的友元函数

    类的友元函数是指在类中声明为友元的函数。友元函数可以访问类的所有成员(包括私有成员),但它本身并不是类的成员函数,因此不需要通过类的对象来调用。友元函数主要用于在类的内部实现对其他类成员的访问和操作。 举例说明: 这个友元函数的参数是一个类A的对象引

    2024年01月22日
    浏览(38)
  • C++ STL第三篇(搞清楚deque原理和有多少用法)

    Vector容器是单向开口的连续内存空间,deque则是一种双向开口的连续线性空间。所谓的双向开口,意思是可以在头尾两端分别做元素的插入和删除操作,当然,vector容器也可以在头尾两端插入元素,但是在其头部操作效率奇差,无法被接受。 Deque容器和vector容器最大的差异,

    2024年03月17日
    浏览(38)
  • Groovy开发语言系列(第三篇):DSL的强大能力

    欢迎阅读本系列的第三篇文章!在前两篇中,我们已经介绍了Groovy语言的发展历史、特点以及安装和基本语法。今天,我们将聚焦于Groovy的强大能力之一:领域特定语言(Domain-Specific Language,简称DSL)。 让我们先通过一个简单的示例来吸引大家对DSL的兴趣: 这段代码执行后

    2024年02月12日
    浏览(31)
  • 第三篇 香橙派的外设开发基础(中)— 串口篇

    目录 一、OrangePi PC Plus的串口 1.开启OrangePi PC+用于通信的串口  🔖方法一 :修改/boot/orangepiEnv.txt  🔖方法二:通过orangepi-config 2.基于wiringPi的串口通信Demo1.c 二、Linux下的串口开发基础  1.Linux下的串口配置 2.Linux串口通信Demo2.c         根据官方的用户手册所描述,OrangeP

    2023年04月08日
    浏览(36)
  • 【Python微信机器人】第三篇:使用ctypes调用进程函数和读取内存结构体

    目前的系列目录(后面会根据实际情况变动): 在windows11上编译python 将python注入到其他进程并运行 注入Python并使用ctypes主动调用进程内的函数和读取内存结构体 使用汇编引擎调用进程内的任意函数 利用beaengine反汇编引擎的c接口写一个pyd库,用于实现inline hook 利用beaengine反汇编

    2024年02月06日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包