Featured image of post C++

C++

环境

编译

  • gcc主要编译C语言,对于C++代码只编译而不自动链接C++标准库,需要使用-lstdc++指定
  • g++专门编译C++代码,自动链接C++标准库
1
./a.out <infile> outfile # 文件重定向, infile文件中为输入

基础

关键字

extern:只声明变量,由外部定义

int型最大值最小值

1
INT_MAX, INT_MIN // limits.h

显示访问全局变量:::a

类型

引用:必须初始化

模板

1
2
3
4
5
6
7
template<typename T>
T func(T arg){
	return T;
}

// 调用
cout << func<int>(1);// 不输入<int>由编译器自己判断

同样适用于类,类模版实例化需输入<type>告诉编译器类型

数组

1
2
3
4
5
6
7
8
// 动态分配数组
int* array = new int[num];   // 不初始化为0
int* array = new int[num](); // 初始化为0

delete[] array;

// 创建静态数组
int arr[num];

矩阵

二维数组,(n+1) * (m+1) 矩阵

1
2
vector<vector<bool>> f(n + 1, vector<bool>(m+1), -1);
//矩阵f, n+1 行, 每行初始化为vector<bool>(m+1) 即 m+1 列, 每个初始化为-1

结构体

定义

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
struct animal {
	int num;
	
	animal(int n): num(n){} //构造函数
    bool operator < (animal a) const{ // 重载函数
        return xxx;
    }
};

animal a(1);
1
2
3
4
5
6
7
const int N = 1000;
struct Q {
  int x;
  int y;
} que[N];

que[idx] = {t.x, t.y};

字符串

  • 库类型std::string,可变长字符序列

初始化

1
2
3
4
5
string s("Hello");
string s1("hello", 3); // hel
string s2("hello", 2, 2); // start, size : ll
string s3(5, 'a'); // aaaaa
string s4({'a','b','c'}); // abc
1
2
3
4
5
s1.assign(s2); // s1 = s2
s1.assign("h"); // s1: h
s1.assign("hello", 3); // s1: hel
s1.assign(3, 'x'); // s1:"xxx"
s1.assign({'a','b'}); // s1: "ab"

长度

1
2
3
4
5
6
7
int n = s.size(); // s.length()
int c = s.capacity(); // 存储空间大小

s.reserve(num); // num < capacity 不改变, > capacity 则容量改变
s.shrink_to_fit(); // 压缩存储空间大小

s.resize(20, 'x'); // 重置大小为20, 不够填充'x', 默认0

迭代器访问

1
2
3
4
5
6
7
8
for(string::iterator it = str.begin(); it != str.end(); ++it){
	*it = ' '; // 更改值
}

string n;
for(char &itr : n){
    itr--; // 字符减一
}

取值

1
2
s.front(); // 第一个字符
s.back(); // 最后一个字符

插入

1
2
3
4
5
6
7
8
s.insert(s.begin(), ' '); // 开头插入空格
s.insert(2, 3, 'x'); // 在索引2处插入3个'x'
s.insert(3, "hello"); // 在索引3处插入"hello"

s.push_back('z'); // 末尾加入元素
s.append("xx"); // 末尾加入string字符串

string str = str1 + str2; // 拼接

获取一行字符串

1
2
while(getline(cin, str)); // 字符串中可包含空格
getline(cin, s, ';'); // 停止界定符

转换为cstring

1
2
3
str = "abc";
str.c_str(); // "abc\0"
str.data(); // "abc"

number转换为string

1
s = to_string(8); // 2.3e7

string转换为number

1
2
3
4
5
6
7
s = "190";
int i = stoi(s); // 190

s = "190 hello";
size_t pos;
i = stoi(s, &pos); // i:190 pos=3指向非number
// stol:to long, stod: to double, stof: to float

查找

1
2
3
4
5
6
size_t found = str.find("xx"); // 找不到返回string::npos, 找到返回下标
found = s.find("u", 2, 4); // 从索引2开始找字符串前4的子串

