Compare commits

...

11 Commits

Author SHA1 Message Date
flykhan 4c986179b4 其他未完成 2023-08-14 17:20:39 +08:00
flykhan 9290e4c051 stl第一部分: string, vector, deque, stack 2023-08-04 09:28:07 +08:00
flykhan 82619cea98 modify readme 2023-08-03 09:47:09 +08:00
flykhan cfd8dd3992 day7: homework 修改第7题 2023-08-03 09:42:28 +08:00
flykhan 166515cf82 day7: homework 修改第7题 2023-08-03 09:30:34 +08:00
flykhan 8c46e7a977 day8: homework 2023-08-02 20:48:31 +08:00
flykhan 606fbc6ff1 day8: coding 2023-08-02 19:23:29 +08:00
flykhan 994963d919 day7 2023-08-02 19:22:52 +08:00
flykhan 15ae1803d7 day7: homework 2023-08-01 22:54:37 +08:00
flykhan c127a3a81b day7: homework-LinkedList 链表的实现 2023-08-01 22:21:52 +08:00
flykhan 5ab334d200 day7: homework 2023-08-01 21:46:18 +08:00
122 changed files with 6050 additions and 0 deletions
+10
View File
@@ -9,3 +9,13 @@
#### day3: 对象的构造与析构, 构造函数的分类与调用, 拷贝构造函数的调用时机, 构造函数的调用规则, 深拷贝和浅拷贝, 多个对象的构造和析构(初始化列表, 类对象作为成员), explicit 关键字(禁止隐式转换), 动态创建对象(malloc/realloc/calloc 在堆中创建空间, new 关键字), 扩展 new 和 delete,
#### day4: static 静态成员, 类的单例设计模式, 对象的存储(this 指针与链式编程, const 修饰成员函数与类对象), 友元, 运算符重载
#### day5: =运算符的重载, () 函数调用重载, `注意: &&和|| 无法重载`,
#### day6: 多继承(同属一个超级父类)产生的问题, 多态,抽象类, 虚函数(virtual)与纯虚函数, 接口类的多继承, override-overload-redefined 的区别, 函数模版, 普通函数与带泛型函数的区别
#### day7: 函数模板, 类模板, 类模板与友元一起使用的情况, 类型转换函数(static_cast, dynamic_cast, const_cast, reinterpret_cast)
#### day8: 异常处理, STL(容器、算法、迭代器)
#### day9: STL-> string, vector, deque, stack
Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 343 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

