C++ Day04 this指针,友元函数,重载

this指针

概念

谁调用 this 所在的函数 ,this 就存储谁的地址

特点

1, 在当前类的非静态成员函数中调用本类非静态成员时 , 默认有 this 关键字
2, 静态成员函数 , 没有 this 指针。
示例
#include <iostream>
#include <cstring>
using namespace std;
class Stu{
private:char name[50];char sex[10];int age;
public:Stu(){}Stu(char *n,char *s,int a):age(a){strcpy(name,n);strcpy(sex,s);}void test01(){//以下两句代码效果相同//证明本类函数中调用本类成员默认使用this关键字cout << this->name << endl;cout << name << endl;}static void test02(){//报错,因为静态函数中没有this//cout << name << endl;}
};
int main(int argc, char *argv[])
{Stu s("张三","男",18);s.test01();s.test02();return 0;
}

使用场景

1, 局部变量与成员变量重名时 , 使用 this 区分
2, 调用本类其他成员 , 此时 this 可以省略不写
示例
#include <iostream>
#include <cstring>
using namespace std;
class Stu{
private:char name[50];char sex[10];int age;
public:Stu(){}Stu(char *name,char *sex,int age){//当局部变量与成员变量重名,使用this区分strcpy(this->name,name);strcpy(this->sex,sex);this->age = age;}void print_info(){//调用本类成员变量cout << this->name << endl;cout << this->sex << endl;cout << this->age << endl;}void test(){//调用本类成员函数this->print_info();}
};
int main(int argc, char *argv[])
{Stu s("张三","男",18);s.print_info();s.test();return 0;
}

实例

使用 :*this 完成链式编程
#include <iostream>
#include <cstring>
using namespace std;
class Stu{
private:char name[50];char sex[10];int age;
public:Stu(){}Stu(char *name,char *sex,int age){strcpy(this->name,name);strcpy(this->sex,sex);this->age = age;}void print_info(){cout << this->name << endl;cout << this->sex << endl;cout << this->age << endl;}Stu& eat(char *foodName){cout << name << "吃" << foodName << endl;return *this;}
};
int main(int argc, char *argv[])
{Stu s("张三","男",18);s.eat("凉皮").eat("肉夹馍").eat("甑糕");return 0;
}

const修饰成员函数(了解)

特点

        const修饰的成员函数内部不能对成员数据写操作, mutable 修饰的成员数据 除外。

实例

class Stu{
private:char name[50];char sex[10];int age;mutable int score;
public:Stu(){}Stu(char *name,char *sex,int age){strcpy(this->name,name);strcpy(this->sex,sex);this->age = age;}void print_info(){cout << this->name << endl;cout << this->sex << endl;cout << this->age << endl;}Stu& eat(char *foodName){cout << name << "吃" << foodName << endl;return *this;}void test() const{//age = 10;//错误score = 99;//正确}
};

友元函数(重要)

概述

关键字 :friend
可以声明 :
        1,全局函数
        2,成员函数
        3,类
注意 :
        友元打破c++ 的封装性。一般用于运算符重载

全局友元函数

特点

可以访问其友元类的任意成员 , 包括私有成员

步骤

1, 在定义并实例全局函数
2, 在类中声明步骤 1 中的函数为友元函数
3, 步骤 1 中定义的函数 , 可以访问步骤 2 中定义的类中的所有成员

示例

#include <iostream>
#include <cstring>
using namespace std;
class Stu{
friend void test(Stu &stu);
private:char name[50];char sex[10];int age;
public:Stu(){}Stu(char *name,char *sex,int age){strcpy(this->name,name);strcpy(this->sex,sex);this->age = age;}void print_info(){cout << this->name << endl;cout << this->sex << endl;cout << this->age << endl;}
private:void eat(char *foodName){cout << name << "吃" << foodName << endl;}
};
void test(Stu& stu)
{
//调用友元类的私有属性cout << stu.name << endl;cout << stu.sex << endl;cout << stu.age << endl;
//调用友元类的私有函数stu.eat("大嘴巴子");
}
int main(int argc, char *argv[])
{Stu s("张三","男",18);test(s);return 0;
}

成员友元函数

特点

        可以访问其友元类的任意成员, 包括私有成员

注意       

1, 成员函数作为友元 那么成员函数所在的类 必须定义到最上方
2, 成员函数所在的类的所有成员函数 必须在两个类的下方实现

步骤