s.find_first_of("abc");
s.find_first_not_of("abc");
s.find_last_of("abc");

删除

1
2
3
4
5
6
7
8
9
// 去除字符串前后空格
str.erase(0, str.find_first_not_of(" ")); // 找不到返回string::npos
str.erase(str.find_last_not_of(" ") + 1);

str.erase(start, size);
str.erase(itr, itr+5);
str.pop_back();

str.clear(); // 清空元素

交换

1
2
s1.swap(s2); // 交换2个字符串
swap(str[0], str[2]); // 交换2个字符

替换

1
2
3
str.replace(2, 3, "re"); // 从索引2开始的3个元素更改为"re"
str.replace(2, 3, 4, 'y'); // 从索引2开始的3个元素被替换插入4个'y'
replace(str.begin(), str.end(), 'e', ' '); // 替换字母

比较

1
2
3
4
5
if(str >= "10"); // 代表数字字符串可直接比较

// 相等返回0, 不匹配的第一个字符值低或字符匹配但字符串短<0, 不匹配第一个字符值大或字符串长>0
int ret = s1.compare(s2);
s1.compare(start, num, s2); // s1从start开始与s2比较num个字符

子串

1
sub_str = str.substr(2, 3); // 从索引2开始的3个字符拷贝

拷贝

1
2
3
4
s = "abcdefg"
char buf[20];
size_t len = s.copy(buf, 3); // buf: abc, len=3
len = s.copy(buf, 4, 2); // buf: cdef, len=4 从索引2开始拷贝4个

链表

结构体

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
typedef struct ListNode
{
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(nullptr) {}
    ListNode() : val(0), next(nullptr) {}
    ListNode(int x, ListNode *next) : val(x), next(next) {}
};

void printLinkList(ListNode *head)
{
    ListNode *current = head;
    while (current != nullptr)
    {
        std::cout << current->val << " -> ";
        current = current->next;
    }
    std::cout << "nullptr" << std::endl;
}

ListNode *initLinkList(int arr[], int n)
{
    if (n == 0)
    {
        return nullptr;
    }

    ListNode *head = new ListNode(arr[0]);
    ListNode *current = head;

    for (int i = 1; i < n; ++i)
    {
        current->next = new ListNode(arr[i]);
        current = current->next;
    }

    return head;
}

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class ListNode {
public:
    int val; // 节点的值
    ListNode *next; // 指向下一个节点的指针

    ListNode(int x) : val(x), next(nullptr) {} // 构造函数
    ListNode(int x){
        xxxx;
    }
};

创建

1
2
3
ListNode *temp = new ListNode(0), *cur = temp;	//虚拟头结点temp, cur指向temp

cur->next = new ListNode(l->value);			   	//创建一个新链表

判断指针是否为尾

1
while(ptr->next)

倒数第n个结点

快慢指针,使两指针移动相差n,快指针到结尾,则慢指针在倒数第n+1个结点

数据结构容器

数组

动态数组vector

定义

1
2
3
4
5
6
7
vector<type> name;

vector<int> pos(128, -1);// 初始化ASCII码共128个元素,每个元素值为-1

vector<pair<int,int>> tint; //每组为一对int型的数组
// 取数 tint[i].first, tint[i].second ...
vector<int> a({1,2,3});

判空

1
vector.empty()

元素个数

1
vector.size()

增删

1
2
vector.push_back({xx,xx,xx})
vector.pop_back()

清空

1
vec.clear()

拷贝构造

1
vector<type> vec2(vec);

设置大小及内容

1
vec.resize(size, 0); // 0为填充数据

交换两个vector容器内容

1
vec2.swap(vec);

首元素

1
vector<int>::iterator it = vector.begin()// 返回迭代器

尾元素

1
vector.end()// 返回置迭代器,最后元素的下一个位

首尾半开放:[begin, end)

迭代器

