52. 操作符重载(上)

使用C++标准库

C++标准库简介

  • C++标准库并不是C++语言的一部分

  • C++标准库是由C++语言编写而成的类库和函数的集合

  • C++标准库中定义的类和对象都位于std命名空间中

  • C++标准库的头文件都不带.h后缀

  • C++标准库涵盖了C库的功能

    • C库中<name.h>头文件对应C++中的<cname>

    • C库中<stdio.h>头文件对应C++中的<cstdio>

C++标准库预定义了多数常用的数据结构

如:字符串,链表,队列,栈等

  • <bitset>库是C++标准库中的一个头文件,它提供了一个固定大小的位集容器。bitset通常用于处理位操作,如设置、清除、翻转、测试某一位的值等。它常常在低级编程或需要紧凑存储的场景中使用。

  • <deque>deque(双端队列)是一个双向队列,允许在其两端快速插入和删除元素。它提供比vector更高的性能,尤其是在前端插入和删除时。

  • <list>list是一个双向链表,元素在内存中不是连续存储的。因此,插入和删除操作通常比vector或deque更快,但访问特定元素的速度较慢。

  • <map>map是一个关联容器,它存储的元素是键值对(key-value pair)。元素总是按键的顺序存储,并且可以通过键快速访问对应的值。

  • <queue>queue是一个先进先出(FIFO)的数据结构。它允许在尾部添加元素,并从头部移除元素。queue通常用于实现任务队列或消息队列。

  • <set>set是一个关联容器,包含唯一元素。元素在set中自动按键的顺序排序。

  • <stack>stack是一个后进先出(LIFO)的数据结构。它允许在顶部添(push)和移除(pop)元素。

  • <vector>vector是一个动态数组,可以容纳多个元素。与静态数组不同,vector的大小可以在运行时改变。vector在内存中是连续存储的,因此可以高效地访问其元素。

C++中的输入输出

#include <iostream>//C++标准库的头文件都不带.h后缀

//C++标准库中定义的类和对象都位于std命名空间中
using namespace std;//使用命名空间std

int main()
{
	/*
		cout<<"Hello World"<<endl;
		把"Hello World"这个字符串左移到cout这个对象上面
		cout是C++标准库用于表示显示器的对象
		所以代码是把"Hello World"左移到显示器上面
		然偶再把endl左移到cout,实现换行
	*/
	cout<<"Hello World"<<endl;

    int x;
	int y;

	/*
		cin>>x;
		cin代表键盘对象,将键盘的输入右移到变量x里面去
		在键盘上输入一个数,将这个数右移到变量x里面去
	*/
	cout<<"1st Parameter: ";
	cin>>x;

	cout<<"2nd Parameter: ";
	cin>>y;

	cout<<"Result: "<<x+y<<endl;

	return 0;
}

C++做了什么

左移运算符<<和 右移运算符>>在C语言中只能用于整数运算,并且语义是确定不变的

C++是怎么改变左移运算符和右移运算符的语义的?

操作符重载

函数重载:一个相同的函数名,当他处于不同的上下文,他将表现出不同的行为

操作符重载为操作符提供不同的语义

加法能用于整数,浮点数,不能用于两个结构体

#include <cstdlib>
#include <iostream>

using namespace std;

struct Complex//复数结构体
{
    int a;
    int b;
};

int main(int argc, char *argv[])
{
    Complex c1 = {1, 2};
    Complex c2 = {3, 4};
    Complex c3 = c1 + c2;//ops!加法能用于整数,浮点数,不能用于两个结构体
    
    cout << "Press the enter key to continue ...";
    cin.get();//cin是键盘对象,肯定有自己的成员函数,cin.get();从键盘获取一个值
    return EXIT_SUCCESS;
}

可以定义一个add函数用于两个Complex的相加

#include <cstdlib>
#include <iostream>

using namespace std;

struct Complex
{
    int a;
    int b;
};

Complex add(const Complex& c1, const Complex& c2)
{
    Complex ret;
    
    ret.a = c1.a + c2.a;
    ret.b = c1.b + c2.b;
    
    return ret;
}