+289
View File
@@ -0,0 +1,289 @@
## 二、STL容器II
### 2.1 queue 容器
#### 2.1.1 queue概念
> Queue 是一种先进先出(First In First Out,FIFO)的数据结构,它有两个出口,queue
> 容器允许从一端新增元素,从另一端移除元素。
![image-20230804074147635](./readme.assets/image-20230804074147635.png)
#### 2.1.2 queue 没有迭代器
Queue 所有元素的进出都必须符合”先进先出”的条件,只有 queue 的顶端元素,才
有机会被外界取用。Queue 不提供遍历功能,也不提供迭代器。
#### 2.1.3 常用API
##### 2.1.3.1 构造函数
```c++
queue<T> queT; //queue 采用模板类实现,queue 对象的默认构造形式:
queue(const queue &que);//拷贝构造函数
```
##### 2.1.3.2 存取、插入和删除
```c++
void push(elem); //往队尾添加元素
void pop(); //从队头移除第一个元素
T back(); //返回最后一个元素
T front(); //返回第一个元素
```
##### 2.1.3.3 赋值与大小
```c++
queue& operator=(const queue &que);//重载等号操作符
empty();//判断队列是否为空
size();//返回队列的大小
```
### 2.2 list 容器
#### 2.2.1 list 概念
list(链表)是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。
每个结点包括两个部分:
```
1)存储数据元素的数据域,
2)存储下一个结点地址的指针域
```
list与vector的比较:
```
1) 相对于vector 的连续线性空间,list 就显得负责许多,每次插入或者删除一个元素,就是配置或者释放一个元素的空间。不浪费多余的空间,且插入与移除元素的操作是常数时间(稳定)。
2list和vector 是两个最常被使用的容器, 但list是由双向链表实现的。
3)list插入操作和删除操作都不会造成原有 list 迭代器的失效。 【重要特性】
```
<img src="./readme.assets/image-20230804075335829.png" width="400">
list特点:
```
1)采用动态存储分配,不会造成内存浪费和溢出
2)链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素
3)链表灵活,但是空间和时间额外耗费较大
```
#### 2.2.2 list 的迭代器
List 不能像 vector 一样以普通指针作为迭代器,因为其节点不能保证在同一块连续的内存空间上。。List 迭代器必须有能力指向 list 的节点,并有能力进行正确的递增、递减、取值、成员存取操作。**递增**时指向下一个节点,**递减**时指向上一个节点,**取值**时取的是节点的数据值,**成员取用**时取的是节点的成员。
另外,list 是一个双向链表,迭代器必须能够具备前移、后移的能力,所以 list 容器提供的是 Bidirectional Iterators.(双向的迭代器)。
List 有一个重要的性质,插入操作和删除操作都不会造成原有 list 迭代器的失效。
<font color=red>【注意】list的迭代器,不支持`+n`操作。</font>
#### 2.2.3 list 数据结构
> list 容器不仅是一个双向链表,而且还是一个循环的双向链表。
#### 2.2.4 常用API
##### 2.2.4.1 构造函数
```c++
list<T> lstT;//list 采用采用模板类实现,对象的默认构造形式:
list(beg,end);//构造函数将[beg, end)区间中的元素拷贝给本身。
list(n,elem);//构造函数将 n 个 elem 拷贝给本身。
list(const list &lst);//拷贝构造函数
```
##### 2.2.4.2 插入和删除
```c++
push_back(elem);//在容器尾部加入一个元素
pop_back();//删除容器中最后一个元素
push_front(elem);//在容器开头插入一个元素
pop_front();//从容器开头移除第一个元素
insert(pos,elem);//在 pos 位置插 elem 元素的拷贝,返回新数据的位置。
insert(pos,n,elem);//在 pos 位置插入 n 个 elem 数据,无返回值。
insert(pos,beg,end);//在 pos 位置插入[beg,end)区间的数据,无返回值。
clear();//移除容器的所有数据
erase(beg,end);//删除[beg,end)区间的数据,返回下一个数据的位置。
erase(pos);//删除 pos 位置的数据,返回下一个数据的位置。
remove(elem);//删除容器中所有与 elem 值匹配的元素
```
##### 2.2.4.3 大小
```c++
size();//返回容器中元素的个数
empty();//判断容器是否为空
resize(num);//重新指定容器的长度为 num, 若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除
resize(num, elem);
```
##### 2.2.4.4 赋值
```c++
assign(beg, end); //将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem); //将 n 个 elem 拷贝赋值给本身。
list& operator=(const list &lst); //重载等号操作符
swap(lst); //将 lst 与本身的元素互换。
```
##### 2.2.4.5 读取
```
front();//返回第一个元素。
back();//返回最后一个元素
```
##### 2.2.4.6 反转和排序
```
reverse(); //反转链表
sort(); //list 排序
```
### 2.3 set/multiset 容器
#### 2.3.1 set概念
set 的特性是所有元素都会根据元素的键值自动被排序。
set 的元素即是键值又是实值, 不允许两个元素有相同的键值。
set 的 iterator 是一种 const_iterator 不允许修改set的键值。
set 拥有和 list 某些相同的性质,当对容器中的元素进行插入操作或者删除操作的
时候,操作之前的迭代器,在操作完成之后依然有效,被删除的那个元素的迭代器必然是一个例外。
#### 2.3.2 set数据结构
multiset 特性及用法和 set 完全相同,唯一的差别在于它允许键值重复。set 和multiset 的底层实现是红黑树,红黑树为平衡二叉树的一种。
二叉树就是任何节点最多只允许有两个字节点。分别是左子结点和右子节点:
<img src="./readme.assets/image-20230804083406386.png" width="300">
二叉搜索树,是指二叉树中的节点按照一定的规则进行排序,使得对二叉树中元素访问更加高效:
<img src="./readme.assets/image-20230804083459911.png" width=400>
二叉搜索树的放置规则是:
任何节点的元素值一定大于其左子树中的每一个节点的元素值,并且小于其右子树的值。因此从根节点一直向左走,一直到无路可走,即得到最小值,一直向右走,直至无路可走,可得到最大值。那么在二叉搜索树中找到最大元素和最小元素是非常简单的事情。
如上图所示:那么当一个二叉搜索树的左子树和右子树不平衡的时候,那么搜索依据上图表示,搜索 9 所花费的时间要比搜索 17 所花费的时间要多,由于我们的输入或者经过我们插入或者删除操作,二叉树失去平衡,造成搜索效率降低。
<img src="./readme.assets/image-20230804083751044.png" width=400>
#### 2.3.3 常用API
##### 2.3.3.1 构造函数
```c++
set<T> st;//set 默认构造函数:
mulitset<T> mst; //multiset 默认构造函数:
set(const set &st);//拷贝构造函数
```
##### 2.3.3.2 赋值和大小
```c++
set& operator=(const set &st);//重载等号操作符
swap(st);//交换两个集合容器
size();//返回容器中元素的数目
empty();//判断容器是否为空
```
##### 2.3.3.3 插入和删除
```
insert(elem); //在容器中插入元素。
clear(); //清除所有元素
erase(pos); //删除 pos 迭代器所指的元素,返回下一个元素的迭代器。
erase(beg, end); //删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
erase(elem); //删除容器中值为 elem 的元素。
```
##### 2.3.3.4 查找
```c++
find(key); //查找键 key 是否存在,若存在,返回该键的元素的迭代器;若不存在,返
回 set.end();
count(key);//查找键 key 的元素个数
lower_bound(keyElem);//返回第一个 key>=keyElem 元素的迭代器。
upper_bound(keyElem);//返回第一个 key>keyElem 元素的迭代器。
equal_range(keyElem);//返回容器中 key 与 keyElem 相等的上下限的两个迭代器。
```
##### 2.3.3.5 set 排序规则
> set自动排序, 但可以改变它的排序规则,默认从小到大。
自定义排序规则,可以使用struct或class, 声明 `bool operator(v1, v2)`仿函数重载。
#### 2.3.4 对组(pair)
对组(pair)将一对值组合成一个值,这一对值可以具有不同的数据类型,两个值可
以分别用 pair 的两个公有属性 first 和 second 访问。
```
类模板:template <class T1, class T2> struct pair
```
用法一:
```c++
pair<string, int> pair1(string("name"), 20);
cout << pair1.first << endl;
cout << pair1.second << endl;
```
用法二:
```c++
pair<string, int> pair2 = make_pair("name", 30);
cout << pair2.first << endl;
cout << pair2.second << endl;
```
用法三:
```c++
pair<string, int> pair3 = pair2;
cout << pair3.first << endl;
cout << pair3.second << endl;
```
### 2.4 map/multimap 容器
Map 的特性是所有元素都会根据元素的键值自动排序。
Map 所有的元素都是pair,同时拥有实值和键值,pair 的第一元素被视为键值,第二元素被视为实值,map 不允许两个元素有相同的键值。
multimap 和 map 的操作类似,唯一区别 multimap 键值可重复。
map 和 multimap 都是以红黑树为底层实现机制。
+33
View File
@@ -0,0 +1,33 @@
// 函数对象
// 仿函数: 一元,二元仿函数
#include <iostream>
using namespace std;
// 一元仿函数
class A
{
public:
A(int n) : n(n) {}
int n;
// 重载 operator() 运算符,只要调用 A 对象的 (int x) ,就会给对象的对应成员对象加一个 x
A &operator()(int i)
{
this->n += i;
return *this;
}
};
void print(A a, int n) // A a = A(30)
{
a(n);
cout << "a.n = " << a.n << endl;
}
int main()
{
// 打印 a 对象的值加额外的值的结果
print(A(20), 3); // A(20) 会创建一个匿名对象
return 0;
}
+59
View File
@@ -0,0 +1,59 @@
// 谓词
// gt 大于, ge 大于等于
// lt 小于, le 小于等于
// eq 等于, ne 小于等于
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class GTFive // 一元谓词
{
public:
bool operator()(int n)
{
return n > 5;
}
};
class GT // 二元谓词
{
public:
bool operator()(const int &n1, const int &n2)
{
return n1 > n2;
}
};
void printGTF(GTFive gtf, int *p, int size)
{
for (int i = 0; i < size; i++)
{
if (gtf(p[i]))
cout << p[i] << " ";
}
cout << endl;
}
void print(int *p, int size, GT gt, int n)
{
for (int i = 0; i < size; i++)
{
if (gt(p[i], n))
cout << p[i] << " ";
}
cout << endl;
}
int main()
{
int ms[] = {1, 2, 4, 7, 9, 20};
cout << "大于 5 的元素" << endl;
printGTF(GTFive(), ms, 6);
cout << "大于 7 的元素" << endl;
print(ms, 6, GT(), 7);
return 0;
}
+39
View File
@@ -0,0 +1,39 @@
// 算术类函数对象
// 算术类函数对象
#include <iostream>
#include <set>
#include <algorithm>
using namespace std;
// template <typename T>
void print(typename set<int>::const_iterator start,
typename set<int>::const_iterator end, plus<int> pl, int m)
{
for (; start != end; start++)
{
cout << pl(*start, m) << " ";
}
cout << endl;
}
void print(typename set<int>::const_iterator start,
typename set<int>::const_iterator end, multiplies<int> mul, int m)
{
for (; start != end; start++)
{
cout << mul(*start, m) << " ";
}
cout << endl;
}
int main()
{
int m[] = {1, 2, 3, 4, 8, 5, 1, 2};
// set 会自动过滤重复,并排序
set<int> s(m, m + sizeof(m) / sizeof(m[0]));
print(s.begin(), s.end(), plus<int>(), 1);
print(s.begin(), s.end(), multiplies<int>(), 3);
return 0;
}
+59
View File
@@ -0,0 +1,59 @@
#include <iostream>
#include <set>
#include <algorithm>
using namespace std;
// template <typename T>
void print(typename set<int>::const_iterator start,
typename set<int>::const_iterator end, plus<int> pl, int m)
{
for (; start != end; start++)
{
cout << pl(*start, m) << " ";
}
cout << endl;
}
void print(typename set<int>::const_iterator start,
typename set<int>::const_iterator end, multiplies<int> mul, int m)
{
for (; start != end; start++)
{
cout << mul(*start, m) << " ";
}
cout << endl;
}
void show(int n)
{
cout << n << " ";
}
// 二元仿函数
class PrintPlus : public binary_function<int, int, void>
{
public:
void operator()(const int &n1, const int &n2) const
{
cout << n1 << "+" << n2 << " = " << n1 + n2 << endl;
}
};
int main()
{
int m[] = {1, 2, 3, 4, 8, 5, 1, 2};
// set 会自动过滤重复,并排序
set<int> s(m, m + sizeof(m) / sizeof(m[0]));
// print(s.begin(), s.end(), plus<int>(), 1);
// print(s.begin(), s.end(), multiplies<int>(), 3);
// for_each(s.begin(), s.end(), show);
// cout << endl;
// PrintPlus 测试
// for (int i = 0; i < 6; i++)
for_each(s.begin(), s.end(), bind1st(PrintPlus(), i));
return 0;
}
+25
View File
@@ -0,0 +1,25 @@
#include <iostream>
#include <set>
#include <algorithm>
using namespace std;
class PrintGt5Adapter : public binary_function<int, int, void>
{
public:
void operator()(const int &n1, const int &n2) const
{
if (n1 > n2)
cout << n1 << " ";
}
};
int main()
{
int m[] = {1, 2, 3, 4, 8, 5, 1, 2};
set<int> s(m, m + sizeof(m) / sizeof(m[0]));
for_each(s.begin(), s.end(), bind2nd(PrintGt5Adapter(), 2));
return 0;
}
+43
View File
@@ -0,0 +1,43 @@
// 取反适配器
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 自定义一个适配器,只需要容器中元素即可。
class GT5 : public unary_function<int, bool>
{
public:
bool operator()(const int &n) const
{
return n > 5;
}
};
class GTN : public binary_function<int, int, bool>
{
public:
bool operator()(const int &n1, const int &n2) const
{
return n1 > n2;
}
};
int main()
{
int m[] = {1, 2, 2, 3, 5, 10};
vector<int> v;
v.assign(m, m + sizeof(m) / sizeof(m[0]));
// find_if(start, end, _callback) 返回查找到的第一个迭代器的位置
vector<int>::iterator ret = find_if(v.begin(), v.end(), not1(bind2nd(greater<int>(), 3)));
cout << *ret << endl;
ret = find_if(v.begin(), v.end(), GT5());
cout << *ret << endl;
ret = find_if(v.begin(), v.end(), bind2nd(GTN(), 3));
cout << *ret << endl;
return 0;
}
+26
View File
@@ -0,0 +1,26 @@
// 函数指针适配
// 使用 ptr_fun<>() 适配函数指针
// <> 中的第一个参数是函数指针的类型,第二个参数是函数指针的参数类型,第三个参数是函数指针的返回值类型
// bind1st() 和 bind2nd() 适配函数对象
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
bool gtn(int n1, int n2)
{
return n1 > n2;
}
int main()
{
int m[] = {1, 2, 2, 3, 5, 10};
vector<int> v;
v.assign(m, m + sizeof(m) / sizeof(m[0]));
vector<int>::iterator ret = find_if(v.begin(), v.end(), bind2nd(ptr_fun<int, int, bool>(gtn), 3));
cout << *ret << endl;
return 0;
}
+39
View File
@@ -0,0 +1,39 @@
// mem_fn 有两个重载版本:
// 用法1mem_fn(&MyClass::printMessage) 用于将成员函数转换为函数对象
// 用法2mem_fn(&MyClass::printMessage)(&obj, "hello world") 用于调用成员函数
// mem_fn 是一个函数模板,它接受一个成员函数指针或成员函数引用,并返回一个函数对象,该对象可以调用相应的成员函数。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Stu
{
private:
string name;
int age;
public:
Stu(const string &name, int age) : name(name), age(age) {}
public:
void show()
{
cout << "name is " << name << ", age is " << age << endl;
}
};
int main()
{
vector<Stu> vs;
vs.push_back(Stu("disen", 18));
vs.push_back(Stu("lucy", 20));
vs.push_back(Stu("jack", 15));
vs.push_back(Stu("mack", 19));
// 遍历容器中所有成员,成员函数作为仿函数时,则通过容器成员调用它的仿函数
for_each(vs.begin(), vs.end(), mem_fun_ref(&Stu::show));
return 0;
}
+30
View File
@@ -0,0 +1,30 @@
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;
using namespace std::placeholders;
int main()
{
int m[] = {1, 2, 2, 3, 5, 10};
vector<int> v;
v.assign(m, m + sizeof(m) / sizeof(m[0]));
int target = 3;
// 使用 std::bind 适配 std::equal_to
vector<int>::iterator ret = adjacent_find(v.begin(), v.end(), bind(equal_to<int>(), _1, 3));
cout << *(++ret) << endl;
if (ret != v.end())
{
cout << "Found adjacent elements equal to " << target << "." << endl;
}
else
{
cout << "No adjacent elements equal to " << target << " found." << endl;
}
return 0;
}
+27
View File
@@ -0,0 +1,27 @@
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;
template <typename T>
void print(const list<T> &lst)
{
for (typename list<T>::const_iterator it = lst.begin(); it != lst.end(); ++it)
cout << *it << ' ';
cout << endl;
}
int main()
{
list<int> lst1(6, 5); // 6 个 5
print(lst1);
string s1 = "abcdefg";
// 将 string 字符串转换为 list
list<char> lst2(s1.begin(), s1.end());
print(lst2);
return 0;
}
+36
View File
@@ -0,0 +1,36 @@
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;
template <typename T>
void print(const list<T> &lst)
{
for (typename list<T>::const_iterator it = lst.begin(); it != lst.end(); ++it)
cout << *it << ' ';
cout << endl;
}
int main()
{
string s = "abcdefg";
// 将 string 字符串转换为 list
list<char> l(s.begin(), s.end());
int size = l.size(); // 获取大小
print(l);
// list 手写逆序
list<char>::iterator it = l.begin(); // 迭代器指向第一个元素
for (int i = 0; i < size; i++) // 逆序 size 次
{
it = l.insert(it, l.back()); // 将最后一个元素插入到第一个元素之前
it++; // 迭代器指向下一个元素
l.pop_back(); // 删除最后一个元素
}
print(l);
return 0;
}
+35
View File
@@ -0,0 +1,35 @@
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;
template <typename T>
void print(const list<T> &lst)
{
for (typename list<T>::const_iterator it = lst.begin(); it != lst.end(); ++it)
cout << *it << ' ';
cout << endl;
}
int main()
{
string s = "abcdefg";
list<char> l(s.begin(), s.end());
// 删除 cde
// list<char>::iterator it = find(l.begin(), l.end(), 'c');
// l.erase(it, find(l.begin(), l.end(), 'e'));
list<char>::iterator it = l.begin(); // 迭代器指向第一个元素
for (int i = 0; i < 2; i++) // 迭代器指向第三个元素
it++;
list<char>::iterator it2 = it; // 迭代器指向第三个元素
for (int i = 0; i < 3; i++) // 迭代器指向第六个元素
it2++;
l.erase(it, it2); // 删除第三个到第五个元素
print(l); // a b f g
return 0;
}
+32
View File
@@ -0,0 +1,32 @@
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;
template <typename T>
void print(const list<T> &lst)
{
for (typename list<T>::const_iterator it = lst.begin(); it != lst.end(); ++it)
cout << *it << ' ';
cout << endl;
}
int main()
{
string s = "abcdefg";
list<char> l(s.begin(), s.end());
print(l);
l.reverse(); // 逆序
print(l);
int m[] = {6, 4, 2, 0, 8, 6, 4};
list<int> l2(m, m + 7);
print(l2);
l2.sort(); // 排序
print(l2);
l2.reverse(); // 逆序
print(l2);
return 0;
}
+26
View File
@@ -0,0 +1,26 @@
#include <iostream>
#include <map>
using namespace std;
int main()
{
map<int, string> ms;
// 1. insert()函数
// map 在插入时会自动根据 map 的键来排序
ms.insert(pair<int, string>(1, "张三")); // pair<int, string>是map<int, string>::value_type的类型
ms.insert(pair<int, string>(4, "李四"));
ms.insert(make_pair(3, "王五")); // make_pair()函数可以自动推导出类型
ms.insert(map<int, string>::value_type(2, "赵六")); // value_type是map<int, string>的类型
ms[5] = "田七"; // 通过下标的方式插入数据
map<int, string>::iterator it = ms.begin();
for (; it != ms.end(); it++)
{
// cout << "sid = " << it->first << ",name = " << it->second << endl;
cout << "sid = " << (*it).first << ",name = " << (*it).second << endl;
}
return 0;
}
+61
View File
@@ -0,0 +1,61 @@
// 使用 map 来解决括号匹配
#include <iostream>
#include <map>
#include <stack>
#include <string>
using namespace std;
string left_c = "{[(";
map<char, char> map1;
bool valid(const char *p)
{
stack<char> stk;
int max_depth = 0;
while (*p)
{
const char &cp = *p;
// if (left_c.find(cp) != string::npos) // 如果当前拿到的是左括号
if (left_c.find(cp) != -1) // 如果当前拿到的是左括号
{
// 入栈
stk.push(*p);
}
else // 如果当前拿到的是右括号
{
// 弹栈
if (stk.empty())
return false;
const char &top = stk.top();
if (map1[cp] != top)
return false;
// 当前左右匹配的后续操作
// 求最大深度
if (max_depth < stk.size())
max_depth = stk.size();
// 弹栈前判断最大深度
stk.pop();
}
p++;
}
cout << "当前括号栈的最大深度为: " << max_depth << endl;
return stk.empty();
}
int main()
{
map1.insert(make_pair('}', '{'));
map1.insert(make_pair(']', '['));
map1.insert(make_pair(')', '('));
cout << valid("{[()]}[[[[[()]]]]]") << endl;
cout << valid("{[())}") << endl;
return 0;
}
+15
View File
@@ -0,0 +1,15 @@
#include <iostream>
#include <map>
using namespace std;
int main()
{
map<int, string> m;
m.insert(make_pair(1, "disen"));
m.insert(make_pair(2, "lucy"));
cout << m.size() << endl;
m.erase(1); // 删除键值为 1 的元素
cout << m.size() << endl;
return 0;
}
+26
View File
@@ -0,0 +1,26 @@
#include <iostream>
#include <map>
using namespace std;
int main()
{
map<int, string> m;
m.insert(make_pair(1, "disen"));
m.insert(make_pair(2, "lucy"));
m.insert(make_pair(3, "jack"));
map<int, string>::const_iterator it = m.find(3);
if (it == m.end())
{
cout << "未查找到" << endl;
}
else
{
const pair<int, string> &p = *it;
cout << p.first << ", " << p.second << endl;
}
return 0;
}
View File
+32
View File
@@ -0,0 +1,32 @@
#include <iostream>
#include <set>
using namespace std;
template <typename T>
void print(const set<T> &s)
{
for (typename set<T>::const_iterator it = s.begin(); it != s.end(); ++it)
cout << *it << ' ';
cout << endl;
}
template <typename T>
void print(const multiset<T> &s)
{
for (typename multiset<T>::const_iterator it = s.begin(); it != s.end(); ++it)
cout << *it << ' ';
cout << endl;
}
int main()
{
int m[] = {1, 2, 3, 2, 3, 4};
set<int> s(m, m + 6);
print(s); // set 会自动去重,输出 1 2 3 4
multiset<int> ms(m, m + 6);
print(ms); // multiset 不会自动去重,输出 1 2 2 3 3 4
return 0;
}
+50
View File
@@ -0,0 +1,50 @@
#include <iostream>
#include <set>
using namespace std;
template <typename T>
void print(const set<T> &s)
{
for (typename set<T>::const_iterator it = s.begin(); it != s.end(); ++it)
cout << *it << ' ';
cout << endl;
}
int main()
{
int m[] = {5, 12, 16, 21, 22, 27, 29, 30};
set<int> s(m, m + 8);
print(s); // set 键值自动排序,且不重复
// 查看大于等于 22 值的所有元素
cout << "查看大于等于 22 值的所有元素: " << endl;
set<int>::iterator it = s.lower_bound(22); // 返回第一个大于等于 22 的元素的迭代器
while (it != s.end())
{
cout << *it << ' ';
++it;
}
cout << endl;
// 查找小于等于 22 值的所有元素
cout << "查找小于等于 22 值的所有元素: " << endl;
// it = s.upper_bound(22); // 返回第一个大于 22 的元素的迭代器
// for (; it != s.begin();)
// {
// --it;
// cout << *it << ' ';
// }
// cout << endl;
// 查找小于等于 22 值的所有元素(另一种写法)
it = s.lower_bound(22);
while (it != s.begin())
{
--it;
cout << *it << ' ';
}
cout << endl;
return 0;
}
+36
View File
@@ -0,0 +1,36 @@
// 自定义排序
#include <iostream>
#include <set>
using namespace std;
// 自定义规则
template <typename T>
class MySort
{
public:
bool operator()(const T &a, const T &b)
{
return a > b; // 从小到大排序
}
};
int main()
{
// 使用 set 时,添加自定义排序规则
set<int, MySort<int> > s1;
s1.insert(20);
s1.insert(30);
s1.insert(1);
s1.insert(8);
set<int, MySort<int> >::iterator it = s1.begin(); // <int, MySort<int>> 可以省略
while (it != s1.end())
{
cout << *it << ' ';
++it;
}
cout << endl;
return 0;
}
+59
View File
@@ -0,0 +1,59 @@
// 自定义排序
#include <iostream>
#include <set>
using namespace std;
// 自定义规则
template <typename T>
class MySort
{
public:
bool operator()(const T &a, const T &b)
{
return a > b; // 从小到大排序
}
};
class Student
{
public:
string name;
int age;
float score;
public:
Student(const string &name, int age, float score)
{
this->name = name;
this->age = age;
this->score = score;
}
};
class MyStudentByAgeSort
{
public:
bool operator()(const Student &s1, const Student &s2)
{
return s1.age > s2.age;
}
};
class MyStudentByScoreSort
{
public:
bool operator()(const Student &s1, const Student &s2)
{
return s1.score > s2.score;
}
};
int main()
{
Student[] *stus = new Student[3]{Student("张三", 18, 100), Student("李四", 20, 90), Student("王五", 19, 95)};
set<Student, MyStudentByAgeSort> s2;
s2............................
return 0;
}
+12
View File
@@ -0,0 +1,12 @@
#include <iostream>
#include <set>
using namespace std;
int main()
{
// pair 是一个模板类,有两个模板参数,
// 用于存储两个数据,可以分别指定两个数据的类型
pair<int, string> p1(1, "张三");
return 0;
}
+40
View File
@@ -0,0 +1,40 @@
// 对组(pair)
// 将一对值组合成一个值,这一对值可以具有不同的数据类型,两个值可
// 以分别用 pair 的两个公有属性 first 和 second 访问。
// 类模板:template<class T1, class T2> class pair
// 用法一:
// pair<string, int> pair1(string("name"), 20);
// cout << pair1.first << endl;
// cout << pair1.second << endl;
// 用法二:
// pair<string, int> pair2 = make_pair("name", 30);
// cout << pair2.first << endl;
// cout << pair2.second << endl;
// 用法三:
// pair<string, int> pair3 = pair2; // 拷贝构造函数
// cout << pair3.first << endl;
// cout << pair3.second << endl;
// 如:
#include <iostream>
#include <set>
#include <algorithm>
using namespace std;
int main()
{
pair<int, string> p1(1, "disen");
pair<int, string> p2 = make_pair(2, "lucy");
cout << "id = " << p1.first << ", name = " << p1.second << endl;
cout << "id = " << p2.first << ", name = " << p2.second << endl;
return 0;
}
+55
View File
@@ -0,0 +1,55 @@
// = 赋值重载
// 注意 = 重载时,可能会调用类本身的拷贝构造函数。如果左值是没有创建的对象时,
// 会调用类的拷贝构造函数
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class A
{
private:
int x;
public:
A(int x) : x(x)
{
cout << "A(int x)" << endl;
}
A(const A &obj)
{
cout << "A(A &obj)" << endl;
this->x = obj.x;
}
A &operator=(const A &other)
{
cout << "A &operator=(A&other)" << endl;
this->x = other.x;
return *this;
}
public:
void show()
{
cout << "x = " << x << endl;
}
};
int main()
{
A a1(100), a2(200);
A a4 = 300; // A(300)
a4 = 400; // operator=()
A a3 = a1; // A(a1)
a3.show();
a3 = a2; // operator=() 调用赋值重载函数
a3.show();
a3 = a4;
a3.show();
return 0;
}
+41
View File
@@ -0,0 +1,41 @@
// () 函数调用重载
// 当类对象作为函数调用时,会执行 operator()(参数列表) 函数
//
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class A
{
private:
int x, y;
public:
A(int x, int y) : x(x), y(y) {}
public:
void operator()(int a, int b)
{
this->x += a;
this->y += b;
show();
}
void show()
{
cout << x << ", " << y << endl;
}
};
int main()
{
A a1(10, 9);
a1.show();
a1(2, 3); // 类对象作为函数使用,实现 2+x,3+y
// a1.show();
return 0;
}
+39
View File
@@ -0,0 +1,39 @@
# 定义路径变量
SRC_DIR = ./
OBJ_DIR = ./
BIN_DIR = ./
# 定义编译器
CC = g++
STD = -std=c++11
# 定义目标文件
TARGET = $(BIN_DIR)/a.out
# 定义源文件
SRCS = $(wildcard $(SRC_DIR)/*.cpp)
# OBJS = $(OBJ_DIR)/lrc.o $(OBJ_DIR)/console.o $(OBJ_DIR)/start_mplayer.o $(OBJ_DIR)/time_delay.o $(OBJ_DIR)/main.o
OBJS = $(patsubst $(SRC_DIR)/%.cpp, $(OBJ_DIR)/%.o, $(SRCS))
# 编译规则
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CC) -c $< -o $@ $(STD)
# 链接规则
$(TARGET): $(OBJS)
$(CC) $^ -o $@ $(STD)
# 默认构建目标
all: $(TARGET)
# 创建目录
$(shell mkdir -p $(OBJ_DIR) $(BIN_DIR))
# 运行测试
run: $(TARGET)
$(TARGET)
# 清理规则
clean:
rm -rf $(OBJ_DIR)/*.o $(TARGET)
# 伪目标
.PHONY: all clean
+12
View File
@@ -0,0 +1,12 @@
#include "mystring.h"
#include <iostream>
using namespace std;
int main()
{
MyString s1("disen");
cout << s1 + ",lucy" << endl;
return 0;
}
+96
View File
@@ -0,0 +1,96 @@
#include "mystring.h"
using namespace std;
ostream &operator<<(ostream &cout, const MyString &str)
{
cout << str.mStr; // 输出字符串 mStr
return cout; // 返回 cout 输出流对象
}
istream &operator<<(istream &cin, MyString &str)
{
cin >> str.mStr; // 输入字符串 mStr
return cin; // 返回 cin 输入流对象
}
MyString::MyString(const char *str)
{
mSize = strlen(str); // 计算字符串长度
mStr = new char[mSize + 1]; // 为 '\0' 留一个位置
strcpy(mStr, str); // 拷贝字符串
}
MyString::MyString(const MyString &str)
{
mSize = str.mSize; // 拷贝字符串长度
char *p = new char[mSize + 1]; // 为 '\0' 留一个位置
strcpy(p, str.mStr); // 拷贝字符串
delete[] this->mStr; // 删除之前的空间
this->mStr = p; // 指向新的空间
}
MyString::~MyString()
{
delete[] mStr; // 释放空间
}
// 字符串拼接
MyString &MyString::operator+(MyString &other)
{
mSize += other.mSize; // 计算新的字符串长度, 用原有长度加上 other 的长度
char *p = new char[mSize + 1]; // 为 '\0' 留一个位置
strcpy(p, mStr); // 拷贝 mStr
strcat(p, other.mStr); // 拼接 other.mStr
delete[] this->mStr; // 删除之前的空间
this->mStr = p; // 指向新的空间
}
MyString &MyString::operator+(const char *other)
{
mSize += strlen(other); // 计算新的字符串长度, 用原有长度加上 other 的长度
char *p = new char[mSize + 1]; // 为 '\0' 留一个位置
strcpy(p, mStr); // 拷贝 mStr
strcat(p, other); // 拼接 other
delete[] this->mStr; // 删除之前的空间
this->mStr = p; // 指向新的空间
}
// 字符串赋值
MyString &MyString::operator=(MyString &other)
{
mSize = other.mSize; // 拷贝字符串长度
char *p = new char[mSize + 1]; // 为 '\0' 留一个位置
strcpy(p, other.mStr); // 拷贝字符串
delete[] mStr; // 删除之前的空间
mStr = p; // 指向新的空间
}
MyString &MyString::operator=(const char *other)
{
mSize = strlen(other); // 拷贝字符串长度
char *p = new char[mSize + 1]; // 为 '\0' 留一个位置
strcpy(p, other); // 拷贝字符串
delete[] mStr; // 删除之前的空间
mStr = p; // 指向新的空间
}
// 字符串比较
MyString &operator==(MyString &other)
{
return strcmp(mStr, other.mStr) == 0; // 比较字符串
}
MyString &operator==(const char *other)
{
return strcmp(mStr, other) == 0; // 比较字符串
}
// 读取字符串中 index 位置的字符
char MyString::operator[](int index)
{
cout << "长度: " << mSize << endl;
// index 支持负数, -1 表示倒数第一个字符
// index 是负数,计算机存储是补码,如果直接位运算,以补码的方式 & 位运算符
// 需要手动取反补码(~), 然后 +1
int absIndex = (~index + 1) & 0x7fffffff; // 0x7fffffff 是有符号正整数 int 的最大值
// 0x7fffffff = 0111 1111 1111 1111 1111 1111 1111 1111
}
+42
View File
@@ -0,0 +1,42 @@
#ifndef __MYSTRING_H__
#define __MYSTRING_H__
#include <iostream>
#include <cstring>
// 重载: 实现自定义字符串类
class MyString
{
friend ostream &operator<<(ostream &cout, const MyString &str) {}
friend istream &operator<<(istream &cout, MyString &str) {}
public:
MyString(const char *str); // 有参构造函数
MyString(const MyString &str); // 拷贝构造函数
~MyString(); // 析构函数
public:
// 字符串拼接
MyString &operator+(MyString &other); // 重载 + 运算符
MyString &operator+(const char *other); // 重载 + 运算符
// 字符串赋值
MyString &operator=(MyString &other); // 重载 = 运算符
MyString &operator=(const char *other); // 重载 = 运算符
// 字符串比较
MyString &operator==(MyString &other); // 重载 == 运算符
MyString &operator==(const char *other); // 重载 == 运算符
// 读取字符串中 index 位置的字符
char operator[](int index); // 重载 [] 运算符
private:
char *mStr; // 字符串
int mSize; // 字符串长度
};
ostream &operator<<(ostream &cout, const MyString &str);
istream &operator<<(istream &cout, MyString &str);
#endif
+51
View File
@@ -0,0 +1,51 @@
// 构造函数
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class Person
{
private:
string name;
int age;
public:
Person(const string &name, int age) : name(name), age(age) {}
public:
void hi()
{
cout << this->name << ", " << this->age << endl;
}
};
class Worker : public Person
{
private:
int salary; // 工资
int year; // 工作年限
public:
// 子类的构造函数定义时,可以调用父类的构造函数进行父类成员的初始化
// 使用初始化列表实现(调用父类的构造函数,传入对应参数)
Worker(const string &name, int age, int salary, int year) : Person(name, age), salary(salary), year(year)
{
}
public:
void hi() // 重写了父类的函数,覆盖了父类的 hi()
{
// 先调用父类的 hi()
Person::hi();
cout << salary << ", " << year << endl;
}
};
int main()
{
Worker w1 = Worker("liming", 18, 2100, 2);
w1.hi();
return 0;
}
+99
View File
@@ -0,0 +1,99 @@
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class A
{
public:
int a;
protected:
int b;
private:
int c;
public:
A(int a, int b, int c) : a(a), b(b), c(c) {}
public:
void showA()
{
cout << "A: " << a << ", " << b << ", " << c << endl;
}
};
class B : public A
{
public:
B() : A(1, 3, 2) {}
public:
void showB()
{
showA();
// B 类的成员函数内,可以访问父类的 public 、protected 成员
// a, b 是父类的 public/protected 的成员变量
cout << "B: " << a << ", " << b << endl;
}
};
class C : protected B
{
public:
C() : B() {}
public:
void showC()
{
showA();
showB();
cout << "C: " << a << ", " << b << endl;
}
};
class D : private C
{
public:
D() : C() {}
public:
void showD()
{
showA();
cout << "D: " << a << ", " << b << endl;
}
};
class E : public D
{
public:
E() : D() {}
public:
void showE()
{
showA();
// cout << "E: " << a << ", " << b << endl;
}
};
int main()
{
// B b1;
// b1.showA();
// b1.showB();
// C c1;
// c1.showC();
// D d1;
// d1.showD();
E e1;
e1.showD();
return 0;
}
+54
View File
@@ -0,0 +1,54 @@
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class A
{
public:
int x;
private:
int y;
public:
A(int x, int y)
// A()
{
cout << "A(int x,int y)" << endl;
// cout << "A()" << endl;
}
~A()
{
cout << "~A()" << endl;
}
};
class B : public A
{
private:
int y;
public:
B() : A(1, 2)
{
cout << "B()" << endl;
}
~B()
{
cout << "~B()" << endl;
}
};
int main()
{
cout << "A size is " << sizeof(A) << endl;
cout << "B size is " << sizeof(B) << endl;
B b1; // A() B() ~B() ~A()
// A a;
return 0;
}
+46
View File
@@ -0,0 +1,46 @@
// 继承中同名成员的处理方法
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class A
{
public:
int x;
A(int x) : x(x) {}
void show()
{
cout << "x = " << x << endl;
}
};
class B : public A
{
private:
int x;
public:
// B(int x) : A(x)
// {
// // 就近原则: this->x 是 B 类的,不是父类 A 的
// this->x = x + 20;
// }
B(int x) : A(x), x(x + 20)
{
}
void showX()
{
cout << "x = " << x << endl;
}
};
int main()
{
B b1(10);
b1.show(); // 从 A 类继承过来的方法,打印的是 A 类的 x
b1.showX(); // B 类自己的,打印自己的 a
return 0;
}
+85
View File
@@ -0,0 +1,85 @@
// 编写一个名为 String 的类,表示字符串。重载赋值运算符 = ,使其能够执行字符串的赋值操作。
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class String
{
private:
char *str;
public:
String(const char *s = NULL) // 构造函数: 默认参数为NULL,表示构造一个空字符串
{
if (s == NULL)
str = NULL;
else
{
str = new char[strlen(s) + 1];
strcpy(str, s);
}
}
String(const String &s)
{
if (s.str == NULL)
str = NULL;
else
{
str = new char[strlen(s.str) + 1];
strcpy(str, s.str);
}
}
~String()
{
if (str != NULL) // 如果str不为空,删除str
delete[] str;
}
public:
String &operator=(const String &s)
{
if (str == s.str)
return *this;
if (str != NULL) // 如果str不为空,则先删除str
delete[] str; // 删除的目的是为了防止内存泄漏
if (s.str == NULL) // 如果s.str为空,则str也为空
str = NULL;
else
str = new char[strlen(s.str) + 1]; // +1 是为了存放'\0'
strcpy(str, s.str);
return *this; // 返回当前对象的引用
}
void print()
{
if (str != NULL)
cout << str << endl;
else
cout << "NULL" << endl;
}
};
int main()
{
String s1("hello");
s1.print();
String *s2 = new String("world");
s2->print();
s1 = "xi'an";
s2 = &s1;
s2->print();
return 0;
}
+40
View File
@@ -0,0 +1,40 @@
// 编写一个名为 Date 的类,表示日期。重载相等运算符 == ,使其能够比较两个日期是否相等。
// 【提示】类中包含year,
// month, day三个变量。
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class Date
{
private:
int year, month, day;
public:
Date(int year, int month, int day) : year(year), month(month), day(day) {}
Date(const Date &d) : year(d.year), month(d.month), day(d.day) {}
~Date() {}
public:
bool operator==(const Date &d)
{
if (year == d.year && month == d.month && day == d.day)
{
return true;
}
return false;
}
};
int main()
{
Date d1(2020, 10, 1);
Date d2(2020, 10, 1);
Date d3(2020, 10, 2);
cout << (d1 == d2) << endl; // 1 表示 true
cout << (d1 == d3) << endl; // 0 表示 false
return 0;
}
+62
View File
@@ -0,0 +1,62 @@
// 编写一个名为 Matrix 的类,表示矩阵。重载乘法运算符 *,使其能够执行两个矩阵的乘法操作。
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class Matrix
{
private:
int row, col;
int **matrix;
public:
Matrix(int row, int col) : row(row), col(col)
{
matrix = new int *[row];
for (int i = 0; i < row; i++)
matrix[i] = new int[col];
}
~Matrix()
{
for (int i = 0; i < row; i++)
delete[] matrix[i];
delete[] matrix;
}
public:
Matrix operator*(const Matrix &m)
{
Matrix result(row, m.col);
for (int i = 0; i < row; i++)
for (int j = 0; j < m.col; j++)
for (int k = 0; k < col; k++)
result.matrix[i][j] += matrix[i][k] * m.matrix[k][j];
return result;
}
friend ostream &operator<<(ostream &out, const Matrix &m)
{
for (int i = 0; i < m.row; i++)
{
for (int j = 0; j < m.col; j++)
out << m.matrix[i][j] << " ";
out << endl;
}
return out;
}
friend istream &operator>>(istream &in, Matrix &m)
{
for (int i = 0; i < m.row; i++)
for (int j = 0; j < m.col; j++)
in >> m.matrix[i][j];
return in;
}
};
int main()
{
}
+36
View File
@@ -0,0 +1,36 @@
// 编写一个名为 Complex 的类,表示复数。重载加法运算符 + ,使其能够执行两个复数的加法操作。
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class Complex
{
private:
double real, imag; // 实部和虚部
public:
Complex(double real, double imag) : real(real), imag(imag) {}
Complex(const Complex &other) : real(other.real), imag(other.imag) {}
~Complex() {}
public:
Complex operator+(const Complex &other)
{
return Complex(real + other.real, imag + other.imag);
}
void show()
{
cout << real << " + " << imag << "i" << endl;
}
};
int main()
{
Complex c1(1, 2);
Complex c2(3, 4);
Complex c3 = c1 + c2;
c3.show(); // 4 + 6i
return 0;
}
+42
View File
@@ -0,0 +1,42 @@
// 假设有三个类,Animal(动物),Mammal(哺乳动物)和 Dog(狗)。Animal 类具有一个成员函数 eat() ,用于输出动物吃的食物。Mammal 类继承自 Animal 类,并添加了一个成员函数 giveBirth() ,用于输出哺乳动物的生育方式。Dog 类继承自 Mammal 类,并添加了一个成员函数 bark() ,用于输出狗的叫声。请在给定的类定义中完成代码,并实现相应的成员函数。
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class Animal
{
public:
void eat()
{
cout << "Animal eat" << endl;
}
};
class Mammal : public Animal
{
public:
void giveBirth()
{
cout << "Mammal give birth" << endl;
}
};
class Dog : public Mammal
{
public:
void bark()
{
cout << "Dog bark" << endl;
}
};
int main()
{
Dog dog;
dog.eat(); // Animal eat
dog.giveBirth(); // Mammal give birth
dog.bark(); // Dog bark
return 0;
}
+20
View File
@@ -0,0 +1,20 @@
// 编写一个名为 MatrixArray 的类,表示矩阵数组。重载乘法运算符 *,使其能够执行两个矩阵积操作。重载[] 运算符,实现返回某一个行的一维数组并对数组进行设置值或访问值。
// 【提示】构造函数提供行数与列数的参数,初始值为0。
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class MatrixArray
{
private:
int row, col;
int **matrix;
};
int main()
{
return 0;
}
+42
View File
@@ -0,0 +1,42 @@
// 假设有两个类,Shape(形状)和 Rectangle(矩形)。Shape 类具有一个成员函数 getArea() ,用于计算形状的面积。Rectangle 类继承自 Shape 类,并添加了两个成员变量 width(宽度)和 height(高度)。请在给定的类定义中完成代码,并实现 Rectangle 类的 getArea() 函数来计算矩形的面积。
// 【提示】Shape的类设计如下,表示为抽象类(getArea() 是纯虚函数):
// class Shape
// {
// public:
// virtual double getArea() const = 0;
// };
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class Shape
{
public:
virtual double getArea() const = 0;
};
class Rectangle : public Shape
{
private:
double width, height;
public:
Rectangle(double width, double height) : width(width), height(height) {}
~Rectangle() {}
public:
double getArea() const // 重写父类的纯虚函数,const 可以保证不会修改成员变量的值
{
return width * height;
}
};
int main()
{
Shape *shape = new Rectangle(3, 4);
cout << shape->getArea() << endl; // 12
return 0;
}
+44
View File
@@ -0,0 +1,44 @@
// 多继承(同属一个超级父类)产生的问题
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class A
{
public:
int x;
};
class B : virtual public A
{
public:
B()
{
x = 50;
}
};
class C : virtual public A
{
public:
C()
{
x = 100;
}
};
class D : public C, public B
{
};
int main()
{
D d1;
cout << d1.x << endl;
d1.x = 0; // x 是从 B 来的,还是从 C 来的? C ,使用就近原则
cout << d1.x << endl;
return 0;
}
+66
View File
@@ -0,0 +1,66 @@
// 初尝多态
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
// 抽象类:
// 至少有一个纯虚函数的类
// 抽象类不能实现对象
class AbstractCaculator // 定义计算器
{
protected: // 使用保护权限(目的是使子类可以访问,而其他类不可访问)
int a, b;
public:
void setA(int a) { this->a = a; }
void setB(int b) { this->b = b; }
public:
// 扩展功能,让子类去实现
virtual int getResult() = 0; // 纯虚函数,声明函数并赋值为 0
};
class AddCa : public AbstractCaculator
{
// 必须要去实现纯虚函数
int getResult()
{
return a + b;
}
};
class SubCa : public AbstractCaculator
{
// 必须要去实现纯虚函数
int getResult()
{
return a - b;
}
};
// 多态的体现:
// 1) 定义函数时,形参的类型为父类对象的指针
// 2) 调用函数时,实参的类型为子类对象的指针
int Result(AbstractCaculator *caculator, int a, int b)
{
caculator->setA(a);
caculator->setB(b);
return caculator->getResult();
}
int main()
{
// 抽象类型不能去定义对象
// error: cannot declare variable a1 to be of abstract type AbstractCaculator
// AbstractCaculator a1;
AddCa *a2 = new AddCa;
cout << Result(a2, 10, 20) << endl;
cout << Result(new SubCa, 10, 20) << endl; // new SubCa 返回的是一个临时对象,不需要 delete
delete a2;
// delete new SubCa; // error: cannot delete expression of type SubCa
return 0;
}
+41
View File
@@ -0,0 +1,41 @@
// 向上类型转换
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class Printer
{
public:
void open()
{
cout << "打印机正在开机..." << endl;
}
};
class DellPrinter : public Printer
{
void open()
{
cout << "Dell打印机..." << endl;
}
};
class HuaweiPrinter : public Printer
{
void open()
{
cout << "Huawei打印机..." << endl;
}
};
int main()
{
DellPrinter dellprinter;
// 多态: 通过父类的引用或指针调用子类对象的成员
// 子类对象自动向上转换位父类的类型
Printer &printer = dellprinter;
printer.open(); // 输出: 打印机正在开机...
return 0;
}
+21
View File
@@ -0,0 +1,21 @@
// 将父类的函数改为虚函数
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
clacc Printer
{
public:
virtual void open()
{
cout << ""
}
}
int main()
{
return 0;
}
+88
View File
@@ -0,0 +1,88 @@
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class Animal
{
protected:
string name;
float price;
public:
Animal(const string &name, float price)
{
this->name = name;
this->price = price;
}
virtual void buy(); // 类内声明的虚函数
};
// 类外实现类中的虚函数
void Animal::buy()
{
cout << "小宠物 " << name << " 卖了 " << price << endl;
}
class Dog : public Animal
{
private:
int age;
public:
Dog(string name, float price, int age) : Animal(name, price), age(age)
{
}
virtual void buy() // 重写父类的虚函数
{
cout << age << " 岁小狗 " << name << " 卖了 " << price << endl;
}
void eat() // 扩展的新功能
{
cout << name << " 喝酒" << endl;
}
};
class Cat : public Animal
{
private:
int age;
public:
Cat(string name, float price) : Animal(name, price)
{
}
virtual void buy() // 重写父类的虚函数
{
cout << "小猫 " << name << " 卖了 " << price << endl;
}
void eat() // 扩展的新功能
{
cout << name << " 吃鱼" << endl;
}
};
class AnimalShop
{
public:
// 多态应用之一
void buy(Animal *animal)
{
cout << "-----动物之家正在出售小宠物-----" << endl;
animal->buy();
cout << "-----出售结束-----" << endl;
delete animal; // 释放堆区空间
}
};
int main()
{
AnimalShop shop;
Dog dog("旺财", 1000, 3);
// 多态的应用
shop.buy(&dog);
shop.buy(new Cat("小花", 500));
return 0;
}
+49
View File
@@ -0,0 +1,49 @@
// 函数模版
/*
template <class T>
函数返回值 函数名(T &n1, T &n2)
{
// 函数体
}
*/
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
namespace my
{
// 推荐使用 typename 而不是 class,因为 typename 更通用
template <typename T>
void swap(T &a, T &b)
{
a ^= b;
b ^= a;
a ^= b;
}
// 函数模版重载: 用于不同类型的参数
template <typename T1, typename T2>
void swap(T1 &a, T2 &b)
{
a ^= b;
b ^= a;
a ^= b;
}
}
int main()
{
int a = 2, b = 6;
cout << a << ", " << b << endl;
my::swap(a, b); // 自动推演类型: swap<int>(a, b)
cout << a << ", " << b << endl;
char c = 30;
cout << a << ", " << (int)c << endl;
my::swap(a, c); // 自动推演类型
cout << a << ", " << (int)c << endl;
return 0;
}
+55
View File
@@ -0,0 +1,55 @@
// 使用函数模版实现对 char 和 int 数组的排序和打印
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
template <typename T>
void sort(T arr[], int size)
{
for (int i = 0; i < size - 1; i++)
{
int min = i;
for (int j = i + 1; j < size; j++)
{
if (arr[min] > arr[j])
{
min = j;
}
}
if (min != i)
{
arr[i] ^= arr[min];
arr[min] ^= arr[i];
arr[i] ^= arr[min];
// T temp = arr[i];
// arr[i] = arr[min];
// arr[min] = temp;
}
}
}
template <typename T>
void printArr(T arr[], int size)
{
for (int i = 0; i < size; i++)
cout << arr[i] << " ";
cout << endl;
}
int main()
{
int arr1[] = {1, 3, 5, 7, 9, 2, 4, 6, 8, 0};
char arr2[] = {'a', 'c', 'e', 'G', 'I', 'b', 'd', 'f', 'h', 'j'};
int size1 = sizeof(arr1) / sizeof(arr1[0]);
int size2 = sizeof(arr2) / sizeof(arr2[0]);
sort(arr1, size1);
sort(arr2, size2);
printArr(arr1, size1);
printArr(arr2, size2);
return 0;
}
+37
View File
@@ -0,0 +1,37 @@
// 多态本质:
// 父类引用或指针指向子类对象,通过父类指针或引用来(操作子类对象)调用子类中重写的成员函数
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class Animal
{
public:
virtual void speak()
{
cout << "动物在唱歌..." << endl;
}
};
class Dog : public Animal
{
public:
void speak()
{
cout << "狗在唱歌..." << endl;
}
};
void DoBusiness(Animal &animal)
{
animal.speak();
}
int main()
{
Dog dog;
DoBusiness(dog);
return 0;
}
+41
View File
@@ -0,0 +1,41 @@
#include <iostream>
using namespace std;
// 前置声明,否则会报错,因为下面的友元函数模版中使用了Pair模版
template <typename T1, typename T2>
class Pair;
template <typename T1, typename T2>
ostream &operator<<(ostream &out, const Pair<T1, T2> &p);
template <typename T1, typename T2>
class Pair
{
// 使用外部实现友元函数的方式,需要添加<>空泛型标识,否则编译器会认为是重复声明
friend ostream &operator<<<>(ostream &out, const Pair<T1, T2> &p);
private:
T1 first;
T2 second;
public:
Pair(T1 f, T2 s) : first(f), second(s) {}
T1 getFirst() const { return first; }
T2 getSecond() const { return second; }
};
template <typename T1, typename T2>
ostream &operator<<(ostream &out, const Pair<T1, T2> &p)
{
out << p.getFirst() << " " << p.getSecond();
return out;
}
int main()
{
Pair<string, int> p1 = Pair<string, int>("x", 20);
Pair<string, string> p2 = Pair<string, string>("name", "disen");
// cout << p1 << endl;
cout << p1 << "," << p2 << endl;
return 0;
}
+36
View File
@@ -0,0 +1,36 @@
#include <iostream>
using namespace std;
template <typename T1, typename T2>
class Pair
{
// 使用友元函数模版的方式,可以避免重复声明
template <typename U1, typename U2>
friend ostream &operator<<(ostream &out, const Pair<U1, U2> &p);
private:
T1 first;
T2 second;
public:
Pair(T1 f, T2 s) : first(f), second(s) {}
T1 getFirst() const { return first; }
T2 getSecond() const { return second; }
};
template <typename U1, typename U2>
ostream &operator<<(ostream &out, const Pair<U1, U2> &p)
{
out << p.getFirst() << " " << p.getSecond();
return out;
}
int main()
{
Pair<string, int> p1 = Pair<string, int>("x", 20);
Pair<string, string> p2 = Pair<string, string>("name", "disen");
// cout << p1 << endl;
cout << p1 << "," << p2 << endl;
return 0;
}
+42
View File
@@ -0,0 +1,42 @@
// 请简述static_cast、dynamic_cast和reinterpret_cast的区别,并给出示例代码进行说明。
// static_cast :
// 静态转换,用于基本类型的转换、隐式转换、向上转换和非多态类之间的转换。它在编译时进行类型检查,并且只能用于具有相关性的类型之间的转换。因为没有运行时类型检查,不能用于多态类的向下转换(即将基类指针或引用转换为派生类指针或引用)。
#include <iostream>
using namespace std;
int num = 10;
double res = static_cast<double>(num); // 将整数类型转换为浮点数类型
class Base
{
public:
virtual void foo()
{
cout << "基类 foo() 函数" << endl;
} // 基类的虚函数
};
class Derived : public Base
{
public:
void bar()
{
cout << "派生类 bar() 函数" << endl;
} // 派生类的成员函数
void foo()
{
cout << "派生类 foo() 函数" << endl;
} // 派生类的虚函数: 重写基类的虚函数
};
int main()
{
Base *p = new Derived();
Derived *dp = static_cast<Derived *>(p); // 向下转换,不安全
dp->bar(); // 但是可以调用派生类的成员函数
dp->foo();
return 0;
}
+41
View File
@@ -0,0 +1,41 @@
// 请简述static_cast、dynamic_cast和reinterpret_cast的区别,并给出示例代码进行说明。
// dynamic_cast :
// 动态转换,用于多态类之间的转换,即在基类指针或引用和派生类指针或引用之间进行转换。它在运行时进行类型检查,如果转换是安全的,则返回转换后的指针或引用;如果转换不安全,则返回空指针或引用。dynamic_case 只能用于具有虚函数的类之间的转换。
#include <iostream>
using namespace std;
class Base
{
public:
virtual void foo() { cout << "基类 foo() 函数" << endl; }
};
class Derived : public Base
{
public:
void bar() { cout << "派生类 bar() 函数" << endl; }
void foo() { cout << "派生类 foo() 函数" << endl; }
};
int main()
{
Base *p = new Derived();
Derived *dp = dynamic_cast<Derived *>(p); // 向下转换,安全
dp->bar(); // 可以调用派生类的成员函数
dp->foo(); // 可以调用派生类的虚函数
Base *p1 = new Base();
Derived *dp1 = dynamic_cast<Derived *>(p1); // 向下转换,不安全
dp1->bar();
// dp1->foo();
Derived *dp2 = new Derived();
Base *p2 = dynamic_cast<Base *>(dp2); // 向上转换,安全
p2->foo();
return 0;
}
+25
View File
@@ -0,0 +1,25 @@
// 请简述static_cast、dynamic_cast和reinterpret_cast的区别,并给出示例代码进行说明。
// reinterpret_cast :
// 重新解释转换,用于不同类型之间的强制转换,即将一个指针或引用转换为完全不相关的类型。它可以将任何指针类型转换为其他指针类型,也可以将整数类型转换为指针类型,反之亦然。它非常危险,不进行类型检查。
#include <iostream>
using namespace std;
int num = 10;
int *np = &num;
double *dp = reinterpret_cast<double *>(np); // 将整数类型指针转换为浮点数类型指针
class Base
{
public:
virtual void foo() {}
};
int main()
{
Base *base = new Base();
int *intp = reinterpret_cast<int *>(base); // 将基类指针转换为整数类型指针
return 0;
}
+87
View File
@@ -0,0 +1,87 @@
// 设计一个模板类 Stack,实现基本的堆栈功能,包括入栈(push)、出栈(pop)、获取栈顶元素(top)和判断栈是否为空(isEmpty)等操作。
// 【提示】Stack栈结构的特性是FILO(先进后出)
#include <iostream>
using namespace std;
template <typename T>
class Stack
{
private:
int capacity; // 容量
int size; // 已存数量计数器
T *arr; // 指向数组的指针
public:
Stack(int capacity)
{
this->capacity = capacity;
this->arr = new T[capacity];
this->size = 0;
}
Stack(const Stack<T> &other)
{
this->capacity = other.capacity;
this->size = other.size;
this->arr = new T[capacity];
for (int i = 0; i < size; i++)
{
this->arr[i] = other.arr[i];
}
}
~Stack()
{
delete[] arr;
}
public:
// & 用于返回引用,支持链式调用
Stack &push(T val)
{
if (size == capacity)
{
cout << "栈已经满了!" << endl;
return *this;
}
arr[size++] = val;
return *this; // 返回自身,支持链式调用
}
T pop()
{
if (size == 0)
{
cout << "栈已经空了!" << endl;
return -1;
}
return arr[--size]; // 先减再取,因为size是计数器,指向下一个空位
}
T top()
{
if (size == 0)
{
cout << "栈已经空了!" << endl;
return -1;
}
return arr[size - 1]; // 直接取顶部元素
}
string isEmpty()
{
return size == 0 ? "栈空" : "栈未空"; // 判断计数器是否为 0,为 0 表示栈空
}
};
int main()
{
Stack<int> s(5);
s.push(1).push(2).push(3).push(4).push(5);
cout << s.pop() << endl; // 5
cout << s.pop() << endl; // 4
cout << s.top() << endl; // 3
cout << s.isEmpty() << endl; // 栈未空
cout << s.pop() << endl; // 3
cout << s.pop() << endl; // 2
cout << s.pop() << endl; // 1
cout << s.isEmpty() << endl; // 栈空
cout << s.pop() << endl; // 栈已经空了! -1
return 0;
}
+96
View File
@@ -0,0 +1,96 @@
// 设计一个模板类 Queue,实现基本的队列功能,包括入队(enqueue)、出队(dequeue)、获取队首元素(front)和判断队列是否为空(isEmpty)等操作。
// 【提示】Queue队列结构的特性是FIFO(先进先出)
#include <iostream>
using namespace std;
template <typename T>
class Queue
{
private:
int capacity; // 容量
int size; // 已存数量计数器
T *arr; // 指向数组的指针
public:
Queue(int capacity)
{
this->capacity = capacity;
this->arr = new T[capacity];
this->size = 0;
}
Queue(const Queue<T> &other)
{
this->capacity = other.capacity;
this->size = other.size;
this->arr = new T[capacity];
for (int i = 0; i < size; i++)
{
this->arr[i] = other.arr[i];
}
}
~Queue()
{
delete[] arr;
}
public:
Queue &enqueue(T val)
{
if (size == capacity)
{
cout << "队列已满!" << endl;
return *this;
}
arr[size++] = val;
return *this;
}
T dequeue() // 取出队首元素,并删除
{
if (size == 0)
{
cout << "队列已空!" << endl;
return -1;
}
T val = arr[0]; // 取出队首元素
for (int i = 0; i < size - 1; i++)
{
arr[i] = arr[i + 1]; // 元素前移
}
size--; // 计数器减一
return val; // 返回队首元素
}
T front() // 只是返回队首元素,并不删除
{
if (size == 0)
{
cout << "队列已空!" << endl;
return -1;
}
return arr[0];
}
string isEmpty()
{
return size == 0 ? "队列空" : "队列未空";
}
};
int main()
{
Queue<float> q(5);
q.enqueue(1.1).enqueue(2.2).enqueue(3.3).enqueue(4.4).enqueue(5.5);
cout << q.dequeue() << endl; // 1.1
cout << q.front() << endl; // 2.2
q.enqueue(6.6);
q.enqueue(7.7); // 队列已满
q.dequeue();
q.dequeue();
cout << q.dequeue() << endl; // 4.4
cout << q.isEmpty() << endl; // 队列未空
cout << q.dequeue() << endl; // 5.5
cout << q.dequeue() << endl; // 6.6
cout << q.isEmpty() << endl; // 队列空
cout << q.dequeue() << endl; // 队列已空
return 0;
}
+154
View File
@@ -0,0 +1,154 @@
// 设计一个模板类 LinkedList,实现基本的链表功能,包括插入节点(insert)、删除节点(remove)、查找节点(search)等操作, 通过全局友元函数,实现列表的打印功能。
#include <iostream>
using namespace std;
template <typename T>
class LinkedList
{
// // 使用友元函数模版的方式,可以避免重复声明
template <typename U>
friend ostream &operator<<(ostream &out, const LinkedList<U> &list);
private:
// 只能在类内部使用的私有结构体
struct Node // 节点结构体,定义数据结构,包括数据和指针
{
T val; // 节点的值
Node *next; // 指向下一个节点的指针
Node(T val) // 构造函数,用于初始化节点
{
this->val = val;
this->next = nullptr;
}
};
Node *head;
int size;
public:
LinkedList()
{
this->head = nullptr;
this->size = 0;
}
LinkedList(const LinkedList<T> &other)
{
this->head = nullptr;
this->size = 0;
Node *p = other.head;
while (p != nullptr)
{
this->insert(p->val);
p = p->next;
}
size = other.size; // 计数器赋值
}
~LinkedList()
{
Node *p = head; // 从头节点开始
while (p != nullptr) // 当前节点不为空时,循环
{
Node *q = p->next; // 保存下一个节点的指针
delete p; // 删除当前节点
p = q; // p 重新指向保存的下一个节点 q
}
size = 0; // 计数器清零
}
public:
LinkedList &insert(T val)
{
Node *node = new Node(val); // 创建新节点
if (head == nullptr)
{
head = node; // 如果头节点为空,直接将新节点赋值给头节点
return *this; // 如果头节点为空,直接返回
}
Node *p = head;
while (p->next != nullptr)
{
p = p->next; // 找到最后一个节点
}
p->next = node; // 将新节点插入到最后一个节点的后面
size++; // 计数器加一
return *this; // 返回当前对象
}
LinkedList &remove(T val)
{
if (head == nullptr)
{
cout << "链表为空,无法删除" << endl;
return *this; // 如果头节点为空,直接返回
}
Node *p = head;
if (p->val == val) // 如果头节点的值等于要删除的值
{
head = p->next; // 将头节点的下一个节点赋值给头节点
delete p; // 删除头节点
size--; // 计数器减一
return *this; // 返回当前对象
}
while (p->next != nullptr && p->next->val != val)
{
p = p->next; // 找到要删除的节点的前一个节点
}
if (p->next == nullptr) // 找到最后也没有找到要删除的节点
{
cout << "未找到要删除的节点" << endl;
return *this; // 如果未找到要删除的节点,直接返回
}
Node *q = p->next; // 保存要删除的节点
p->next = q->next; // 将要删除的节点的下一个节点赋值给要删除的节点的前一个节点的下一个节点
delete q; // 删除要删除的节点
size--; // 计数器减一
return *this; // 返回当前对象
}
void search(T val)
{
Node *p = head;
while (p != nullptr && p->val != val)
{
p = p->next; // 找到要删除的节点的前一个节点
}
if (p == nullptr) // 找到最后也没有找到要查找的节点
{
cout << val << " 未找到" << endl;
return;
}
cout << val << " 已找到" << endl;
return;
}
};
template <typename U>
ostream &operator<<(ostream &out, const LinkedList<U> &list)
{
/*
typename 关键字告诉编译器 LinkedList<U>::Node 是一个类型名,而不是一个成员变量
LinkedList<U>::Node 表示 LinkedList<U> 类的嵌套类型 Node
*p 指向 Node 类型的对象
list.head 是链表的头节点指针
*/
// 注意,由于 Node 是一个内部嵌套结构体,所以在使用时需要使用 typename 关键字来指示其是一个类型名
typename LinkedList<U>::Node *p = list.head; // 从头节点开始
while (p != nullptr) // 遍历链表
{
out << p->val << " "; // 输出节点的值
p = p->next; // 指向下一个节点
}
out << endl; // 最后输出换行
return out; // 返回输出流对象
}
int main()
{
LinkedList<double> list; // 创建一个链表
list.insert(1.1).insert(2.2).insert(3.3).insert(4.4).insert(5.5); // 插入节点
cout << list; // 输出链表
list.search(3.9); // 查找节点
list.search(4.4); // 查找节点
list.remove(3.3); // 删除节点
cout << list; // 输出链表
return 0;
}
+43
View File
@@ -0,0 +1,43 @@
// 请完成以下程序的代码,实现数组的循环迭代
#include <iostream>
using namespace std;
template <typename T>
class Iterator
{
public:
T *data;
int size;
int currentIndex;
public:
Iterator(T *d, int s) : data(d), size(s), currentIndex(0) {}
T getCurrent() // 获取当前元素
{
return data[currentIndex];
}
void next() // 迭代器前进的代码
{
currentIndex = (currentIndex + 1) % size; // 对 size 取余用于循环
}
void previous() // 迭代器后退的代码
{
currentIndex = (currentIndex - 1 + size) % size; // + size 用于防止负数,对 size 取余用于循环
}
};
int main()
{
int *p = new int[5]{1, 2, 3, 4, 5}; // 创建数组
Iterator<int> it(p, 5); // 创建迭代器对象
int cnt = 0; // 计数器,用于控制循环次数
while (cnt++ < 5)
{
cout << it.getCurrent() << endl; // 输出当前元素
it.next(); // 迭代器前进
}
return 0;
}
+134
View File
@@ -0,0 +1,134 @@
/********************************************************************
假设有一个基类 Animal 和两个派生类 Cat 和 Dog,它们的定义如下 : class Animal
{
public:
virtual ~Animal() {}
};
class Cat : public Animal
{
public:
void meow()
{
std::cout << "Meow!" << std::endl;
}
};
class Dog : public Animal
{
public:
void bark()
{
std::cout << "Woof!" << std::endl;
}
};
请完成以下任务:
1) 在 main 函数中创建一个 Animal 类型的指针,并使用 dynamic_cast 将其转换为 Cat 类型的指针。如果转换成功,调用 meow 函数让猫发出"Meow!"声音;如果转换失败,输出转换失败的提示信息。
2) 在 main 函数中创建一个 Animal 类型的指针,并使用 dynamic_cast 将其转换为 Dog 类型的指针。如果转换成功,调用 bark 函数让狗发出"Woof!"声音;如果转换失败,输出转换失败的提示信息。
3) 在 main 函数中创建一个 Cat 类型的指针,并使用 dynamic_cast 将其转换为 Animal 类型的指针。输出转换成功的提示信息。
4) 在 main 函数中创建一个 Dog 类型的指针,并使用 dynamic_cast 将其转换为 Animal 类型的指针。输出转换成功的提示信息。
【提示】可以尝试
try
{
}
catch (int e)
{
}
异常尝试捕获语法确定转换是否成功。
********************************************************************/
#include <iostream>
#include <typeinfo>
using namespace std;
class Animal
{
public:
virtual ~Animal() {}
};
class Cat : public Animal
{
public:
void meow()
{
cout << "Meow!" << endl;
}
};
class Dog : public Animal
{
public:
void bark()
{
cout << "Woof!" << endl;
}
};
int main()
{
Animal *ap = new Animal(); // 创建一个 Animal 类型的指针
try
{
Cat *cp = dynamic_cast<Cat *>(ap); // 将其转换为 Cat 类型的指针
if (cp)
cp->meow();
else
throw 1;
}
catch (int &e)
{
cout << "dynamic_cast 将 Animal 转换为 Cat 失败" << endl;
}
Animal *ap2 = new Animal(); // 创建一个 Animal 类型的指针
try
{
Dog *dp = dynamic_cast<Dog *>(ap2); // 将其转换为 Dog 类型的指针
if (dp)
dp->bark();
else
throw 1;
}
catch (...)
{
cout << "dynamic_cast 将 Animal 转换为 Dog 失败" << endl;
}
Cat *cp2 = new Cat(); // 创建一个 Cat 类型的指针
try
{
Animal *ap3 = dynamic_cast<Animal *>(cp2); // 将其转换为 Animal 类型的指针
cout << "dynamic_cast 将 Cat 转换为 Animal 成功" << endl;
}
catch (...)
{
cout << "dynamic_cast 将 Cat 转换为 Animal 失败" << endl;
}
Dog *dp2 = new Dog(); // 创建一个 Dog 类型的指针
try
{
Animal *ap4 = dynamic_cast<Animal *>(dp2); // 将其转换为 Animal 类型的指针
cout << "dynamic_cast 将 Dog 转换为 Animal 成功" << endl;
}
catch (...)
{
cout << "dynamic_cast 将 Dog 转换为 Animal 失败" << endl;
}
delete ap;
delete ap2;
delete cp2;
delete dp2;
return 0;
}
+105
View File
@@ -0,0 +1,105 @@
#include <iostream>
#include <typeinfo>
class Animal
{
public:
virtual ~Animal() {}
};
class Cat : public Animal
{
public:
void meow()
{
std::cout << "Meow!" << std::endl;
}
};
class Dog : public Animal
{
public:
void bark()
{
std::cout << "Woof!" << std::endl;
}
};
int main()
{
// 任务1:将Animal类型指针转换为Cat类型指针
Animal *animal1 = new Cat();
try
{
Cat *cat = dynamic_cast<Cat *>(animal1);
if (cat)
{
cat->meow();
}
else
{
throw 1;
}
}
catch (int e)
{
std::cout << "转换失败:无法将Animal类型转换为Cat类型。" << std::endl;
}
// 任务2:将Animal类型指针转换为Dog类型指针
Animal *animal2 = new Dog();
try
{
Dog *dog = dynamic_cast<Dog *>(animal2);
if (dog)
{
dog->bark();
}
else
{
throw 2;
}
}
catch (int e)
{
std::cout << "转换失败:无法将Animal类型转换为Dog类型。" << std::endl;
}
// 任务3:将Cat类型指针转换为Animal类型指针
Cat *cat2 = new Cat();
try
{
Animal *animal3 = dynamic_cast<Animal *>(cat2);
if (animal3)
{
std::cout << "转换成功:Cat类型成功转换为Animal类型。" << std::endl;
}
}
catch (const std::bad_cast &e)
{
std::cout << "转换失败:" << e.what() << std::endl;
}
// 任务4:将Dog类型指针转换为Animal类型指针
Dog *dog2 = new Dog();
try
{
Animal *animal4 = dynamic_cast<Animal *>(dog2);
if (animal4)
{
std::cout << "转换成功:Dog类型成功转换为Animal类型。" << std::endl;
}
}
catch (const std::bad_cast &e)
{
std::cout << "转换失败:" << e.what() << std::endl;
}
// 释放内存
delete animal1;
delete animal2;
delete cat2;
delete dog2;
return 0;
}
+21
View File
@@ -0,0 +1,21 @@
// 抛出异常
#include <iostream>
using namespace std;
int div(int a, int b)
{
if (b == 0)
{
throw "除数不能为0";
}
return a / b;
}
int main()
{
cout << "-----aaaaa-----" << endl;
int ret = div(20, 0);
cout << ret << endl;
return 0;
}
+81
View File
@@ -0,0 +1,81 @@
// 异常的多态
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class Exception
{
private:
string msg;
public:
Exception()
{
this->msg = "";
cout << this << " : Exception()" << endl;
}
Exception(const string &msg)
{
this->msg = msg;
cout << this << " : Exception(const string &)" << endl;
}
Exception(const Exception &other)
{
this->msg = other.msg;
cout << this << " : Exception(const Exception &)" << endl;
}
~Exception() { cout << this << " : ~Exception()" << endl; }
public:
string &getMsg() // const 表示该成员函数不会修改成员变量
{
return this->msg;
}
};
class ZeroDivisionException : public Exception
{
public:
ZeroDivisionException() {}
ZeroDivisionException(const string &msg) : Exception(msg) {}
};
class OutOfRangeException : public Exception
{
public:
OutOfRangeException() {}
OutOfRangeException(const string &msg) : Exception(msg) {}
};
int main(int argc, char const *argv[])
{
int n = atoi(argv[1]);
try
{
if (n == 0)
// 抛出子类的异常对象
throw ZeroDivisionException("除数为不能 0");
else if (n >= 20)
throw OutOfRangeException("范围越界 20");
else if (n == 10)
throw Exception("n 不能为 10");
else
cout << "n = " << n << endl;
}
catch (ZeroDivisionException &error) // 接子类引用
{
cout << "精准捕获到子类异常: " << error.getMsg() << endl;
}
catch (Exception &e) // 接父类引用(要写到子类异常的后面)
{
cout << "捕获异常: " << e.getMsg() << endl;
}
catch (...) // 捕获所有异常
{
cout << "捕获所有异常" << endl;
}
return 0;
}
+37
View File
@@ -0,0 +1,37 @@
// exception 的使用
// invalid_argument: 用于处理无效参数异常
#include <iostream>
#include <cstdlib>
#include <exception>
#include <cstdio>
using namespace std;
int maxVal(int a, int b)
{
if (a == b)
{
char msg[100];
sprintf(msg, "两个参数不能相等,a = %d, b = %d", a, b);
throw invalid_argument(msg);
}
return a > b ? a : b;
}
int main(int argc, char const *argv[])
{
int a = atoi(argv[1]);
int b = atoi(argv[2]);
try
{
int ret = maxVal(a, b);
cout << "maxValue is " << ret << endl;
}
catch (exception &error)
{
cout << "error: " << error.what() << endl; // what() 返回异常信息,异常信息是一个字符串
}
return 0;
}
+83
View File
@@ -0,0 +1,83 @@
// 异常与模版
// 异常处理循环问题的示例
#include <iostream>
#include <exception>
using namespace std;
template <typename T>
class Stack
{
private:
T *mData; // 数据
int mCapacity; // 容量
int mIndex; // 索引
public:
// -1 表示栈为空
Stack(int capacity) : mCapacity(capacity), mIndex(-1)
{
this->mData = new T[this->mCapacity];
}
~Stack()
{
delete[] this->mData; // 释放内存
mData = nullptr; // 防止野指针
}
public:
T pop() throw(out_of_range)
{
if (mIndex < 0)
throw out_of_range("当前栈未空,请先压栈");
return this->mData[this->mIndex--];
}
Stack<T> &push(const T &item) throw(out_of_range)
{
if (mIndex >= mCapacity - 1) // >= 表示栈满 , mCapacity - 1 表示栈顶
throw out_of_range("当前栈已满,请先出栈");
this->mData[++this->mIndex] = item;
return *this; // 返回当前对象,支持链式编程
}
T &at(int index) throw(out_of_range)
{
// mIndex == -1 表示栈为空,index < 0 表示索引小于 0index > mIndex 表示索引大于栈顶
if (mIndex == -1 || index < 0 || index > mIndex)
throw out_of_range("当前栈为空或位置无效");
return this->mData[index];
}
int size() const
{
return this->mIndex + 1;
}
};
int main()
{
Stack<int> s1(5);
s1.push(10).push(20).push(30);
for (int i = 0; i < s1.size(); i++)
cout << s1.at(i) << endl;
cout << "*** 弹出数据 ***" << endl;
// 清空数据
while (1)
{
try
{
cout << s1.pop() << endl;
}
catch (exception &e)
{
cout << "error: " << e.what() << endl;
break; // 异常处理: 跳出循环
}
}
cout << "*** 弹栈完成,重新打印 ***" << endl;
for (int i = 0; i < s1.size(); i++)
cout << s1.at(i) << endl;
return 0;
}
+91
View File
@@ -0,0 +1,91 @@
// 自定义标准异常类
#include <iostream>
#include <exception>
using namespace std;
class OutOfRangeError : public exception
{
public:
virtual const char *what() const throw()
{
return "访问索引越界";
}
};
template <typename T>
class Stack
{
private:
T *mData; // 数据
int mCapacity; // 容量
int mIndex; // 索引
public:
// -1 表示栈为空
Stack(int capacity) : mCapacity(capacity), mIndex(-1)
{
this->mData = new T[this->mCapacity];
}
~Stack()
{
delete[] this->mData; // 释放内存
mData = nullptr; // 防止野指针
}
public:
T pop() throw(OutOfRangeError)
{
if (mIndex < 0)
throw OutOfRangeError();
return this->mData[this->mIndex--];
}
Stack<T> &push(const T &item) throw(OutOfRangeError)
{
if (mIndex >= mCapacity - 1) // >= 表示栈满 , mCapacity - 1 表示栈顶
throw OutOfRangeError();
this->mData[++this->mIndex] = item;
return *this; // 返回当前对象,支持链式编程
}
T &at(int index) throw(OutOfRangeError)
{
// mIndex == -1 表示栈为空,index < 0 表示索引小于 0index > mIndex 表示索引大于栈顶
if (mIndex == -1 || index < 0 || index > mIndex)
throw OutOfRangeError();
return this->mData[index];
}
int size() const
{
return this->mIndex + 1;
}
};
int main()
{
Stack<int> s1(5);
s1.push(10).push(20).push(30);
for (int i = 0; i < s1.size(); i++)
cout << s1.at(i) << endl;
cout << "*** 弹出数据 ***" << endl;
// 清空数据
while (1)
{
try
{
cout << s1.pop() << endl;
}
catch (exception &e)
{
cout << "error: " << e.what() << endl;
break; // 异常处理: 跳出循环
}
}
cout << "*** 弹栈完成,重新打印 ***" << endl;
for (int i = 0; i < s1.size(); i++)
cout << s1.at(i) << endl;
return 0;
}
+30
View File
@@ -0,0 +1,30 @@
// 处理异常的语法
// 捕获基本数据类型的异常
#include <iostream>
using namespace std;
int div(int a, int b)
{
if (b == 0)
{
throw "除数不能为0"; // 抛出异常
}
return a / b;
}
int main()
{
cout << "-----aaaaa-----" << endl;
int ret = 0;
try // 捕获异常
{
ret = div(20, 0);
}
catch (const char *err) // 捕获异常
{
cout << "异常: " << err << endl; // 处理异常
}
cout << "ret = " << ret << endl;
return 0;
}
+75
View File
@@ -0,0 +1,75 @@
// throw 的限制
// 在使用 throw 抛出异常信息时,受到函数声明处的 throw() 声明的
// 可抛出异常类型的限制。
// 如: 函数内可以抛出任何异常
#include <iostream>
using namespace std;
class A
{
public:
int n;
public:
A(int n = 0) : n(n) {}
};
// throw() 声明表示不抛出任何异常
// throw(int, char, double, A) 表示可以抛出 int, char, double, A 类型的异常
void show(int x) throw(int, char, double, A)
{
switch (x)
{
case 1:
throw 0;
break;
case 2:
throw 'a';
break;
case 3:
throw "abc";
break;
case 4:
throw 1.25;
break;
case 5:
throw A(100); // 抛出自定义类的对象
break;
// default 可以不写,因为前面已经覆盖了所有情况
}
cout << "x = " << x << endl;
}
int main()
{
cout << "输入一个整数: ";
int x;
cin >> x;
try
{
show(x);
}
catch (const int &error)
{
cout << "捕获异常: " << error << endl;
}
catch (const char &error)
{
cout << "捕获异常: " << error << endl;
}
catch (const char *error)
{
cout << "捕获异常: " << error << endl;
}
catch (const double &error)
{
cout << "捕获异常: " << error << endl;
}
catch (const A &error)
{
cout << "捕获异常: " << error.n << endl;
}
return 0;
}
+71
View File
@@ -0,0 +1,71 @@
// 限制函数抛出异常
// throw() 声明表示不抛出任何异常
#include <iostream>
using namespace std;
class A
{
public:
int n;
public:
A(int n = 0) : n(n) {}
};
// throw() 声明表示不抛出任何异常
void show(int x) throw()
{
switch (x)
{
case 1:
throw 0;
break;
case 2:
throw 'a';
break;
case 3:
throw "abc";
break;
case 4:
throw 1.25;
break;
case 5:
throw A(100); // 抛出自定义类的对象
break;
// default 可以不写,因为前面已经覆盖了所有情况
}
cout << "x = " << x << endl;
}
int main()
{
cout << "输入一个整数: ";
int x;
cin >> x;
try
{
show(x);
}
catch (const int &error)
{
cout << "捕获异常: " << error << endl;
}
catch (const char &error)
{
cout << "捕获异常: " << error << endl;
}
catch (const char *error)
{
cout << "捕获异常: " << error << endl;
}
catch (const double &error)
{
cout << "捕获异常: " << error << endl;
}
catch (const A &error)
{
cout << "捕获异常: " << error.n << endl;
}
return 0;
}
+29
View File
@@ -0,0 +1,29 @@
// 栈解旋(unwinding):当抛出异常时,会调用所有对象的析构函数
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class A
{
public:
A() { cout << "A()" << endl; }
~A() { cout << "~A()" << endl; }
};
int main()
{
try
{
A a1;
// 栈解旋(unwinding):当抛出异常时,会调用所有对象的析构函数
throw 0; // 抛出异常时,则会调用 a1 的析构函数
}
catch (...) // ... 表示其他异常,可以不写,写的话必须放在最后
{
cout << "异常被处理" << endl;
}
return 0;
}
+45
View File
@@ -0,0 +1,45 @@
// 异常接口声明
// 如: 结构体作为异常对象
#include <iostream>
#include <cstring>
using namespace std;
struct ERROR_S
{
string title; // 错误信息
int errnum; // 错误码
} error_1; // ERROR_S error_1; // error_1 是一个全局变量
void test1(int n) throw(ERROR_S, int)
{
if (n == 0)
{
error_1.title = "n 参数不能为 0";
error_1.errnum = 1;
throw error_1;
}
else if (n == 1)
{
throw 2;
}
cout << "n = " << n << endl;
}
int main()
{
try
{
test1(1);
}
catch (const ERROR_S &error)
{
cout << "捕获异常: " << error.title << endl;
cout << "错误码: " << error.errnum << endl;
}
catch (...)
{ // ... 表示其他异常
cout << "捕获其他异常" << endl;
}
return 0;
}
+53
View File
@@ -0,0 +1,53 @@
// 异常变量生命周期
// 如 1: 抛出对象,接收对象,会使用拷贝构造函数
// 异常变量生命周期
// 如 1: 抛出对象,接收引用,不会使用拷贝构造函数,会直接使用构造函数
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class Exception
{
private:
string msg;
public:
Exception()
{
this->msg = "";
cout << this << "Exception()" << endl;
}
Exception(const string &msg)
{
this->msg = msg;
cout << this << "Exception(const string &)" << endl;
}
Exception(const Exception &other)
{
this->msg = other.msg;
cout << this << "Exception(const Exception &)" << endl;
}
~Exception() { cout << this << "~Exception()" << endl; }
public:
string &getMsg() // const 表示该成员函数不会修改成员变量
{
return this->msg;
}
};
int main()
{
try
{
throw Exception("异常");
}
catch (Exception e)
{
cout << "捕获异常: " << e.getMsg() << endl;
}
return 0;
}
+51
View File
@@ -0,0 +1,51 @@
// 异常变量生命周期
// 如 1: 抛出对象,接收引用,不会使用拷贝构造函数,会直接使用构造函数
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class Exception
{
private:
string msg;
public:
Exception()
{
this->msg = "";
cout << this << "Exception()" << endl;
}
Exception(const string &msg)
{
this->msg = msg;
cout << this << "Exception(const string &)" << endl;
}
Exception(const Exception &other)
{
this->msg = other.msg;
cout << this << "Exception(const Exception &)" << endl;
}
~Exception() { cout << this << "~Exception()" << endl; }
public:
string &getMsg() // const 表示该成员函数不会修改成员变量
{
return this->msg;
}
};
int main()
{
try
{
throw Exception("异常");
}
catch (Exception &e)
{
cout << "捕获异常: " << e.getMsg() << endl;
}
return 0;
}
+53
View File
@@ -0,0 +1,53 @@
// 异常变量生命周期
// 如 1: 抛出对象(堆区),捕获对象(堆区),会使用拷贝构造函数,需要手动释放内存
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class Exception
{
private:
string msg;
public:
Exception()
{
this->msg = "";
cout << this << "Exception()" << endl;
}
Exception(const string &msg)
{
this->msg = msg;
cout << this << "Exception(const string &)" << endl;
}
Exception(const Exception &other)
{
this->msg = other.msg;
cout << this << "Exception(const Exception &)" << endl;
}
~Exception() { cout << this << "~Exception()" << endl; }
public:
string &getMsg() // const 表示该成员函数不会修改成员变量
{
return this->msg;
}
};
int main()
{
try
{
// 要使用 new 创建对象,否则会在栈区创建对象,导致异常抛出时,会调用析构函数
throw new Exception("异常"); // 在堆区创建对象
}
catch (Exception *e)
{
cout << "捕获异常: " << e->getMsg() << endl;
delete e; // 手动释放内存
}
return 0;
}
+33
View File
@@ -0,0 +1,33 @@
// const修饰的成员虚函数,能否在子类中重写?请举例说明
// 可以
#include <bits/stdc++.h>
using namespace std;
class A
{
public:
virtual void show() const
{
cout << "A" << endl;
}
};
class B : public A
{
public:
virtual void show() const override
{
cout << "B" << endl;
}
};
int main()
{
A *p = new B;
p->show(); // B
B *q = new B;
q->show(); // B
return 0;
}
+34
View File
@@ -0,0 +1,34 @@
// throw() 和throw有什么区别?请举例说明
// 1. throw()是函数声明,表示该函数不会抛出任何异常
// 2. throw是抛出异常的关键字
// 3. throw()是函数声明,throw是语句
#include <bits/stdc++.h>
using namespace std;
void show(int n) throw() // throw() 表示异常抛出限制: 不抛出任何异常
// void show(int n) throw(int ) // throw(int) 表示只抛出 int 类型的异常
{
if (n == 0)
{
throw 0; // throw 0 表示抛出 int 类型的异常
}
cout << "n = " << n << endl;
}
int main()
{
try
{
show(0);
}
catch (const int &e)
{
cout << "捕获异常: " << e << endl;
}
catch (...)
{
cout << "捕获其他异常" << endl;
}
return 0;
}
+58
View File
@@ -0,0 +1,58 @@
// 编写一个C++ 程序,读取一个文件的内容并打印到控制台。 在文件读取过程中处理以下异常情况: 1)如果文件打开失败,则抛出一个自定义的异常对象 FileOpenException。 2)如果文件读取过程中发生错误,则抛出一个自定义的异常对象 FileReadException。
// 【要求】在 main 函数中调用文件读取函数,并捕获并处理可能抛出的异常。
#include <bits/stdc++.h>
using namespace std;
// 自定义异常类
class FileOpenException : public exception
{
public:
const char *what() const throw()
{
return "文件打开异常";
}
};
class FileReadException : public exception
{
public:
const char *what() const throw()
{
return "文件读取异常";
}
};
int main()
{
FILE *fp = fopen("test.txt", "r");
try
{
if (fp == NULL)
{
throw FileOpenException(); // 抛出自定义文件打开异常
}
}
catch (exception &e)
{
cout << "捕获异常: " << e.what() << endl;
}
char ch;
try
{
// EOF 表示到达文件结尾
if (fscanf(fp, "%c", &ch) == EOF)
throw FileReadException(); // 抛出自定义文件读取异常
}
catch (exception &e)
{
cout << "捕获异常: " << e.what() << endl;
}
fclose(fp);
return 0;
}
+54
View File
@@ -0,0 +1,54 @@
// 编写一个C++ 程序,动态分配一个整型数组,并根据用户输入的索引值访问数组元素。 在访问数组元素时处理以下异常情况: 1)如果数组分配内存失败,则抛出一个自定义的异常对象 MemoryAllocationException。 2)如果用户输入的索引超出了数组的范围,则抛出一个自定义的异常对象 IndexOutOfBoundsException。
// 【要求】在 main 函数中调用动态内存分配函数,并捕获并处理可能抛出的异常。
#include <bits/stdc++.h>
using namespace std;
// 自定义异常类
class MemoryAllocationException : public exception
{
public:
const char *what() const throw()
{
return "内存分配异常";
}
};
class IndexOutOfBoundsException : public exception
{
public:
const char *what() const throw()
{
return "索引越界异常";
}
};
int main()
{
int *arr = new int[10]; // 动态分配一个整型数组
try
{
if (arr == NULL)
throw MemoryAllocationException();
// 当不抛出异常时,继续执行数组的赋值操作
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
arr[3] = 4; // 其余元素会被初始化为 0
int n;
cout << "请输入索引值: ";
cin >> n;
if (n < 0 || n > 9)
throw IndexOutOfBoundsException();
// 当不抛出异常时,继续执行数组的访问操作
cout << "arr[" << n << "] = " << arr[n] << endl;
}
catch (exception &e)
{
cout << "捕获异常: " << e.what() << endl;
}
return 0;
}
+39
View File
@@ -0,0 +1,39 @@
// 编写一个C++ 函数 divideNumbers,接受两个整数作为参数,并返回它们的商。 在函数中处理以下异常情况: 1)如果除数为0,则抛出 std::logic_error 异常类的一个实例,并传递适当的错误消息。 2)如果被除数为0,则抛出 std::runtime_error 异常类的一个实例,并传递适当的错误消息。
// 【要求】在 main 函数中调用 divideNumbers,并捕获并处理可能抛出的异常。
#include <bits/stdc++.h>
using namespace std;
int divideNumbers(int a, int b)
{
if (b == 0)
throw std::logic_error("除数为0");
if (a == 0)
throw std::runtime_error("被除数为0");
return a / b; // 结果为整数商
}
int main()
{
try
{
cout << "请输入两个整数:" << endl;
int a, b;
cin >> a >> b;
cout << a << "" << b << " 的商为:" << divideNumbers(a, b) << endl;
}
catch (const std::logic_error &e)
{
cout << "捕获异常:" << e.what() << endl;
}
catch (const std::runtime_error &e)
{
cout << "捕获异常:" << e.what() << endl;
}
catch (...)
{
cout << "捕获其他异常" << endl;
}
return 0;
}
+33
View File
@@ -0,0 +1,33 @@
// 编写一个C++ 程序,读取一个文件的内容并打印到控制台。 在文件读取过程中处理以下异常情况: 1)如果文件打开失败,则抛出 std::runtime_error 异常类的一个实例,并传递适当的错误消息。 2)如果文件读取过程中发生错误,则抛出 std::ios_base::failure 异常类的一个实例,并传递适当的错误消息。
// 【要求】在 main 函数中调用文件读取函数,并捕获并处理可能抛出的异常。
#include <bits/stdc++.h>
using namespace std;
int main()
{
FILE *fp = fopen("test.txt", "r");
try
{
if (fp == NULL)
throw std::runtime_error("文件打开异常");
}
catch (const std::runtime_error &e)
{
cout << "捕获异常:" << e.what() << endl;
}
char ch;
try
{
if (fscanf(fp, "%c", &ch) == EOF)
throw std::ios_base::failure("文件读取异常");
}
catch (const std::ios_base::failure &e)
{
cout << "捕获异常:" << e.what() << endl;
}
fclose(fp);
return 0;
}
+1
View File
@@ -0,0 +1 @@
helloworld
+27
View File
@@ -0,0 +1,27 @@
// stl 标准模板库开发
// 初次使用:
// vector 存放基础类型的数据示例
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
v1.push_back(6);
// 创建迭代器
vector<int>::iterator it;
for (it = v1.begin(); it != v1.end(); it++)
{
cout << *it << " ";
}
return 0;
}
+46
View File
@@ -0,0 +1,46 @@
// 存放类对象的数据 vector
#include <bits/stdc++.h>
using namespace std;
class Student
{
friend ostream &operator<<(ostream &out, const Student &stu);
private:
string name;
int age;
public:
Student(const string &name, int age)
{
this->name = name;
this->age = age;
}
};
ostream &operator<<(ostream &out, const Student &stu)
{
out << "name: " << stu.name << ", age: " << stu.age;
return out;
}
int main()
{
vector<Student> v;
v.push_back(Student("zhangsan", 20));
v.push_back(Student("lisi", 21));
v.push_back(Student("wangwu", 22));
v.push_back(Student("zhaoliu", 23));
v.pop_back(); // 删除最后一个元素
// 创建迭代器
vector<Student>::iterator it = v.end();
while (it != v.begin())
{
cout << *(--it) << endl; // 重载了<<运算符
}
return 0;
}
+48
View File
@@ -0,0 +1,48 @@
// 基于 d3.cpp 的改进
// vector 存放对象的指针
#include <bits/stdc++.h>
using namespace std;
class Student
{
friend ostream &operator<<(ostream &out, const Student *stu);
private:
string name;
int age;
public:
Student(const string &name, int age)
{
this->name = name;
this->age = age;
}
};
ostream &operator<<(ostream &out, const Student *stu)
{
out << "name: " << stu->name << ", age: " << stu->age;
return out;
}
int main()
{
vector<Student *> v;
v.push_back(new Student("张三", 18));
v.push_back(new Student("李四", 19));
v.push_back(new Student("王五", 20));
v.pop_back(); // 删除最后一个元素
// 创建迭代器
vector<Student *>::iterator it = v.end();
while (it != v.begin())
{
it--;
cout << *it << endl; // 重载了<<运算符
delete *it; // 释放空间
}
return 0;
}
+52
View File
@@ -0,0 +1,52 @@
// vector 的嵌套使用示例
#include <bits/stdc++.h>
using namespace std;
int main()
{
// 注意: vector<vector<int> > vs; 防止编辑器自动格式化为 >>
vector<vector<int> > vs; // 嵌套容器
vector<int> v1, v2, v3;
for (int i = 0; i < 9; i++)
{
switch (i / 3)
{
case 0:
v1.push_back(i + 1);
break;
case 1:
v2.push_back(i + 1);
break;
case 2:
v3.push_back(i + 1);
break;
}
}
vs.push_back(v1);
vs.push_back(v2);
vs.push_back(v3);
// for (int i = 0; i < vs.size(); i++)
// {
// for (int j = 0; j < vs[i].size(); j++)
// {
// cout << vs[i][j] << " ";
// }
// cout << endl;
// }
vector<vector<int> >::iterator it;
for (it = vs.begin(); it != vs.end(); it++)
{
vector<int>::iterator it2;
for (it2 = (*it).begin(); it2 != (*it).end(); it2++)
{
cout << *it2 << " ";
}
cout << endl;
}
return 0;
}
+15
View File
@@ -0,0 +1,15 @@
// 【场景】字符串反转
// 编写一个函数 reverseString,接受一个字符串作为参数,并返回该字符串的反转版本。
#include <bits/stdc++.h>
using namespace std;
string reverseString(string &other)
{
}
int main()
{
cout << "反转后的字符串 hello 为: " << reverseString("hello") << endl;
return 0;
}
+28
View File
@@ -0,0 +1,28 @@
// 【场景】向量vector求和
// 编写一个函数 sumVector,接受一个整数向量作为参数,并返回向量中所有元素的和。
#include <iostream>
#include <vector>
using namespace std;
int sumVector(vector<int> &vec)
{
int sum = 0;
vector<int>::iterator it = vec.begin();
while (it != vec.end())
{
sum += *it;
it++;
}
return sum;
}
int main()
{
vector<int> v;
for (int i = 0; i < 10; i++)
v.push_back(i);
cout << "向量中所有元素的和为: " << sumVector(v) << endl;
return 0;
}
+34
View File
@@ -0,0 +1,34 @@
// 【场景】双端队列操作
// 编写一个程序,演示双端队列(deque)的以下操作: 1)在队列的前面插入一个元素。 2)在队列的后面插入一个元素。 3)从队列的前面删除一个元素。 4)从队列的后面删除一个元素。
#include <iostream>
#include <deque>
using namespace std;
template <typename T>
void print(deque<T> &dq)
{
// cout << "******************" << endl;
typename deque<T>::iterator it = dq.begin();
for (; it != dq.end(); it++)
{
cout << *it << endl;
}
cout << "------------------" << endl;
}
int main()
{
deque<string> dq;
dq.push_front("push_front");
dq.push_back("push_back");
cout << "删除前: " << endl;
print(dq);
dq.pop_front();
dq.pop_back();
cout << "删除后: " << endl;
print(dq);
return 0;
}
+43
View File
@@ -0,0 +1,43 @@
// 【场景】栈操作
// 编写一个程序,演示栈(stack)的以下操作: 1)将一个元素压入栈顶。 2)从栈顶弹出一个元素。 3)获取栈顶元素的值。
#include <iostream>
#include <stack>
using namespace std;
template <typename T>
void print(stack<T> &s)
{
cout << "当前栈中元素(按出栈顺序)打印如下: " << endl;
// 先将栈转存到另一个临时栈中,临时栈的元素顺序和原栈相反
// 临时栈用于打印,而不改变原栈的元素顺序
stack<T> tmp = s; // 拷贝原来的栈,避免改变原栈
while (!tmp.empty())
{
cout << tmp.top() << " ";
tmp.pop();
}
cout << endl;
cout << "------------------" << endl;
}
int main()
{
stack<int> stk;
stk.push(1);
stk.push(2);
stk.push(3);
stk.push(4);
stk.push(5);
print(stk);
cout << "从栈顶弹出一个元素: " << stk.top() << endl;
stk.pop();
print(stk);
cout << "获取栈顶元素的值: " << endl;
cout << stk.top() << endl;
return 0;
}
+21
View File
@@ -0,0 +1,21 @@
// 【场景】字符串拼接
// 编写一个函数 concatenateStrings,接受两个字符串作为参数,并返回它们的拼接结果。
#include <iostream>
#include <string>
using namespace std;
string concatenateStrings(const string &str1, const string &str2)
{
return str1 + str2;
}
int main()
{
string s1 = "hello";
string s2 = "world";
s1 = concatenateStrings(s1, " "); // 先拼接一个空格
s1 = concatenateStrings(s1, s2); // 再拼接 s2
cout << s1 << endl;
return 0;
}
+45
View File
@@ -0,0 +1,45 @@
// 【场景】向量vector查找
// 编写一个函数 findElement,接受一个整数向量和一个目标值作为参数,并返回目标值在向量中的索引。
// 如果目标值不存在于向量中,则返回 -1。
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int findElement(vector<int> &v, const int &item)
{
int index = 0;
vector<int>::iterator it = v.begin();
while (it != v.end())
{
if (*it == item) // 如果找到了
return index; // 返回索引
index++; // 索引加一
it++; // 迭代器指向下一个元素
}
return -1;
}
string print(int item)
{
if (item == -1)
return "目标不存在";
else
{
// to_string() 函数可以将整数转换为字符串
// 需要 #include <string> 头文件
// 需要 c++11 标准,编译时加上 -std=c++11
string s = to_string(item);
return s;
}
}
int main()
{
int arr[] = {1, 2, 3, 4, 5, 4, 6, 7, 8, 9, 10}; // 定义数组
vector<int> v1(arr, arr + sizeof(arr) / sizeof(arr[0])); // 将数组转换为向量
cout << "5 在目标值向量中的索引为: " << print(findElement(v1, 5)) << endl; // 4
cout << "11 在目标值向量中的索引为: " << print(findElement(v1, 11)) << endl; // -1
return 0;
}
+3
View File
@@ -0,0 +1,3 @@
// 【场景】双端队列排序
// 编写一个程序,演示如何使用双端队列对一组整数进行排序。
// 【提示】应用插入排序算法: 从第2个开始,确认当前位置数在前面有序(从小到大或从大到小)队列中的位置。
+62
View File
@@ -0,0 +1,62 @@
// 【场景】栈应用
// 编写一个程序,判断给定的字符串是否是有效的括号序列。例如,对于字符串 "{[()]}",应返回 true;对于字符串 "{[(])}",应返回 false。
// 【提示】华为OD的机试题
#include <iostream>
#include <stack>
#include <string>
using namespace std;
bool judge(const string &str)
{
stack<char> stk;
int max_depth = 0;
for (char c : str) // 增强型 for 循环,用于遍历字符串
{
if (c == '(' || c == '[' || c == '{')
{
stk.push(c); // 当左括号出现时,入栈
}
else if (c == ')' || c == ']' || c == '}') // 当碰到右括号时,开始匹配
{
if (stk.empty()) // 如果栈已经为空,说明没有左括号与之匹配
{
return false; // 返回无法匹配
}
char top = stk.top(); // 拿出栈顶元素
if (max_depth < stk.size())
max_depth = stk.size();
stk.pop(); // 弹出栈顶元素
// 判断本次取出的字符与栈顶元素是否匹配,即左右括号是否匹配,不匹配则返回无效,匹配则继续进行下一轮遍历循环
if ((c == ')' && top != '(') || (c == ']' && top != '[') || (c == '}' && top != '{'))
{
return false; // 括号不匹配
}
}
}
cout << "括号栈的最大深度为: " << max_depth << endl;
return stk.empty(); // 栈为空表示括号完全匹配 = 有效 = true = 1,反之,如果栈非空,说明还有未匹配的左括号,返回无效 = false = 0
}
string print(bool flag)
{
if (flag) // flag 为 true = 1
return "有效";
else
return "无效";
}
int main()
{
// string str1 = "{[(])}";
// string str1 = "{(])}";
string str1 = "{[(s[s])s]}[][[[[()]]]]";
cout << "括号序列 " << str1 << " 是否有效: " << print(judge(str1)) << endl; // 1
return 0;
}
+468
View File
@@ -0,0 +1,468 @@
# STL(一)
### 1. string 容器
> string 也是字符串的类型,可以理解时它是用于存放字符的容器。
#### 1.1 String 和 c 风格字符串对比
```
1) char * 是一个指针,string 是一个类
2) string 封装了很多实用的成员方法
查找 find,拷贝 copy,删除 delete 替换 replace,插入 insert
3) 不用考虑内存释放和越界
string 管理 char*所分配的内存。每一次 string 的复制,取值都由 string 类负责维
护,不用担心复制越界和取值越界等。
```
#### 1.2 string 容器 api
```
// 构造函数
string(); //创建一个空的字符串 例如: string str;
string(const string& str);//使用一个 string 对象初始化另一个 string 对象
string(const char* s);//使用字符串 s 初始化
string(int n, char c); //使用 n 个字符 c 初始化
// 赋值
string& operator=(const char* s);//char*类型字符串 赋值给当前的字符串
string& operator=(const string &s);//把字符串 s 赋给当前的字符串
string& operator=(char c);//字符赋值给当前的字符串
string& assign(const char *s);//把字符串 s 赋给当前的字符串
string& assign(const char *s, int n); //把字符串 s 的前 n 个字符赋给当前的字
符串
string& assign(const string &s);//把字符串 s 赋给当前字符串
string& assign(int n, char c);//用 n 个字符 c 赋给当前字符串
string& assign(const string &s, int start, int n);//将 s 从 start 开始 n 个
字符赋值给字符串
// 取值
char& operator[](int n);//通过[]方式取字符
char& at(int n);//通过 at 方法获取字符
// 字符串拼接
string& operator+=(const string& str);//重载+=操作符
string& operator+=(const char* str);//重载+=操作符
string& operator+=(const char c);//重载+=操作符
string& append(const char *s);//把字符串 s 连接到当前字符串结尾
string& append(const char *s, int n);//把字符串 s 的前 n 个字符连接到当前字符串结尾
string& append(const string &s); //同 operator+=()
string& append(const string &s, int pos, int n);//把字符串 s 中从 pos 的 n 个字符连接到当前字符串结尾
string& append(int n, char c);//在当前字符串结尾添加 n 个字符 c
// 查找与替换
int find(const string& str, int pos = 0) const; //查找 str 第一次出现位置, 从 pos 开始查找, 如果未查找到返回 -1
int find(const char* s, int pos = 0) const; //查找 s 第一次出现位置,从 pos 开始查找
int find(const char* s, int pos, int n) const; //从 pos 位置查找 s 的前 n个字符第一次位置
int find(const char c, int pos = 0) const; //查找字符 c 第一次出现位置
int rfind(const string& str, int pos = npos) const;//查找 str 最后一次位置,从 pos 开始查找
int rfind(const char* s, int pos = npos) const;//查找 s 最后一次出现位置, 从 pos 开始查找
int rfind(const char* s, int pos, int n) const;//从 pos 查找 s 的前 n 个字符最后一次位置
int rfind(const char c, int pos = 0) const; //查找字符 c 最后一次出现位置
string& replace(int pos, int n, const string& str); //替换从 pos 开始 n 个字符为字符串 str
string& replace(int pos, int n, const char* s); //替换从 pos 开始的 n 个字符为字符串 s
// 比较 ,返回值 0:相等, 1:大于s, -1:小于s
int compare(const string &s) const;//与字符串 s 比较
int compare(const char *s) const;//与字符串 s
// 截取子字符串
string substr(int pos = 0, int n = npos) const;//返回由 pos 开始的 n 个字符组成的字符串
// 插入与删除
string& insert(int pos, const char* s); //插入字符串
string& insert(int pos, const string& str); //插入字符串
string& insert(int pos, int n, char c);//在指定位置插入 n 个字符 c
string& erase(int pos, int n = npos);//删除从pos 开始的 n 个
// 转成 char *
const char * c_str() 将当前字符串转成 char *
// 获取字符串的长度
int size();
```
### 2. vector 容器
#### 2.1 vector 与数组的区别
vector 的结构类同于数组,数组是静态的,在定义时确定的数组的大小;而 vector 是动态的,添加元素时如果空间不足时,则会自动扩容器(2^n);整体来说,vector 比较灵活的,而且 vector 是类模板,可以存放任意类型的元素。
#### 2.2 vector 迭代器
> vector 维护一个线性空间(线性连续空间), vector 迭代器所需要的操作行为 是(\*,->, ++, --, +, -, +=, -=)运算符重载等。vector 支持随机存取,vector 提供的是随机访问迭代器(Random Access Iterator), 迭代器中的元素即为 vector 容器中的元素。
<font color=red>【重要说明】: vector 容器扩容之后,原迭代器则无效,需要重新获取获取器</font>
```
所谓动态增加大小,并不是在原空间之后续接新空间(因为无法保证原空间之后尚有可配置的空间),而是一块更大的内存空间,然后将原数据拷贝新空间,并释放原空间。
因此,对 vector 的任何操作,一旦引起空间的重新配置,指向原vector的所有迭代器就都失效了。这是程序员容易犯的一个错误,务必小心。
```
#### 2.3 vector 容器 api
##### 3.3.1 构造函数
```
// 构造函数
vector<T> v; //采用模板实现类实现,默认构造函数
vector(v.begin(), v.end());//将 v[begin(), end())区间中的元素拷贝给本身。
vector(n, elem);//构造函数将 n 个 elem 拷贝给本身。
vector(const vector &vec);//拷贝构造函
```
##### 3.3.2 赋值操作
```c++
assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem);//将 n 个 elem 拷贝赋值给本身。
vector& operator=(const vector &vec);//重载等号操作符
swap(vec);// 将 vec 与本身的元素互换
```
##### 3.3.3 大小操作
```c++
int size(); // 返回容器中元素的个数
bool empty(); //判断容器是否为空, 返回bool值(0, 1)
void resize(int num); //重新指定容器的长度为 num,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
void resize(int num, elem); //重新指定容器的长度为 num,若容器变长,则以 elem 值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
int capacity(); //容器的容量
void reserve(int len); //容器预留 len 个元素长度,预留位置不初始化,元素不可访问。
```
##### 3.3.4 存取操作
```c++
at(int idx); //返回索引 idx 所指的数据,如果 idx 越界,抛出 out_of_range 异常。
operator[](int idx); //返回索引 idx 所指的数据,越界时,运行直接报错
front(); //返回容器中第一个数据元素
back(); //返回容器中最后一个数据元素
```
##### 3.3.5 插入和删除
```c++
insert(const_iterator pos, int count, T ele); //迭代器指向位置 pos 插入 count个元素 ele.
push_back(ele); //尾部插入元素 ele
pop_back();//删除最后一个元素
erase(const_iterator start, const_iterator end); //删除迭代器从 start 到 end 之间的元素, 删除[start, end)区间的所有元素
erase(const_iterator pos); //删除迭代器指向的元素
clear(); //删除容器中所有元素
```
#### 2.4 小技巧示例
##### 2.2.4.1 巧用 swap 收缩内存空间
> resize()+swap()实现 vector 收缩内存空间
```c++
resize(n);
vector<T>(v).swap(v);
```
### 3. deque 容器
#### 3.1 deque 基本概念
vector 容器是单向开口的连续内存空间,deque 则是一种双向开口的连续线性空间。
所谓的双向开口,意思是可以在头尾两端分别做元素的插入和删除操作,当然,vector 容器也可以在头尾两端插入元素,但是在其头部操作效率奇差,无法被接受。
qeque 容器和 vector 容器最大的差异:
```
1) 在于 deque 允许使用常数项时间对头端进行元素的插入和删除操作。
2) 在于 deque 没有容量的概念,因为它是动态的以分段连续空间组合而成,随时可以增加一段新的空间并链接起来。
3) deque 没有必须要提供所谓的空间保留(reserve)功能
4) 虽然deque容器也提供了 Random Access Iterator,但是它的迭代器并不是普通的指针,其复杂度和vector 不是一个量级,这当然影响各个运算的层面。因此,除非有必要,我们应该尽可能的使用vector,而不是deque。
5)对 deque 进行的排序操作,为了最高效率,可将 deque 先完整的复制到一个 vector 中,对 vector 容器进行排序,再复制回 deque。
```
#### 3.2 deque 实现原理
逻辑上,deque 容器是连续的空间, 是由一段一段的定量的连续空间构成。一旦有必要在 deque 前端或者尾端增加新的空间,便配置一段连续定量的空间,串接在 deque 的头端或者尾端。
deque 最大的工作就是维护这些分段连续的内存空间的整体性的假象,并提供随机存取的接口。
既然 deque 是分段连续内存空间,那么就必须有中央控制(map 实现的),维持整体连续的假象,数据结构的设计及迭代器的前进后退操作颇为繁琐。
中央控制: 连续小空间,由 map 实现,存放是地址,地址指向的另一个连续空间为缓冲区。
缓冲区:是 deque 的存储空间的主体。
#### 3.3 常用 API
##### 3.3.1 构造函数
```c++
deque<T> deqT;//默认构造形式
deque(beg, end);//构造函数将[beg, end)区间中的元素拷贝给本身。
deque(n, elem);//构造函数将 n 个 elem 拷贝给本身。
deque(const deque &deq);//拷贝构造函数。
```
##### 3.3.2 赋值操作
```c++
assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem);//将 n 个 elem 拷贝赋值给本身。
deque& operator=(const deque &deq); //重载等号运算符
swap(deq);// 将 deq 与本身的元素互换
```
##### 3.3.3 大小操作
```c++
deque.size();//返回容器中元素的个数
deque.empty();//判断容器是否为空
deque.resize(num);//重新指定容器的长度为 num,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
deque.resize(num, elem); //重新指定容器的长度为 num,若容器变长,则以 elem 值填充新位置,如果容器变短,则末尾超出容器长度的元素被删除。
```
##### 3.3.4 双端插入和删除
```c++
void push_back(elem);//在容器尾部添加一个数据
void push_front(elem);//在容器头部插入一个数据
void pop_back();//删除容器最后一个数据
void pop_front();//删除容器第一个数据
```
##### 3.3.5 数据存取
```c++
at(idx);//返回索引 idx 所指的数据,如果 idx 越界,抛出 out_of_range。
operator[]; //返回索引 idx 所指的数据,如果 idx 越界,不抛出异常,会直接出错。
front();//返回第一个数据。
back();//返回最后一个
```
如:operator[] 操作数据,超出范围之后,则会直接报错并不抛出异常
> 【注意】 string 泛型的 deque 默认分配 16 个, int 默认 128 个
##### 3.3.6 插入操作
```c++
void insert(iterator pos,T elem);//在 pos 位置插入一个 elem 元素的拷贝,返回新数据的位置。
void insert(iterator pos,int n,T elem);//在 pos 位置插入 n 个 elem 数据,无返回值。
void insert(iterator pos,iter_beg,iter_end);//在 pos 位置插入[beg,end)区间的数据,无返回值。
```
##### 3.3.7 删除操作
```c++
clear();//移除容器的所有数据
iterator erase(iterator beg,iterator end);//删除[beg,end)区间的数据,返回下一个数据的位置。
iterator erase(iterator pos);//删除 pos 位置的数据,返回下一个数据的位置。
```
### 4 stack 容器
#### 4.1 stack 基本概念
stack 是一种先进后出(First In Last Out,FILO)的数据结构,它只有一个出口,stack 容器允许新增元素、移除元素、取得栈顶元素,但是除了最顶端外,没有任何其他方法可以存取 stack 的其他元素。换言之,stack 不允许有遍历行为。
<img src="./E:/UserFiles/Videos/千锋物联网/第二阶段 C++语言/第二周/c++第九天课堂笔记.assets/image-20230803164259349.png" width=300>
#### 4.2 stack 没有迭代器
stack 所有元素的进出都必须符合”先进后出”的条件,只有 stack 顶端的元素,才有机会被外界取用。Stack 不提供遍历功能,也不提供迭代器。
#### 4.3 常用 API
##### 4.3.1 构造函数
```
stack<T> stkT;//stack 采用模板类实现, stack 对象的默认构造形式:
stack(const stack &stk);//拷贝构造函数
```
##### 4.3.2 赋值操作
```
stack& operator=(const stack &stk);//重载等号操作符
```
##### 4.3.3 数据存取
```c++
void push(elem);//向栈顶添加元素
void pop();//从栈顶移除第一个元素
T top();//返回栈顶元素
```
##### 4.3.4 大小操作
```
empty();//判断堆栈是否为空
size();//返回堆栈的大小
```
####
案例: 人员的淘汰方式(业绩从高到低、后入职)
```c++
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
class Worker;
class Date
{
friend Worker;
friend ostream &operator<<(ostream &cout, Date &date)
{
cout << date.year << "年" << date.month << "月" << date.day << "日";
return cout;
}
private:
int year;
int month;
int day;
public:
Date(int year, int month, int day)
{
this->year = year;
this->month = month;
this->day = day;
}
bool operator>(Date &other)
{
// cout << *this << " pk " << other << endl;
return year > other.year || (year == other.year && month > other.month) || (year == other.year && month == other.month && day > other.day);
}
bool operator<=(Date &other)
{
return year <= other.year && month <= other.month && day <= other.day;
}
};
class Worker
{
public:
string name; // 姓名
Date *hire_date; // 入职时间
double volume; // 业绩值
public:
Worker(const string &name, Date *hire_date, double volume)
{
this->name = name;
this->hire_date = hire_date;
this->volume = volume;
}
Worker(const Worker &other)
{
Date *hire_date = new Date(other.hire_date->year, other.hire_date->month, other.hire_date->day);
this->hire_date = hire_date;
this->name = other.name;
this->volume = other.volume;
}
Worker &operator=(const Worker &other)
{
this->hire_date->year = other.hire_date->year;
this->hire_date->month = other.hire_date->month;
this->hire_date->day = other.hire_date->day;
this->name = other.name;
this->volume = other.volume;
return *this;
}
~Worker()
{
if (hire_date)
delete hire_date;
hire_date = NULL;
}
void show()
{
cout << "name=" << name << ",hire_date=" << *hire_date << ",volume=" << volume << endl;
}
};
void sortByHireDate(Worker *p, int size)
{
for (int i = 0; i < size - 1; i++)
{
int min = i;
for (int j = i + 1; j < size; j++)
{
if (*(p[min].hire_date) > *(p[j].hire_date))
{
min = j;
}
}
if (min != i)
{
// cout << p[i].name << " 和 " << p[min].name << " 交换数据" << endl;
Worker tmp = p[i]; // 拷贝构造函数
p[i] = p[min]; // operator=重载
p[min] = tmp;
}
}
}
void sortByVolume(Worker *p, int size)
{
for (int i = 0; i < size - 1; i++)
{
int min = i;
for (int j = i + 1; j < size; j++)
{
if (p[min].volume < p[j].volume)
{
min = j;
}
}
if (min != i)
{
// cout << p[i].name << " 和 " << p[min].name << " 交换数据" << endl;
Worker tmp = p[i]; // 拷贝构造函数
p[i] = p[min]; // operator=重载
p[min] = tmp;
}
}
}
int main(int argc, char const *argv[])
{
Worker w1("disen", new Date(2020, 1, 15), 1000);
Worker w2("jack", new Date(2021, 1, 15), 100);
Worker w3("lucy", new Date(2020, 2, 15), 500);
Worker w4("mack", new Date(2020, 3, 25), 300);
Worker w5("judy", new Date(2022, 5, 18), 400);
Worker w6("rose", new Date(2023, 1, 10), 1200);
Worker m[] = {w1, w2, w3, w4, w5, w6};
// sortByHireDate(m, 6);
sortByVolume(m, 6);
vector<Worker> v1(m, m + 6);
stack<Worker> s1;
vector<Worker>::iterator it = v1.begin();
while (it != v1.end())
{
(*it).show();
s1.push(*it);
it++;
}
// 辞退2位新来的员工
// cout << "-----辞退2位新来的员工----" << endl;
cout << "-----业绩最差的2位员工----" << endl;
for (int i = 0; i < 2; i++)
{
s1.top().show();
s1.pop();
}
return 0;
}
```

Some files were not shown because too many files have changed in this diff Show More