1
2
vector<type>::iterator it;
cout << *it << endl; //取值

取数

1
2
vec[1]
vec.at(1) // 若越界会抛出异常

遍历访问

1
2
3
for (auto it : vec)
    cout << it << endl;
// 遍历,it不需要提前声明,vec为vector<type>

修改

1
2
int *p = &vec[0]; // 赋值p为第一个值的内存地址
p[1] = 6; // 改变vec值

静态数组array

1
2
3
4
5
array<int, 3> a = {1,2,3};
a.begin();
a.end();
a.size();
a.swap();

队列

queue

定义

1
queue<type> q; // 定义

初始化

1
2
3
queue<tuple<int, int, int>> q;
q.emplace(x, x, x); // 容器内直接构造元素
auto [x, y, time] = q.front(); // 接收元素

基础操作

1
2
3
4
5
6
q.empty() // 判空
q.size() // 元素个数
q.front() // 队列头
q.back() // 队列尾
q.pop() // 删除
q.push() // 添加

deque双端队列

1
2
deq.push_front(2); // 前插入
deq.push_back(3); // 后插入

priority_queue优先队列

1
2
3
4
5
6
7
8
priority_queue<type> pq; // 大根堆
priority_queue<type, vector<type>, greater<type>> name; // 小根堆
/* struct cmp{
		bool operator() (ListNode* a, ListNode* b){
			return a->val > b->val;
		}
	}
*/

访问

1
2
3
4
heap.push(x) // 增加
heap.empty() // 判空
heap.top() // 头元素
heap.pop() // 弹出头元素

链表

list双向链表

初始化

1
list<int> li = {1, 2, 3};

插入

1
2
list<int>::iterator itr = find(l.begin(), l.end(), 2); // itr->2
list.insert(itr, 8); // 向itr指向值前方插入8

增删

1
2
// push_front push_back
l.erase(itr); // 删除itr指向值

遍历

1
2
3
4
for (auto it = mylist.begin(); it != mylist.end(); ++it){
	cout << *it << " ";
}
cout << endl;

集合

  • set:红黑树实现,自动排序,<>接收2参数:元素类型,比较器类型,每个值唯一,值不可修改
  • multiset:允许重复值,值不可修改
  • unordered_set:无序集合

定义

1
2
set<int> myset;
set<int, less<int>> s;

插入

1
2
3
pair<set<int>::iterator, bool> ret;
ret = myset.insert(2); // 若已有2,返回(it->2, false)
// ret.first, ret.second

查找

1
2
set<int>::iterator it;
it = myset.find(2);

删除

1
2
myset.erase(it);
myset.erase(value);

无序集合

1
2
3
4
5
6
7
unordered_set<int> aset;
aset.insert(xx);

// 检查
unordered_set<string>::const_iterator it = myset.find("hello");
if(it != myset.end())
    cout << *it << endl;

接口

1
2
3
myset.load_factor(); // 装载因子
myset.bucket(x); // x的索引
myset.bucket_count(); // 索引总数

哈希表

  • 键值对存储 pair类型,map
  • multimap:允许重复值,multimap和map的键不允许修改

定义

1
2
3
4
5
map<type t1, type t2> mp;
unordered_map<type1, type2> hp; // 无序哈希表
hp = {
	{x1, x2}, {y1, y2}
}; // 初始化

状态

1
2
3
4
5
6
7
8
9
mp.empty(); // 判空
mp.size(); // 元素个数
mp.begin(); // 返回迭代器
mp.end(); // 最后一个元素的下一位

// 取值
(*it).first;// 键
(*it).second;// 值
// *it的类型: pair<const type1, type2>

增删

1
2
3
4
5
6
7
map.insert(pair<type, type>(x1, x2)); // 添加,不可修改
map.insert(make_pair(x1, x2));

mp['a'] = "aa"; // 修改或插入

map.erase(); // 删除
map.clear(); // 清空

查找

