2022年6月28日,开始自学算法竞赛的第一天,用书《算法竞赛入门经典(第二版)》,在此之前有一年的C/C++学习基础。本篇记录C过渡至C++的特殊用法,补充进阶使用,为明日的STL学习衔接。
目录
C++版程序框架
头文件
C++流
std名称空间
其他
引用
字符串
结构体
模板
C++版程序框架
头文件
将一个简单的C++程序和C程序比较,可以发现C++与C很多头文件不同。C中.h后缀的头文件依然存在,但C++更推荐使用开头带c的头文件,如:
| C语言头文件 | C++头文件 | 作用 |
| stdio.h | cstdio | (standard input & output) 标准输入输出 |
| math.h | cmath | 声明使用标准库中的math.h文件,数学运算 |
| ctype.h | cctype | 定义测试字符值(C语言字符分类函数) |
| string.h | csting | 定义字符数组函数 |
C++中还有一些特有的头文件,如 iostream 提供输入输出流;algorithm 提供常用算法(如取最大值函数max / 取最小值函数min)等。
C++流
相比较于C语言中的scanf,C++中使用 cin>>a 从标准流输入中读取a,返回值是“已经读取a的新流”,并可以从新流中继续读取下一个数据——所以可以写成 cin>>a>>b。
据此很容易联想到类的流运算符重载,如果想要直接使用 cin>>var_class,其中var_class是一个类的对象,需要对流运算符重载。听起来这个想法有点逆天(怎么可以直接cin一个类呢??),具体代码如下:
class Array{ //声明一个叫class类叫做Array
public: //公有成员
friend istream& operator>>(istream& is, Array& t); //声明一个流运算符重载函数函数
.... //可能会有其他公有成员
private:
int a; //假设有一个私有成员a
};
//流重载函数的体外实现
istream& operator>>(istream& in, Array & t)
{
in >> t.a;
return in; //返回值为流本身
}
int main(){
Array var1,var2; //定义Array类的对象名叫var1/var2
//由于定义了流重载,可以不写构造函数初始化,或另外写成员函数进行赋值
cin>>var1; //可以只输入一个
cin>>var1>>var2; //由于第一次输入的返回值是流对象本身,所以可以继续第二次输入
//同理,也可以使用输出流重载
return 0;
}
可以看到在重载函数的具体实现中,也是遵循了C++流“返回值为已经读取的新流”,所以可以重复输入。类的流运算符重载和本篇无太大关系(扯远了),仅作复习。
C++流的好处是,可以直接套while循环,判断语句为cin>>a,流读完后循环会自动退出,相比之下C语言需要在scanf中添加%d、%s等占位符。且C++流完美避开了long long型输入输出占位符不统一的情况。
C++流的缺点是运行速度太慢,输入量大时尽量不要使用。
补充:流也可以加速,方法是关闭和stdio的同步,即调用以下代码:
ios::sync_with_stdio(false)
std名称空间
C++中头文件下方通常有一句 using namespace std ,其中“namespace”就是指的名称空间,缓解复杂程序的组织问题。
一般头文件里定义的内容放在std名称空间里,可以使用 std::cin / std::cout ;也可以使用 using namespace std 将std里的名字导入默认空间,前提是下面代码和这段std空间里的内容不重名。
总结一下,C++可以使用流简化输入输出操作。标准输入输出流在头文件 iostream 中定义,存在名称空间 std 中。如果使用了 using namespace std,可以直接使用。
其他
C++中有 bool 类型而C语言中没有。
引用
函数参数名前加上“&”,表示这个参数按照传引用的方式传递。通过gdb调试可发现函数执行时使用形参的地址就是原实参地址。引用就是变量的“别名”,指的还是变量本身,传引用可以在函数内直接修改实参。
引用比较方便的例子是自行实现的swap交换函数,代码如下:
void swap2(int& a,int& b){ //形参是指针
int t=a;
a=b;
b=t; //进行三参数的数据交换
}
//使用时参数位置直接写参数本身即可(不需要使用地址)
当然系统内置的 swap 函数功能更加强大。可以进行所有内置类型及结构体(结构体交换记得用!)。
字符串
C语言中使用字符数组“模拟”字符串,C++中使用 string 字符串。好处是可以直接用 cin/cout 读写,甚至可以直接相加以实现字符串拼接(而C中需要使用strcat)。
以下代码为例,解决的是每一行输入多个整数并用空格分开,求每行整数和的问题:
#include#include #include using namespace std; int main() { string line; //需要头文件string while (getline(cin, line)) { //读取一行 int sum = 0, x; stringstream ss(line); //需要头文件sstream,表示字符串流 while (ss >> x) sum += x; cout << sum << "n"; } }
可以使用 getline 函数读取一行数据,再为这一行创建字符串流,然后就像读取cin一样读取ss即可,每一个字符串流中的内容就会想一个个读整数一样。
可以将 string 作为流进行读写,定义在 sstream 头文件中。
string 和 sstream 都很慢,仔细一想好像C++特有的东西都比较慢(乐。
结构体
struct 结构体和 class 类使用方法类似,结构体更注重于储存数据,类更注重于数据处理。
其中 struct 运算符重载时函数不需要成为友元(也没办法成为),为结构体中没有public及private之分。
模板
当函数参数需要多种类型都适用时,建议使用模板:
template... //函数返回类型/形参类型/内部自动变量类型都可以设为T,以适应不同数据类型。
函数模板和函数重载最大的不同时,函数模板仅能解决参数个数相同但类型不同的情况(从而引入模板T代替具体类型),而函数重载解决的是参数个数不同(从而可以直接根据参数个数匹配函数)。
同理结构体和类也可以带模板。
今日完,明学习STL初步



