当前位置: 首页 > news >正文

C++(运算符重载)

 一.友元

C++中使用关键字friend可以在类外访问所有的成员,包括私有成员(之前提到过封装的核心思想是隐藏内部实现细节,通过公共接口控制访问),所以友元可以突破封装的限制访问数据,盲目使用会导致程序稳定性降低,所以使用友元必须慎重。

友元分类:

        友元函数

        友元类

        友元成员函数

1.友元函数

全局函数访问私有成员,可以配合运算符重载使用,友元函数是一种在类内“声明”,类外定义的非成员函数,但是没访问类内所有的成员。友元函数可以做到修改私有成员变量

注意:

(1)友元函数没有this指针。

(2)友元函数可以在类的私有部分,也可以在类的公有部分。
(3)一个函数可以是多个类的友元函数,只需要在不同的类汇中声明。

#include <iostream>
#include <string>using namespace std;class Techer{
private:int age = 45;string name = "zhangsna";
public:Techer(int age,string name):age(age),name(name){}//Techer():age(45),name("lisi"){}int get_age()const{return age;}string get_name()const{return name;}void print()const{cout << get_age() << endl;cout << get_name() << endl;}int print_age(){return 18;}friend void print_real_age(Techer &t);                //类内声明友元函数
};void print_real_age(Techer &t){                            //类外定义友元函数cout << "真实年龄:" << t.age << endl;cout << "虚假年龄:" << t.print_age() << endl;t.age = 30;cout << "修改年龄:" << t.age << endl;
}int main (){Techer t1(34,"zhangsan");cout << t1.print_age() << endl;print_real_age(t1);return 0;
}

2.友元类

当B是A的友元类时,类B就可以访问类A的所有成员,

需要注意的是:

        (1)友元类不具备交换性:A声明B为友元 → B可访问A的私有成员,但A不能访问B的私有成员。

        (2)友元类不具备传递性:A是B的友元,B是C的友元 → A不是C的友元。

        (3)友元类不具备继承性:基类友元不会继承给派生类。

#include <iostream>
#include <string>using namespace std;class Techer{
private:int age = 45;string name = "zhangsna";
public:Techer(int age,string name):age(age),name(name){}//Techer():age(45),name("lisi"){}int get_age()const{return age;}string get_name()const{return name;}void print()const{cout << get_age() << endl;cout << get_name() << endl;}int print_age(){return 18;}friend class student;
};class Student{
public:void get_name(Techer &t){cout << t.get_name() << endl;}
};int main (){Techer t1(34,"zhangsan");Student s1;s1.get_name(t1);return 0;
}

 友元成员函数

#include <iostream>
#include <string>using namespace std;class Techer; //声明类class Student{
public:void print_name(Techer &t);
};class Techer{
private:int age = 45;string name = "zhangsna";
public:Techer(int age,string name):age(age),name(name){}//Techer():age(45),name("lisi"){}int get_age()const{return age;}string get_name()const{return name;}void print()const{cout << get_age() << endl;cout << get_name() << endl;}int print_age(){return 18;}friend void Student::print_name(Techer &t);           //1.友元声明
};//4.实现友元函数
void Student::print_name(Techer &t){cout << t.get_name() <<endl;
}int main (){Techer t1(34,"zhangsan");Student s1;s1.print_name(t1);return 0;
}

二.函数运算符重载

C++中函数是可以重载的运算符也是一种特殊的函数,也可以重载,这样一来,本来只能基本数据类型能做的加减乘除也可以让对象直接加减乘除。

函数的三要素是:函数名,参数和返回值。

下面就是C++中运算符+含义,所以我们对+函数进行重载,就可以实现对象之间相加。