1
2
mp.find(first, last, val); // [first, last)
if(mp.find(val) != mp.end()){找到val}

遍历

1
2
3
4
5
for(const auto& pair : mp){
	cout << pair.first << ": " << pair.second << endl;
}

for(const auto &[x, indices] : xmap)

1
2
#include<stack>
stack<int> sk

状态

1
2
sk.empty(); //是否为空
sk.size();  //元素个数

增删

1
2
sk.push(); //添加
sk.pop();  //删除

访问

1
sk.top(); //栈顶元素

二叉树

1
2
3
4
5
struct TreeNode{
	type value;
	TreeNode *leftChild;
	TreeNode *rightChild;
};

大根堆

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
make_heap(vec.begin(), vec.end());

pop_heap(vec.begin(), vec.end()); // 移除最大元素
vec.pop_back(); // 移除最大元素

push_heap(vec.begin(), vec.end()); // 加入新值
vec.push_back();

// 堆排序
sort_heap(vec.begin(), vec.end());

并查集

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class UnionSet{
private:
	vector<int> parent; // 父结点
    vector<int> deep; // 树深度
public:
    UnionSet(int n){
        parent.resize(n);
        deep.resize(n, 0);
        for(int i = 0; i < n; ++i){
            parent[i] = i;
        }
    }
    int find(int x){
        if(parent[x] != x){
            parent[x] = find(parent[x]); // 递归找根
        }
        return parent[x];
    }
    void union(int x, int y){
        int rootX = find(x);
        int rootY = find(y);
        if(rootX != rootY){
            if(rank[rootX] < rank[rootY]){
                rank[rootX] = rootY;
            }else if(rank[rootX] > rank[rootY]){
                rank[rootY] = rootX;
            }else{
                rank[rootX] = rootY;
                rank[rootY]++;
            }
        }
    }
}

基本操作

取模

1
((x%p)+p)%p // 将任意值转移到0~p之间

数字字符char转为数字

1
str - '0'

字母字符转为数字

1
str - 'A'

初始化数组

1
memset(str, 0, sizeof(str));

检查字符是否为十进制数字字符

1
isdigit()

最值

1
2
max(a,b)
min(a,b)

查询最大(小)值所在的第一个位置

1
2
max_element(begin, end)
min_element(begin, end)

整型十六进制

1
printf("%#x", n)

整数求对应ASCII码的符号

1
(char)n

字符求对应ASCII码值

1
int(string[i])

整型转换为二进制字符串

1
2
bitset<8> binary(int_number); // 8表示二进制串的位数
binary.to_string();

二进制字符串转换为整型

1
2
bitset<5> tempbit(string_value); // 先转换为bitset
int tempdec = (int)tempbit.to_ulong(); // 再转换为整型

输入格式

1
2
3
4
5
#include<bits/stdc++.h>

while(scanf("%d", &h) != EOF){
	xxx;
}

合并有序序列

1
2
3
4
5
6
7
8
9
// 都需要有序
merge(vec.begin(), vec.end(), // 范围1
     vec2.begin(), vec2.end(),// 范围2
     vec_out.begin());		  // 输出数组


// 原序列上合并两个有序的子序列
vector<int> vec = {1,2,3,4,1,2,3,4};
inplace_merge(vec.begin(), vec.begin()+4, vec.end()); // 1,1,2,2,3,3,4,4

高级操作

排序

适用于vector,deque,array等可随机访问结构

1
2
sort(vec.begin(), vec.end(), compare_function); // 通过compare_function排序
partial_sort(vec.begin(), vec.begin()+5, vec.end(), greater<int>()); // 获取最大前5个值

将满足某条件值移到最前

1
2
3
4
5
bool lessThanten(int i){
	return (i < 10);
}
partition(vec.begin(), vec.end(), lessThanten);
stable_partition(vec.begin(), vec.end(), lessThanten); // 保持原有顺序

逆序