        1,定义 B , 但不现实
        2,定义成员函数 A1 所在的类 A, 但其中只定义该成员函数 A1
        3,实现 B , 并在其中声明成员函数 A1 为友元函数
        4,实现成员函数

示例

#include <iostream>
#include <cstring>
using namespace std;
//定义B类,但是没有实现
class B;
class A{
public:void test(B& b);
};
class B{
friend void A::test(B& b);
private:int a;
public:B(int a){this->a = a;}
private:void print_B(){cout << "a = " << a << endl;}
};
void A::test(B& b){cout << b.a << endl;b.print_B();}
int main(int argc, char *argv[])
{A a;B b(10);a.test(b);return 0;
}

整个类作为友元函数

特点

        在B 中声明 A B 的友元类 , 此时 A 中任意成员函数中皆可直接访问 B 中的成员

步骤        

1, 定义 B
2, 定义并实现 A , 其中函数只定义不实现
3, 实现 B , 在其中声明 A 类为友元类
4, 实现 A 类中的成员函数

示例

#include <iostream>
#include <cstring>
using namespace std;
//定义B类,但是没有实现
class B;
class A{
public:void test01(B& b);void test02(B& b);
};
class B{
friend class A;
private:int a;
public:B(int a){this->a = a;}
private:void print_B(){cout << "a = " << a << endl;}
};
void A::test01(B& b)
{cout << "test01" << endl;cout << b.a << endl;b.print_B();
}
void A::test02(B& b)
{cout << "test02" << endl;cout << b.a << endl;b.print_B();
}
int main(int argc, char *argv[])
{A a;B b(10);a.test01(b);cout << "--------------------" << endl;a.test02(b);return 0;
}

注意

1, 友元关系不能被继承。
2, 友元关系是单向的,类 A 是类 B 的朋友,但类 B 不一定是类 A 的朋友。
3, 友元关系不具有传递性。类 B 是类 A 的朋友,类 C 是类 B 的朋友,但类 C 不一
定是类 A 的朋友

实例

说明

遥控器类的对象可以操作电视机类对象的成员
所以遥控器类是电视机类的友元类

代码

#include <iostream>
#include <cstring>
using namespace std;
class TV;
class YK{
public:void up(TV& tv);void down(TV& tv);
};
class TV{
friend class YK;
private:int yl;
public:TV(){}TV(int yl){this->yl = yl;}
};
void YK::up(TV &tv)
{tv.yl++;cout << "当前音量:" << tv.yl << endl;
}
void YK::down(TV &tv)
{tv.yl--;cout << "当前音量:" << tv.yl << endl;
}
int main(int argc, char *argv[])
{TV tv(10);YK yk;yk.up(tv);yk.up(tv);yk.up(tv);yk.down(tv);yk.down(tv);yk.down(tv);return 0;
}

string

c++ 字符串类 , 使其字符串操作方便
示例
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char *argv[])
{
string str01 = "hello";
string str02 = str01;//字符串赋值
cout << str01 << endl;//字符串输出
cout << str02 << endl;
str02 = "world";
cout << str01 << endl;
cout << str02 << endl;
string str03 = str01 + str02;//字符串拼接
cout << str03 << endl;
string str04;
cin >> str04;//字符串输入
cout << str04 << endl;
string str05 = "Hi C++";
string str06 = "Hi C++";
string str07 = "Hi C";
cout << (str05 == str06) << endl;//判断字符串内容是否相同
cout << (str05 == str07) << endl;
cout << &str05 << endl;//打印str05地址
cout << &str06 << endl;//打印str06地址
return 0;
}

重载

引入

经源码查看 string 发现其也是一个类
那么为什么 string 的类对象可以使用 >>,<<,+,== 等运算符 , 我们自定义的类不行呢 ?
因为 string 类对运算符进行了重载
那我们如何实现运算符的重载

概述

作用

        是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。

关键字

        operator

语法