可以被重载的运算符:(了解)
        算术运算符: +、-、*、人、%、++、--
        位操作运算符:&、|、~、^(位异或)、<<(左移)、>>(右移)
        逻辑运算符:!、&&、
        比较运算符:<、>、>=、《=、==、!=
        赋值运算符:=、+=、-=、*=、/=、%=、&=、 I=、^=、《<=、>>=
        其他运算符:范、0、->、、new、delete、new[、delete[
不被重载的运算符:
        成员运算符""、指针运算符“*”、三目运算符"?:“、sizeof、作用域""

1.使用友元函数运算符重载

函数名:+

参数:const Integer &i1和const Integer &i2

返回值:Inteder

    friend Integer operator +(const Integer &i1,const Integer &i2);
#include <iostream>
#include <string>using namespace std;class Integer{
private:int value;
public:Integer(int value):value(value){}int get_value()const{return value;}void set_value(int a){value = a;}friend Integer operator +(const Integer &i1,const Integer &i2);friend Integer operator ++(Integer &i);friend Integer operator ++(Integer &i,int);
};Integer operator +(const Integer &i1,const Integer &i2){return i1.value + i2.value;                //返回两个int类型,这个时候编译器会自动帮你创建一个Integer类型的副本,类似于:return Integer(i1.value + i2.value);
}
Integer operator ++(Integer &i){return ++i.value;
}
Integer operator ++(Integer &i,int){return i.value++;
}int main (){Integer i1(3);Integer i2(4);Integer i3 = i1 + i2;cout << i3.get_value() << endl;++i3;cout << (i3++).get_value() << endl;cout << i3.get_value() << endl;return 0;
}

2.使用成员函数运算符重载

简单三步实现:(投机取巧的方式)

        (1).把友元函数实现的代码的friend去掉

        (2).再把所有传入的第一个参数去掉,函数内使用this指针替换(不加也可以,编译器自动识别)

        (3).在函数名前加上作用域限定符(Integer::)

正常直接写,就是写成员函数的步骤。

#include <iostream>
#include <string>using namespace std;class Integer{
private:int value;
public:Integer(int value):value(value){}int get_value()const{return value;}void set_value(int a){value = a;}Integer operator +(const Integer &i);Integer operator ++();Integer operator ++(int);
};Integer Integer::operator +(const Integer &i){return value + i.value;
}
Integer Integer::operator ++(){return ++value;
}
Integer Integer::operator ++(int){return value++;
}int main (){Integer i1(3);Integer i2(4);Integer i3 = i1 + i2;cout << i3.get_value() << endl;++i3;cout << (i3++).get_value() << endl;cout << i3.get_value() << endl;return 0;
}

3.特殊运算符重载

3.1复制运算符重载

如果程序员不手写赋值运算符重载函数,则编译器会自动为每个类增加一个赋值运算符重载函数。

在 C++ 中,赋值运算符(operator=必须被重载为类的成员函数,而不能作为友元函数或全局函数。这一设计决策源于 C++ 语言的核心特性:

(1)、根本原因:语言规范要求

C++ 标准(ISO/IEC 14882)明确规定:赋值运算符(=)必须被声明为类的非静态成员函数这是语言规范层面的硬性规定,违反此规则将导致编译错误。

(2)、技术原因:this 指针机制
1. 成员函数的隐式 this 指针
  • 成员函数自动获得隐式 this 指针,指向调用对象

  • 赋值操作需要修改左操作数的状态,this 提供直接访问

2. 友元函数缺少 this 指针
  • 友元函数没有隐式 this 指针

  • 必须显式声明两个参数(左操作数和右操作数)

  • 违反赋值运算符的二元操作符语法形式

#include <iostream>
#include <string>using namespace std;class String{
private:string str;
public:String(string str):str(str){}string get_str(){return str;}void set_str1(string str){this->str = str;}String& operator =(const String& a){        //系统默认自带的this->str = a.str;return *this;}
};int main (){String s1("hello ");String s2("world");s1 = s2;cout << s1.get_str() << endl;return 0;
}

3.2类型转换运算符重载

如果我们想把string类型转换为成员变量,如果正好你的成员变量只有一个string类型的成员变量,这个时候编译器会自动帮你赋值优化,String s1 = name;就不会报错,但是你要是想把s1对象赋值给string类型的name,这个时候编译器就无法识别,需要使用成员函数进行重载。

可以把注释的部分去掉,错误就没了,注视部分就是类型转换重载。

#include <iostream>
#include <string>using namespace std;class String{
private:string str;
public:String(string str):str(str){}string get_str(){return str;}void set_str1(string str){this->str = str;}/*operator string(){return str;}*/
};int main (){String s1("hello ");String s2("world");s1 = s2;string name = s1;cout << name << endl;cout << s1.get_str() << endl;return 0;
}

4.注意:

1.重载的运算符只能对C++语言中已有的运算符进行操作,不能创建新的运算符;

2.运算符重载也是函数重载;

3.运算符不能改变运算符的优先级(*的优先级比+大,不能改变)和结合性(a*b就是a*b不能ab*运算),也不能改变操作数和语法结构;