1
reverse(str.begin(), str.end());

查找

二叉查找

1
2
3
4
5
6
7
8
9
bool found = binary_search(vec.begin(), vec.end(), 9); //查找9是否在

bool found = includes(vec.begin(), vec.end(), // s和vec均有序
                     s.begin(), s.end());// 若s所有元素被包含在vec中返回true

itr = lower_bound(vec.begin(), vec.end(), 9); // 找到9可以被插入保持有序的第一个位置
itr = upper_bound(vec.begin(), vec.end(), 9); // 找到9可以被插入保持有序的最后一个位置

pair_of_itr = equal_range(vec.begin(), vec.end(), 9); // 返回第一和最后的位置对

迭代器操作

  • 范围半开放:[begin, end)

计数

1
2
int n = count(vec.begin(), vec.end(), val); // 返回val个数
int n = count_if(vec.begin(), vec.end(), [](int x){return x<10;}); //返回满足条件的个数

比较

1
2
3
4
5
itr = max_element(vec.begin(), vec.end()); // 返回第一个最大值*itr
itr = max_element(vec.begin(), vec.end(), [](int x, int y){return (x%10)<(y%10);});
// 返回满足比较方法条件的第一个最大值

pair_of_itr = minmax_element(vec.begin(), vec.end(), [](int x, int y){return (x%10)<(y%10);}); // 返回一对迭代器

线性搜索

1
2
3
itr = find(vec.begin(), vec.end(), val); // 查找val,返回找到值的下一位的索引
itr = find_if(vec.begin(), vec.end(), [](int x){return x>80;});
itr = find_if_not(vec.begin(), vec.end(), [](int x){return x>80;});
1
2
3
4
5
6
itr = search_n(vec.begin(), vec.end(), count, val); // 查找连续count的val
distance(vec.begin(), itr); // itr的索引, 获取两者间距离

// 查找子集
itr = search(vec.begin(), vec.end(), sub.begin(), sub.end());
itr = find_end(vec.begin(), vec.end(), sub.begin(), sub.end()); // 查找最后一个子范围
1
2
3
4
5
// 查找到items中任何一个均可
itr = find_first_of(vec.begin(), vec.end(), items.begin(), items.end());

// 联结搜索, 默认搜索连着的相同的
itr = adjacent_find(vec.begin(), vec.end(), [](int x, int y){return x==y*4});

比较

1
2
3
4
if(equal(vec.begin(), vec.end(), vec2.begin())){} // 相同
if(is_permutation(vec.begin(), vec.end(), vec2.begin())){}   // 相同元素不同顺序
pair_of_itr = mismatch(vec.begin(), vec.end(), vec2.begin()) // 找到第一个不同
lexicographical_compare(vec.begin(), vec.end(), vec2.begin(), vec2.end()); // 一比一比较小于

检查

1
2
3
4
5
is_sorted(vec.begin(), vec.end())		 // 检查是否有序
is_sorted_until(vec.begin(), vec.end()); // 直到...均有序
is_partitioned(vec.begin(), vec.end(), [](int x){return x>80;}); // 检查是否以该条件区分开
is_heap(vec.begin(), vec.end())			 // 检查是否为堆
is_heap_until(vec.begin(), vec.end())    // 直到...前为堆
1
2
3
4
// 检查是否 所有/任何一个/无 元素满足条件
all_of(vec.begin(), vec.end(), [](int x){return x>80;});
any_of(vec.begin(), vec.end(), [](int x){return x>80;});
none_of(vec.begin(), vec.end(), [](int x){return x>80;});

拷贝

1
2
3
4
5
copy(vec.begin(), vec.end(), vec2.begin());
copy_if(vec.begin(), vec.end(), vec2.begin(), [](int x){return x>80;});

copy_n(vec.begin(), count, vec2.begin()); // 拷贝count个
copy_backward(vec.begin(), vec.end(), vec2.end());// 从后拷贝进入

移动

