目录
引言
C++博大精深,不过对于算法竞赛,我们只需要使用其中很少的特性。本篇仅针对算法竞赛介绍,帮助C到C++过渡。
C++过渡
1-1 万能头文件
#include<bits/stdc++.h>
using namespace std;
第一行:在程序前敲上这串,就不用再记头文件了。
第二行:接下来介绍的函数中,如std::cin,std::cout,以及STL中的std::vector等,需要这行代码以省去“std::”的部分。
总之记住这两行就对了。
温馨提醒:仅算法竞赛。未来做项目老老实实敲头文件。
1-2 cin,cout
这是输入与输出,相比C而言最大的优势是不用再记%d、%s等占位符。
int a, b;
scanf("%d%d", &a, &b);//C版本
cin >> a >> b;//C++版本
printf("%d %d\n", a, b);//C版本
cout << a << " " << b << endl;//C++版本
cin/cout注意箭头方向。endl可以记忆为“endline”缩写。
1-3 &引用
C语言在函数内对实参的操作通过指针实现,而C++提供了“引用”。(不觉得没有指针的代码更自然吗)
//C版本
void swap2(int *x, int *y) {
int temp = *x;
*x = *y;
*y = temp;
}
//C++版本
void swap2(int &x, int &y) {
int temp = x;
x = y;
y = temp;
}
为什么不叫“swap”?因为C++自带的swap函数不仅可以交换int,double等,甚至还可以交换结构体。我们很快就会学到如何编写这样强大的函数。
1-4 字符串
C++提供一个可被cin/cout直接读写的字符串类型:string类型。当用cin读取时遇空格视为结束。想读取整行可用getline()。
#include<bits/stdc++.h>
using namespace std;
int main(){
string line;
while(getline(cin, line)){//相当于C的fgets
int sum = 0, x;
stringstream ss(line);//创建"字符串流"(类似于cin)
while(ss >> x){
sum += x;
cout << sum << endl;
}
}
return 0;
}
1-5 范围for循环
通过类似for(int a: b)的形式可以从头到尾访问b容器。
#include<bits/stdc++.h>
using namespace std;
int main(){
string line{"abcde"};
for(char a : line){
a = toupper(a);//转大写,tolower()转小写
cout << a;
}
cout << endl;
cout << line << endl;//看看结果?
return 0;
}
需要修改容器中的元素,或者你想避免复杂类型对象的不必要拷贝时,应该使用&。
#include<bits/stdc++.h>
using namespace std;
int main(){
string line{"abcde"};
for(char &a : line){//使用&
a = toupper(a);
}
cout << line << endl;
return 0;
}
不需要修改容器中的元素,且元素类型是复杂类型(如std::string或用户定义的类)时,最好使用const &,可以避免不必要的拷贝。
#include<bits/stdc++.h>
using namespace std;
struct Person {
string name;
int age;
};
int main() {
vector<Person> people = {//vector是变长数组
{"Alice", 30},
{"Bob", 25},
{"Charlie", 35}
};
for (const auto &person : people) {
cout << person.name << " is " << person.age << " years old." << endl;
}
return 0;
}
当然,完全可以使用传统形式:
#include<bits/stdc++.h>
using namespace std;
int main() {
string line = "Hello, World!";
for (size_t i = 0; i < line.length(); ++i) {//对于.length(),.begin等其返回值为size_t类型
line[i] = tolower(line[i]);
}
cout << line << endl;
return 0;
}
1-6 构造与重载
#include<bits/stdc++.h>
using namespace std;
struct Point {
int x, y;
// 带有默认参数的构造函数
Point(int x=0, int y=0) : x(x), y(y) {}//觉得难以理解可以试试y(y), x(x) 以及 x(y), y(x) 会发生什么
};
// 重载+运算符,使其能够处理Point对象的加法
Point operator+(const Point& A, const Point& B) {//不修改地引用传递参数以避免不必要的复制,特别是对于大型对象。
return Point(A.x + B.x, A.y + B.y);
}
// 重载<<运算符以输出Point对象
ostream& operator<<(ostream& out, const Point& p) {
out << "(" << p.x << "," << p.y << ")";
return out;
}
int main() {
Point a, b(1, 2);//此时a为(0, 0)
a.x = 3;
cout << a + b << endl;
return 0;
}
上段代码展示了构造函数与重载操作符的部分特性(冰山一角)。看不懂没关系,在未来很长的一段时间内,读者完全可以避开这些用法。在一段时间的沉淀后,欢迎深入研究它们的特性。
1-7 模板
看一个简单点函数:
int add(int a, int b){
return a+b;
}
函数没什么问题,但有局限——double怎么办?我们的Point数组(1-6)怎么办?
我们稍作修改:
template <typename T>
T add(T a, T b){
return a+b;
}
这样,我们就造了一个“万能”函数。
练习
2-1
函数reverse()可以实现反转。现在你不能直接使用,尝试用所学知识编写相同功能:要求对于一行任意输入,输出其反转后的字符串。
2-2
完成任意数据类型Point数组(1-6)(同类型)相加。
提示:Point</*此处可定义类型*/>
int main(){
Point<int> a(1,2), b(3,4);
Point<double> c(1.1, 2.2), d(3.3, 4.4);
cout << a+b << " " << c+d << endl;
return 0;
}//请补充代码