使用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<<保持一致,并支持链式操作。