1
2
3
// 若为string可能原vec被移动的就消失了,若是int则直接类似于拷贝
move(vec.begin(), vec.end(), vec2.begin()); 
move_backward(vec.begin(), vec.end(), vec2.begin());

转移

1
2
3
4
5
6
7
8
transform(vec.begin(), vec.end(), // vec3[0] = vec[0] - 1
         vec3.begin(),
         [](int x){ return x-1;});

transform(vec.begin(), vec.end(),
          vec2.begin(),
          vec3.begin(),
          [](int x, int y) {return x+y;}); // vec3[0] = vec[0] + vec2[0]

交换

1
swap_ranges(vec.begin(), vec.end(), vec2.begin()); // 双向拷贝

填充

1
2
3
4
5
fill(vec.begin(), vec.end(), val); // 填充val
fill_n(vec.begin(), count, val);   // 填充count个val

generate(vec.begin(), vec.end(), rand); // 生成
generate_n(vec.begin(), count , rand);

替代

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
replace(vec.begin(), vec.end(),	// 数据范围
       6,						// 原始值
       9); 						// 新的值

replace_if(vec.begin(), vec.end(),
          [](int x){return x>80;},
          9);

replace_copy(vec.begin(), vec.end(), // 源
            vec2.begin(),		 	 // 目的
            6,						 // 原始值
            9);					     // 新值

移除

1
2
3
4
5
remove(vec.begin(), vec.end(), 3); // 移除所有的3
remove_if(vec.begin(), vec.end(), [](int x){return x>80;}); // 条件删除
remove_copy(vec.begin(), vec.end(), 
           vec2.begin(),
           6);// 移除所有的6,剩余值拷贝到vec2中
1
2
3
unique(vec.begin(), vec.end()); // 移除连续的相同的元素
unique(vec.begin(), vec.end(), less<int>()); // 移除比前一个元素大的元素
unique_copy(vec.begin(), vec.end(), vec2.begin());

倒置

1
2
reverse(vec.begin(), vec.end());
reverse_copy(vec.begin(), vec.end(), vec2.begin());

旋转

1
2
3
rotate(vec.begin(), vec.begin()+3, vec.end());
// 1 2 3 4 5 6 7
// 4 5 6 7 1 2 3

打乱

1
2
3
random_shuffle(vec.begin(), vec.end());

shuffle(vec.begin(), vec.end(), default_random_engine());

更改

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// vector, deque, array等随机访问迭代器可对迭代器直接加减,比较
vector<int>::iterator itr;
++itr;
if(itr2>itr2) ...;
itr = itr + 2;

// list, set/multiset, map/multimap等双向迭代器只可自加减
++itr;
--itr;

// forward_list等单向迭代器只可自增,不可自减
++itr;

int x = *itr;
*itr = 100; // 更改值

advance(itr, 5); // 等价于 itr+=5
std::advance(iterator, 2); // 迭代器前移2个位置
std::distance(vec.begin(), iterator); // 获取索引

流迭代器

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
vector<string> vec4;

// 从标准输入读取字符串到vec4
copy(istream_iterator<string>(cin), // 起始位置
     istream_iterator<string>(),    // 结束位置
     back_inserter(vec4));
// 使用 back_inserter 适配器将读取的字符串插入到 vec4 的末尾

// 将 vec4 中的字符串输出到标准输出,以空格分隔
copy(vec4.begin(), vec4.end(),
     ostream_iterator<string>(cout, " "));
1
2
3
4
// 不经过中间容器
copy(istream_iterator<string>(cin),
     istream_iterator<string>(),
     ostream_iterator<string>(cout, " ")); 

插入迭代器

1
2
3
4
5
6
7
8
vector<int> vec1 = {4, 5};
vector<int> vec2 = {12, 14, 16, 18};
vector<int>::iterator it = find(vec2.begin(), vec2.end(), 16);