        返回值类型 operator+ 运算符 ( 形参列表 )
        {
                函数体
        }
        如:
        >>
        void operator>>(形参列表 )
        {
        }
思路
1 、分析运算符的运算对象的个数
2 、分析运算符左边的运算对象是 自定对象 还是其他
左边:是其他 只能全局函数实现 (必须使用友元)
左边:自定义对象
可以用使用全局函数重载运算符(参数个数 和 运算符对象的个数一致)
也可以使用成员函数重载运算符(参数可以少一个) (推荐)

示例1:重载<<,>>运算符

效果
        使其可以通过<< 输出自定义类型的变量或通过 >> 输入自定义类型变量
分析
<< >> 符号左边为 cout cin 不是自定义对象 , 只能使用全局函数对其进行重载
示例
#include <iostream>
#include <cstring>
using namespace std;
class Data{
public:int x,y,z;Data(){}Data(int a,int b,int c):x(a),y(b),z(c){}
};
//第一个参数为运算符左边的变量
//第二个参数为运算符右边的变量
istream& operator >>(istream& in,Data& d)
{in >> d.x >> d.y >> d.z;return in;
}
ostream& operator <<(ostream& out,Data& d)
{out << "x = " << d.x << "\ty = " << d.y << "\tz = " << d.z << endl;return out;
}
int main(int argc, char *argv[])
{Data d;cin >> d;cout << d << endl;return 0;
}

示例2:重载+运算符

效果

        使用+ 运算符将自定义类型对象的属性一一相加

分析

        +符号左边为自定义类型 , 可以使用全局函数重载也可以使用成员函数中

示例:全局函数重载

#include <iostream>
using namespace std;
class Data{
public:int x,y,z;Data(){}Data(int a,int b,int c):x(a),y(b),z(c){}
};
//第一个参数为运算符左边的变量
//第二个参数为运算符右边的变量
Data* operator +(Data& d1,Data& d2)
{Data *d = new Data();d->x = d1.x + d2.x;d->y = d1.y + d2.y;d->z = d1.z + d2.z;return d;
}
int main(int argc, char *argv[])
{Data d1(1,2,3);Data d2(1,2,3);Data* d3 = d1 + d2;cout << d3->x << d3->y << d3->z << endl;return 0;
}
示例 2: 成员函数重载 + 运算符
#include <iostream>
using namespace std;
class Data{
public:int x,y,z;Data(){}Data(int a,int b,int c):x(a),y(b),z(c){}
//调用该函数的对象为运算符左边的变量
//参数为运算符右边的变量
Data* operator +(Data& d2)
{Data *d = new Data();d->x = this->x + d2.x;d->y = this->y + d2.y;d->z = this->z + d2.z;return d;
}
};
int main(int argc, char *argv[])
{Data d1(1,2,3);Data d2(1,2,3);Data* d3 = d1 + d2;cout << d3->x << d3->y << d3->z << endl;return 0;
}

示例3:重载==运算符

效果
        比较类中成员变量值是否相同
分析
        符号左边为自定义类型, 可以使用全局函数重载也可以使用成员函数中
示例
#include <iostream>
using namespace std;
class Data{
public:int x,y,z;Data(){}Data(int a,int b,int c):x(a),y(b),z(c){}
//调用该函数的对象为运算符左边的变量
//参数为运算符右边的变量bool operator ==(Data& d2){if(this->x == d2.x && this->y == d2.y && this->z == d2.z){return true;}else{return false;}}
};
int main(int argc, char *argv[])
{Data d1(1,2,3);Data d2(1,2,3);Data d3(2,2,3);cout << (d1 == d2) << endl;cout << (d1 == d3) << endl;return 0;
}

示例4:重载++运算符

注意

++ 运算符分为 ++ 在前与 ++ 在后两种所以需要重载两种
当编译器看到 ++a( 前置 ++), 它就调用 operator++(Type& a)( 全局函数 ),operator++
()( 成员函数 )
当编译器看到 a++( 后置 ++), 它就会去调用 operator++(Type& a,int)( 全局函
),operator++(int)( 成员函数 )

示例

#include <iostream>
using namespace std;
class Data{
public:int x,y,z;Data(){}Data(int a,int b,int c):x(a),y(b),z(c){}Data& operator ++()//++前置{++x;++y;++z;return *this;}Data operator ++(int)//++后置{Data old = *this;//记录旧值++x;++y;++z;return old;//返回旧值}
};
ostream& operator <<(ostream& out,Data& d)
{out << d.x << d.y << d.z << endl;return out;
}
int main(int argc, char *argv[])
{Data d1(1,2,3);++d1;cout << d1;Data d2(1,2,3);Data d3 = d2++;cout << d3;cout << d2;return 0;
}

示例5:重载*->

要求