int main(int argc, char *argv[])
{
    Complex c1 = {1, 2};
    Complex c2 = {3, 4};
    Complex c3 = add(c1, c2);
    
    cout<<"c3.a = "<<c3.a<<endl;
    cout<<"c3.b = "<<c3.b<<endl;
    
    cout << "Press the enter key to continue ...";
    //cin是键盘对象,肯定有自己的成员函数,cin.get();从键盘获取一个值
    cin.get();//效果等同于getchar();
    return EXIT_SUCCESS;
}
result:
c3.a = 4
c3.b = 6
Press the enter key to continue ...

add函数可以解决Complex变量相加的问题,但是Complex是现实世界中确实存在的复数,并且复数在数学中的地位和普通的实数相同,为什么不能让+操作符也支持复数相加呢?

C++中操作符重载的本质

  • C++中通过operator关键字可以利用函数扩展操作符

  • operator的本质是通过函数重载实现操作符重载

结构体用operator关键字扩展的操作符

用operator关键字扩展的操作符可以用于类吗?

C++中的类的友元

  • private声明使得类的成员不能被外界访问

  • 但是通过friend关键字可以例外的开放权限

例:重载左移运算符

#include <cstdlib>
#include <iostream>

using namespace std;

class Complex
{
    int a;
    int b;
public:
    Complex(int a = 0, int b = 0)
    {
        this->a = a;
        this->b = b;
    }
    
    int getA()
    {
        return a;
    }
    
    int getB()
    {
        return b;
    }
    
    friend Complex operator+ (const Complex& c1, const Complex& c2);
    friend ostream& operator<< (ostream& out, const Complex& c);
};

//★重载左移运算符★ ostream是显示器对象cout的类型
ostream& operator<< (ostream& out, const Complex& c)
{
    out<<c.a<<" + "<<c.b<<"i";
    
    return out;
}

//★重载加号★
Complex operator+ (const Complex& c1, const Complex& c2)

{
    Complex ret;
    
    ret.a = c1.a + c2.a;
    ret.b = c1.b + c2.b;
    
    return ret;
}

int main(int argc, char *argv[])
{
    Complex c1(1, 2);
    Complex c2(3, 4);
    Complex c3 = c1 + c2;//本质是函数调用
    
    cout<<c1<<endl;
    cout<<c2<<endl;
    cout<<c3<<endl;
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}
result:
1 + 2i
3 + 4i
4 + 6i
Press the enter key to continue ...

这里为什么引用返回out?为什么返回一个ostream的引用?

//★重载左移运算符★ ostream是显示器对象cout的类型
ostream& operator<< (ostream& out, const Complex& c)
{
    out<<c.a<<" + "<<c.b<<"i";
    
    return out;
}
  • 在C++标准库里定义了很多类似的操作符重载函数

  •     且他们的原型都是ostream&

  •     把ostream&改成void,operator<<(cout,c1);是可以编译过运行的,cout<<c1;也是可以运行的,cout<<c1<<endl;编译不过了

  •     原因:(cout<<c1)<<endl;先做括号里的操作,(operator<<(cout,c1))<<endl;括号里执行函数调用操作但函数类型是void

  •     因此这里使用ostream&,直接返回cout,支持链式调用

//cout<<c1;等价于operator<<(cout,c1);
//(cout<<c1)<<endl 即 (operator<<(cout,c1))<<endl

文心一言给出的解释:

返回out的引用。这是非常重要的,因为它允许链式操作。例如,cout << obj1 << obj2;会首先调用operator<<输出obj1,然后返回cout的引用接着用这个引用调用operator<<输出obj2即:(cout << obj1) << obj2;括号执行完后返回cout;然后cout<<obj2;完成链式调用

返回out的引用而不是其他类型(如void或Complex)的原因是为了支持链式操作。如果返回void,则不能继续对同一输出流进行操作。如果返回Complex或其他类型,则链式操作将不再有意义,因为你不能将一个Complex对象与另一个ostream对象进行连接。

所以,返回ostream&(即输出流的引用)是为了让这个运算符的行为与内置类型的operator<<保持一致,并支持链式操作

C++是怎么改变左移运算符和右移运算符的语义的?

C++中的操作符重载可以改变左移和右移运算符的语义!

小结

操作符重载是C++的强大特性之一

操作符重载的本质是通过函数扩展操作符的语义

operator关键字是操作符重载的关键

friend关键字可以对函数或类开发访问权限

操作符重载遵循函数重载的规则

  • 24
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值