insert_iterator<vector<int>> iitr(vec2, it);
copy(vec1.begin(), vec1.end(), // source
     iitr);                    // destination
                               // vec2 = {12, 14, 4, 5, 16, 18}

逆向迭代器

1
2
3
4
5
vector<int> vec = {4,5,6};
reverse_iterator<vector<int>::iterator> ritr;
for(ritr = vec.rbegin(); ritr != vec.rend(); ritr++){
	cout << *ritr << endl;// 6,5,4
}

常量迭代器

1
2
set<int>::const_iterator citr; // 只读不可改
for_each(myset.cbegin(), myset.cend(), MyFunction); // c++11 对每个元素执行MyFunction

函数

函数对象:重载了operator()类的实例

内置函数对象

1
2
int x = multiplies<int>()(3, 4); // x = 3 * 4
if(not_equal_to<int>()(x, 10))   // if(x!=10)

自定义函数对象

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// 构造函数对象,用于将元素乘以10
class MultiplyBy10 {
public:
    int operator()(int x) const {
        return x * 10;
    }
};

std::vector<int> nums = {1, 2, 3, 4, 5};
std::vector<int> result;
// 使用 std::transform 和自定义函数对象 MultiplyBy10 将 nums 中的每个元素乘以10
std::transform(nums.begin(), nums.end(),   // 源
               std::back_inserter(result), // 目的
               MultiplyBy10());

绑定器:将函数或函数对象的某些参数绑定为固定值

1
2
3
4
5
transform(myset.begin(), myset.end(),		// 源
         back_inserter(vec),				// 目的
         bind(multiplies<int>(), placeholders::_1, 10));// 绑定器
		 // placeholders::_1 占位符,表示 transform 传入的每个元素
		 // 绑定了multiplies的第2个参数为10

函数转化为函数对象

1
2
3
4
5
double Pow(double x, double y){
    return pow(x, y);
}

auto f = function<double (double, double)>(Pow);

lambda函数

1
[] (int x){return (x>20)||(x<5)};

输入输出流

创建支持流的类

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
 struct Dog {
 	 int age_;
     string name_;
 };

ostream& operator<<(ostream& sm, const Dog& d){
    sm << "name is " << d.name_ << " and age is " << d.age_ << endl;
    return sm;
}

istream& operator>>(istream& sm, Dog& d){
    sm >> d.name_;
    sm >> d.age_;
    return sm;
}

int main(){
    Dog d{2, "Bob"};
    cout << d; // name is Bob and age is 2
    cin >> d;
}

格式化数据

1
2
3
4
5
6
7
8
cout.setf(ios::oct, ios::basefield); // 输出八进制
cout.setf(ios::hex, ios::basefield); // 输出十六进制
cout.setf(ios::dec, ios::basefield); // 输出十进制
cout.setf(ios::showbase); // 会输出几进制前的标识符: 0x, 0等
cout.unsetf(ios::showbase);

cout.width(10); // 宽度为10个字符
cout.setf(ios::left, ios::adjustfield); // 靠左

文件流

打开文件写

1
2
3
4
5
6
ofstream of1("h.txt"); // 创建文件写 或 打开文件并清空原内容
ofstream of2("a.txt", ofstream::app); // append加入到原内容后

ofstream of3("b.txt", ofstream::in | ofstream::out); // 从中间加入内容
of3.seekp(10, ios::beg); // 将输出指针移动到begin的后10个字符处,覆写
of3.seekp(-5, ios::end); // 离end的前5个字符处

写入文件

1
2
3
4
of <<  "hello" << endl; // hello
of << 233 << endl; // 233
of << bitset<8>(14) << endl; // 00001110
of << complex<int>(2,3) << endl; // (2,3)
1
2
3
ofstream of("x.txt");
of.put('c'); // 放一个字符到流
of.write(buf, 6); // buf中6个字符输出到流
1
2
3
4
cout << ends; // '\0'
cout << flush; // 清空流
cout << setw(8) << left << setfill('_') << 99 << endl; // 99______ 宽度为8,输出不足用_填充
cout << hex << showbase << 14; // 0xe 流格式为十六进制