        重载指针运算符实现智能指针

推演

#include <iostream>
using namespace std;
class Data{
private:int x,y,z;
public:Data(){cout << "无参构造函数" << endl;}Data(int a,int b,int c):x(a),y(b),z(c){cout << "有参构造函数" << endl;}~Data(){cout << "析构函数" << endl;}
};
int main(int argc, char *argv[])
{Data *p = new Data();return 0;
}
观察以上代码 , 我们发现创建的对象没有被销毁 , 但是我们在编写代码时经常会忘记销
, 那该怎么办呢 ?
解决方案如下
#include <iostream>
using namespace std;
class Data{
private:
int x,y,z;
public:Data(){cout << "无参构造函数" << endl;}Data(int a,int b,int c):x(a),y(b),z(c){cout << "有参构造函数" << endl;}~Data(){cout << "析构函数" << endl;}
};
class FreeData{
private:Data* p;
public:FreeData(){p = NULL;}FreeData(Data* data){p = data;}~FreeData(){if(p != NULL){delete p;p = NULL;}}
};
int main(int argc, char *argv[])
{FreeData fd(new Data(1,2,3));return 0;
}
现在我们发现 Data 对象可以销毁 , 但是如何调用其对象中的属性呢 ?
方案如下
#include <iostream>
using namespace std;
class Data{
private:int x,y,z;
public:Data(){cout << "无参构造函数" << endl;}Data(int a,int b,int c):x(a),y(b),z(c){cout << "有参构造函数" << endl;}~Data(){cout << "析构函数" << endl;}int getX(){return x;}
};
class FreeData{
private:Data* p;
public:FreeData(){p = NULL;}FreeData(Data* data){p = data;}~FreeData(){if(p != NULL){delete p;p = NULL;}}Data& operator *(){return *p;}Data* operator ->(){return p;}
};
int main(int argc, char *argv[])
{FreeData fd(new Data(1,2,3));cout << (*fd).getX() << endl;cout << fd->getX() << endl;return 0;
}

示例6:重载()

作用

当类对象作为函数调用时,会执行 operator()( 参数列表 ) 函数。
对象作为函数调用
对象名 ( 实参列表 );
一种仿函数

示例

#include <iostream>
using namespace std;
class Data{
friend ostream& operator <<(ostream& out,Data& d);
private:int x,y,z;
public:Data(){cout << "无参构造函数" << endl;}Data(int a,int b,int c):x(a),y(b),z(c){cout << "有参构造函数" << endl;}~Data(){cout << "析构函数" << endl;}void operator ()(int a,int b,int c){this->x += a;this->y += b;this->z += c;}
};
ostream& operator <<(ostream& out,Data& d)
{out << d.x << "\t" << d.y << "\t" << d.z << endl;return out;
}
int main(int argc, char *argv[])
{Data d(1,2,3);d(2,5,8);cout << d;return 0;
}

示例7:重载=

注意
= 重载时,可能会调用类本身的拷贝构造函数。
如果左值是没有创建的对象时 , 会调用拷贝构造函数 .
如果左值是已创建的类对象 , 会执行 = 重载函数 , 实现数据的拷贝
示例
#include <iostream>
using namespace std;
class Data{
friend ostream& operator <<(ostream& out,Data& d);
private:int x,y,z;
public:Data(){cout << "无参构造函数" << endl;}Data(int a,int b,int c):x(a),y(b),z(c){cout << "有参构造函数" << endl;}Data(const Data& d){cout << "执行拷贝构造" << endl;this->x = d.x;this->y = d.y;this->z = d.z;}~Data(){cout << "析构函数" << endl;}void operator =(Data& d){cout << "执行重载=运算符的函数" << endl;this->x = d.x;this->y = d.y;this->z = d.z;}
};
ostream& operator <<(ostream& out,Data& d)
{out << d.x << "\t" << d.y << "\t" << d.z << endl;return out;
}
int main(int argc, char *argv[])
{Data d1(1,2,3);Data d2(3,6,9);d1 = d2;//d1已完成初始化,执行重载的=号运算符Data d3 = d2;//d3未完成初始化,执行拷贝构造return 0;
}

注意:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/207080.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电力感知边缘计算网关产品设计方案-业务流程设计

1.工业数据通信流程 工业数据是由仪器仪表、PLC、DCS等工业生产加工设备提供的,通过以太网连接工业边缘计算网关实现实时数据采集。按照现有的通信组网方案,在理想通信状态下可以保证有效获取工业数据的真实性和有效性。 边缘计算数据通信框架图: 2.边缘计算数据处理方案 …

__int128类型movaps指令crash

结论 在使用__int128时&#xff0c;如果__int128类型的内存起始地址不是按16字节对齐的话&#xff0c;有些汇编指令会抛出SIGSEGV使程序crash。 malloc在64位系统中申请的内存地址&#xff0c;是按16字节对齐的&#xff0c;但一般使用时经常会申请一块内存自己切割使用&#…

轻量封装WebGPU渲染系统示例<37>- 多个局部点光源应用于非金属材质形成的效果(源码)

当前示例源码github地址: https://github.com/vilyLei/voxwebgpu/blob/feature/rendering/src/voxgpu/sample/BasePbrMaterialMultiLights.ts 当前示例运行效果: 此示例基于此渲染系统实现&#xff0c;当前示例TypeScript源码如下&#xff1a; export class BasePbrMaterial…

2021年06月 Scratch(二级)真题解析#中国电子学会#全国青少年软件编程等级考试

Scratch等级考试(1~4级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 小明同学设计了一款游戏,其中一段程序如下图所示,下面这段程序可以实现哪项功能? A:在任何地方点击鼠标,角色都会移到鼠标位置 B:没有任何操作的时候角色会在舞台区域随机移动…

地图导航测试用例,你get了吗?

地图导航是我们经常使用的工具&#xff0c;能帮助我们指引前进的方向。 接下来&#xff0c;会从功能测试、UI测试、兼容测试、安全测试、网络测试、性能测试、易用性测试、文档和国际化语言测试8个方面来编写地图导航测试用例。 一 功能测试 输入起点和终点&#xff0c;验证…

Vue中Slot的使用指南

目录 前言 什么是slot&#xff1f; 单个slot的使用 具名slot的使用 作用域插槽 总结 前言 在Vue中&#xff0c;slot是一种非常强大和灵活的功能&#xff0c;它允许你在组件模板中预留出一个或多个"插槽"&#xff0c;然后在使用这个组件的时候动态地填充内容。这…

轻量级压测工具Apache Bench实战

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

安防视频EasyCVR平台太阳能供电+4G摄像头视频监控方案的建设

在工地、光伏、风电站、水库河道等场景中&#xff0c;以及一些偏远地区的项目现场&#xff0c;会存在无网无电情况&#xff0c;大大制约了视频监控系统建设的效率及可行性。在这种场景中&#xff0c;我们也可以通过太阳能供电4G监控摄像机的方案&#xff0c;满足偏远地区无网无…

【Linux】掌握 Vim 的基本使用方法:Vimtutor 学习指南

Vim 是一个功能强大的文本编辑器&#xff0c;广受程序员和系统管理员的喜爱。然而&#xff0c;由于其独特的编辑模式和命令行界面&#xff0c;对于初学者来说可能有一些学习曲线。不过不用担心&#xff0c;Vim 自带了一个交互式教程程序 Vimtutor&#xff0c;通过它你可以轻松掌…

论文阅读 Forecasting at Scale (二)

最近在看时间序列的文章&#xff0c;回顾下经典 论文地址 项目地址 Forecasting at Scale 3.2、季节性 3.3、假日和活动事件3.4、模型拟合3.5、分析师参与的循环建模4、自动化预测评估4.1、使用基线预测4.2、建模预测准确性4.3、模拟历史预测4.4、识别大的预测误差 5、结论6、致…

防爆智能安全帽、防爆手持终端,防爆智能矿灯守护安全,在煤矿安全生产远程可视化监管中的应用

煤矿安全新守护&#xff1a;如何通过防爆智能装备实现远程可视化监管 煤矿是国民经济的重要支柱产业&#xff0c;但长期以来&#xff0c;安全生产事故的频发一直是困扰煤矿行业发展的严峻问题。安全生产事故不仅危及矿工的生命安全&#xff0c;也对企业和地方经济造成了重大的…

【Vue】Node.js的安装与环境变量的配置

目录 一.安装 官网&#xff1a; 二.环境变量的配置 node.cache node.global 一.安装 官网&#xff1a; https://nodejs.org/en/download 下载完之后&#xff0c;安装的时候一直点next即可&#xff0c;也可以根据自己的需求进行勾选 二.环境变量的配置 这两个文件可以 自…