Object-Oriented Programming¶
约 1133 个字 113 行代码 3 张图片 预计阅读时间 5 分钟
in c++
Lec1¶
string str1 = "foo, bar!";
ofstream fout("out.txt");
ifstream fin("out.txt");
string str2, str3;
fin >> str2 >> str3;
在这里我们使用两个字符串变量来接out.txt是因为其中的内容包含一个white space,也就是空格或者tab,这样会打断读取。最终得到的就是:str2 = foo,
str3 = bar!
Lec2¶
这节课展示了c++的抽象能力
- C语言在函数传递参数时如果将数组作为参数传入,其实数组是退化了的,传入的实际是指针,指向数组首元素:
//原先的:
void print_array(int arr[], int size) {
for (int i = 0; i < size; i++) {
cout << arr[i] << " ";
}
}
//如果这样写
void print_array(int arr[]) {
int size = sizeof(arr) / sizeof(arr[0]);
...
}
//这样写是错的,因为sizeof(arr)返回的是指针的大小,而不是数组的大小。
//因此不能这样写
- swap函数对数组中的元素没有交换效果
c++的处理方式是使用引用类型,也就是在函数参数中使用&符号:
- 函数重载:
在第一个函数中我们只考虑了int类型,如果想要支持多种类型,我们可以使用函数重载:
void print_array(int arr[], int size) {
for (int i = 0; i < size; i++) {
cout << arr[i] << " ";
}
}
void print_array(double arr[], int size) {
for (int i = 0; i < size; i++) {
cout << arr[i] << " ";
}
}
允许同名函数但是参数表不一样,会根据调用情况来决定使用哪个函数。
这是我们发现如果每次都写一个不同变量类型的函数很麻烦,因此c++引入了模板:
template <typename T>
void print_array(T arr[], int size) {
for (int i = 0; i < size; i++) {
cout << arr[i] << " ";
}
}
- 定义结构体也可以这样操作吗?
会发现问题出在比较上,因为结构体中包含多个变量,编译器不知道需要怎么比较、输出等操作,这时候需要自己进行定义:
struct Student {
int id;
string name;
bool operator<(const Student& s) {
return id < s.id;
}
};
ostream& operator<<(ostream& out, const Student& s) {
return out << "(" << s.id << "," << s.name << ")";
}
Lec3¶
STL
Container¶
-
Sequencial:
- array(static)
- vector(dynamic)动态数组
- deque
- forward_list(single linked)
- list(doubly-linked)双向链表
-
Associative
- set(keys)
- map(keys and values)
- multimap(允许重复key)
- multiset(允许重复key)
-
Unordered associative
- unordered_set,map,multiset,multimap
-
Adapters
- stack
- queue
- priority_queue
- insert函数:
就是在begin+4的位置插入5个10
- iterator方式遍历
也可以在这里使用auto:
因为在这里编译器可以根据后面的赋值判断出it的类型,但如果直接随便写一个auto it;
是没有意义的
也可以这样遍历:
这是一个语法糖,编译器将你写的东西转换成了iterator
如果需要对其中的内容进行修改:
将x声明为引用即可
注意
在进行遍历时,只有vector可以用 < 符号来进行终止判断,因为vector是连续内存,其他容器通常用it != container.end()
来判断(链表比较大小没有意义)
- Map
#include <map>
#include <string>
map<string, float> price;
price["snapple"] = 0.75;
price["coke"] = 0.50;
string item;
double total=0;
while (cin >> item)
total += price[item];
如果我们在进行输入的时候写进total的字符不是已知的snapple、coke,那么他其实会帮你插入这个字符,并将他的value设置为默认值0.0
int main() {
map<string, int> word_map;
for (const auto& w: {"we", "are", "not", "humans", "we", "are", "robots"})
++word_map[w];
for (const auto& [word, count]: word_map)
cout << count << " occurrences of word '" << word << "'\n";
}
这里运用了map的[]运算符和输出时的结构化绑定
- Algorithms
算法作用的对象都是迭代器,我们传入迭代器后算法进行操作,同一种算法可以作用于不同的容器,因为算法是不依赖于容器的,这样形成了算法与容器的解耦,提高了代码的复用性。
- reverse
可以看到reverse直接作用在vector本身,是直接对vector进行修改的
这样程序会报错segmentation fault,因为u没有初始化大小,默认是空的,因此也不会有begin这个位置,也就是说我们需要u中有数据
如果想要能够做到插入可以换一个迭代器:
还能够用algo来实现输出流:
但是这样我们输出的最后会多一个逗号,可以用一个头文件来解决:
这个头文件是在除了第一个元素以后的遍历中都保留操作然后我们就直接使用:
- erase
迭代器在erase后会失效,因此不能++li,需要重新赋值
Lec4¶
内存模型 Memory Model

-
Global 变量是可以跨文件访问的:使用
extern
关键字 -
Static 的全局变量不是外部可见的,只能在一个编译单元(.cpp)中使用
string s;
和 string *ps;
的区别:
- 前者是全局变量,后者是全局指针
- 前者在data段,后者在bss段
- 前者在main执行前初始化,后者在main中初始化 因为string本身是一个class,会有一个默认的构造函数进行初始化,而ps没有初始化每次跑结果都不一样
- 前者在程序结束时自动释放,后者需要手动释放
Referennce¶
对上面的三句话进行解释:
- 第一句进行一个声明,表示c是一个char类型的变量,占据1 byte,位置在某个地址address
- 第二句话表示p是一个指针,里面有8个bytes,表示一个地址,这个地址指向的是c的地址address
- 但三句话表示r是一个引用,可以完全把c和r看作是等价的,只是一个别名,位置还是在address
但是区别在于指针可以重新赋值,而引用不能
同时引用是必须要初始化的不能为空:
但是可以作为函数参数进行传递:
这样是可以的
还有一种是class:
引用的意义在于:
- 可以作为函数参数传递
- 可以作为函数返回值
引用的限制:
- 引用不能嵌套
- 没有引用类型的指针,但是有指针的引用(可以是&,不能是 &)
- 数组中不能放yinyong
Dynamic Memory Allocation¶
类似于malloc free DMA使用new delete
但对于非原生数据类型,比如class,使用new进行定义的时候不仅会malloc一块内存,还会使用构造函数进行初始化,这样就确保了定义时不仅是一块内存,而是初始化后的内存,同样delete也会执行析构函数,而不仅仅是释放内存
const 可以理解为一个宏,但是具备了类型检查
注意const和指针的结合:

下面前两个是一样的

留言