取整

1
2
ceil()// 向上取整
floor()// 向下取整

打开文件读

1
2
3
ifstream inf("h.txt");
int i;
inf >> i; // 读一个字
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
ifstream inf("x.txt");
char buf[80];

inf.get(buf, 80); // 读80字符到buf
inf.getline(buf, 80); // 读80直到'\n'
inf.read(buf, 20); // 读20字符
inf.ignore(3); // 忽略3字符
inf.peek(); // 返回流顶部的字符
inf.unget(); // 返回一个字符给流
inf.putback('z'); // 返回一个字符'z'给流
inf.gcount(); // 返回字符流读出的字符数

错误状态

1
2
3
4
5
6
7
8
9
inf.good(); // 一切正常 goodbit=1
inf.bad();  // 不可恢复错误 badbit=1
inf.fail(); // 错误流操作 failbit=1 badbit=1
inf.eof();  // 文件结束 eofbit=1

inf.clear(); // 清除所有状态
inf.clear(ios::badbit); // 为错误flag设置新值 置1
inf.rdstate(); // 读状态flag
inf.clear(inf.rdstate() & ~ios::failbit); // 只清除failbit

判断错误格式

1
2
3
4
if(inf){} // 成功读
if(inf >> i){} // 成功读

inf.exceptions(ios::badbit | iOS::failbit); // 两者中任何一个置1,抛出异常

字符串流

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
std::istringstream istr("12,");
int i;
char comma;

istr >> i >> comma; // i=12, comma=','

stringstream ss;

ss << 89 << "  Hex: " << hex << 89 << "  Oct: " << oct << 89;
cout << ss.str() << endl;  // 89  Hex: 59  Oct: 131

int a, b, c;
string s1;

ss >> hex >> a; // a = 137 = 0x89
ss >> s1;		// s1:"Hex:"
ss >> dec >> b; // b=59 读一个十进制的59

ss.ignore(6);
ss >> oct >> c; // c= 89 = 八进制的131

缓冲区

1
2
3
4
5
6
7
8
cout << 34;
streambuf* pbuf = cout.rdbuf();
ostream myCout(pbuf);
myCout << 34; // 34输出到标准输出

myCout.setf(ios::showpos); // 显示正负数
myCout.width(20);
myCout << 12 << endl; //                  +12
1
2
3
4
5
6
7
ofstream of("hello.txt");
streambuf* origBuf = cout.rdbuf();
cout.rdbuf(of.rdbuf());
cout << "hello" << endl;  // hello.txt has "hello"

cout.rdbuf(origBuf);
cout << "bye" << endl; // stdout: bye

流缓冲区迭代器

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
istreambuf_iterator<char> i(cin);
ostreambuf_iterator<char> o(cout);

while(*i != 'x'){
    *o = *i;
    ++o;
    ++i;
}// stdin输入啥,stdout输出啥,遇x退出

copy(istreambuf_iterator<char>(cin), istreambuf_iterator<char>(), ostreambuf_iterator<char>(cout));// 和上面基本一样,除了遇x不退出

语法

继承

派生类可以访问基类中的public和protected成员;外部类只能访问类的public成员

多态

调用成员函数时,会根据调用函数的对象的类型来执行不同的函数

虚函数:关键字为virtual,派生类重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数,而是使用动态链接根据所调用的对象类型来选择调用的函数

重载

在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同

重载运算符

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class Box
{
   public:
      // 重载 + 运算符
      Box operator+(const Box& b)
      {
         return xxx; // 调用为 B+A
      }
      void operator()(const Box& b) // 可以重载括号
      {
         cout << "x" << endl;// 调用为 B()
      }
}
Licensed under CC BY-NC-SA 4.0
Built with Hugo
主题 StackJimmy 设计
Caret Up