4.运算符重载函数不支持默认参数,即运算符的操作数数量固定(如二元运算符需要两个操作数)

5.运算符重载函数的操作数中一定包含自定义类型(运算符重载函数的操作数中必须至少有一个是用户定义类型

三.string字符串常用手册

C++函数手册:

通过网盘分享的文件:C++函数手册 (LibraryFunctions).chm
链接: https://pan.baidu.com/s/17gE3aR6VQhQQ10tBZNFfHg 提取码: 3589

#include <iostream>
#include <string.h>using namespace std;int main()
{string s1 = "ABC";// 隐式调用了下面的,参数为const char*string s2("ABC");string s3 = s2; // 拷贝构造函数cout << s3 << endl; // ABC// 参数1:const char*// 参数2:保留前几个字符string s4("ABCDE",2);cout << s4 << endl; // ABs1 = "ABCDE";// 参数1:string// 参数2:不保留前几个字符string s5(s1,2);cout << s5 << endl; // CDE// 参数1:字符数量// 参数2:字符内容string s6(3,'Z');cout << s6 << endl; // ZZZswap(s5,s6);cout << s5 << " " << s6 << endl; // ZZZ CDE// 向后追加字符串cout << s1.append("...").append(s5) << endl;// 向后追加单字符s6.push_back('O');cout << s6 << endl; // CDEO// 参数1:插入的位置// 参数2:插入的内容s6.insert(1,"222");cout << s6 << endl;// 参数1:删除的起始位置// 参数2:删除的字符数s6.erase(1,3);cout << s6 << endl;// 参数1:替换的起始位置// 参数2:替换的字符数// 参数3:替换的字符s6.replace(0,3,"xxxxxxx");cout << s6 << endl;s6.clear(); // 清空// 判断是否为空cout << s6.empty() << endl; // 1char c[20];s6 = "ABCDEFG";// 参数1:拷贝的目标// 参数2:拷贝的字符数// 参数3:拷贝的起始点s6.copy(c,2,3);cout << c << endl;char c2[20];s6 = "ABCDEFG";// c_str返回的char*指向一个内部数组,相对不可控cout << s6.c_str() << endl;// 因此需要拷贝出来strcpy(c2,s6.c_str());cout << c2 << endl;return 0;
}

练完后会不会有个疑问,为什么string有这么多操作,之前说过他不是基本数据类型,因为它就是C++中定义好的类。

http://www.lryc.cn/news/572189.html

相关文章:

  • 2025虚幻引擎文件与文件夹命名规律
  • 代理 AI 时代的隐私重构:从边界控制到信任博弈
  • MySQL RC隔离级别惊现间隙锁:是bug吗?
  • 如何在中将网络改为桥接模式并配置固定IP地址
  • openLayers切换基于高德、天地图切换矢量、影像、地形图层
  • Zabbix监控系统安装部署(图文)
  • Linux简单了解以及VM虚拟机的安装使用(后端程序员)
  • 探秘阿里云EBS存储:云计算的存储基石
  • LINUX 619 NFS rsync
  • 深度学习-164-MCP技术之开发本地MCP服务器和异步客户端
  • LTC3130EMSE#TRPBF ADI电子元器件深度解析 物联网/工业传感器首选!
  • AWS GuardDuty邮件推送设置
  • 刘波卸任OPPO法定代表人、经理等职务,段要辉“接棒”
  • C++ 互斥量
  • 【Python】python系列之函数作用域
  • 微信小程序获取指定元素,滚动页面到指定位置
  • Maven镜像
  • ssh配置sftp,实现上传下载文件
  • uni-app总结4-项目配置+HBuilder插件使用+uni插件使用
  • 正则表达式一些例子
  • 视频续播功能实现 - 断点续看从前端到 Spring Boot 后端
  • 【Bug:docker】--Docker同时部署Dify和RAGFlow出现错误
  • web3 浏览器注入 (如 MetaMask)
  • 无人机电调技术要点与突破解析!
  • 插值与模板字符串
  • 宇鹿家政服务系统小程序ThinkPHP+UniApp
  • Spring Boot 工程启动以后,我希望将数据库中已有的固定内容,打入到 Redis 缓存中,请问如何处理?
  • WEB安全--WAF的绕过思路
  • Flutter中FutureBuilder和StreamBuilder
  • 对gateway和nocas的理解