CS
C++
Code
前言 笔者觉得自己C++语法太差,还停留在只有竞赛够用的垃圾水平,于是决定恶补
实际上是笔者现在连OOP都看不懂
基本语法 enum
枚举适合用来定义一组有限、离散的常量,如状态机、错误码、类型分类等
1 2 3 4 5 6 enum Level { LOW, MEDIUM, HIGH };
默认的话,会分配给第一个变量low
一个下标0
,然后第二个变量就会有下标1
,以此类推,比如
1 2 enum Level myLevel = MEDIUM;cout << myLevel << endl;
如果想改变下标,有两种方式:
给每个变量都分配下标
1 2 3 4 5 6 enum Level { LOW = 10 , MEDIUM = 50 , HIGH = 100 };
给一个变量分配下标,然后接下来的会根据这个下标递增
1 2 3 4 5 6 enum Level { LOW = 5 , MEDIUM, HIGH };
一般来说,enum
会配合switch
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 enum Level myLevel = MEDIUM;switch (myLevel){ case 1 : cout << "Low Level" << endl; break ; case 2 : cout << "Medium Level" << endl; break ; case 3 : cout << "High Level" << endl; break ; }
&
引用
这个时候,a
和b
共用一个地址 ,改变一个会影响另一个的数值,因为本质上是一样的,可以理解为别名
1 2 b = 2 ; cout << a << endl;
值得一提的是,虽然三种写法int& a
、int &a
和int & a
是等价的,但一般来说工程项目会使用第一个
注意
int& a, b
中,只有a
是引用,b
还是普通的int
变量,因为&
只绑定到当前变量!
取地址 如题,就是取地址符号
在C++中,当一个变量被声明,会分配给其一个内存地址,&
就可以取这个变量的地址,是十六进制格式
1 2 int a = 1 ;cout << &a << endl;
*
指针 指针是存储内存地址的变量
1 2 3 4 5 int a = 1 ;int * b = &a;cout << a << endl; cout << &a << endl; cout << b << endl;
和&
一样,声明指针也推荐用int* a
,而不是int *a
或int * a
,并且指针的变量类型也要跟原变量相同
解引用 前面我们用指针变量存储了另一个变量的地址,我们也可以继续用*
得到这个地址的变量的值,称为解引用
1 2 3 int a = 1 ;int * b = &a;cout << *b << endl;
修改指针的值 1 2 3 4 5 int a = 1 ;int * b = &a;*b = 2 ; cout << *b << endl; cout << a << endl;
->
通过指针访问成员,可以用在struct
或者class
之类的地方。
a->b
等价于 (*a).b
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 struct node { int num1, num2; }; int main () { node b; node* a = &b; a->num1 = 1 ; a->num2 = 2 ; cout << a->num1 + a->num2 << endl; cout << b.num1 + b.num2 << endl; return 0 ; }
内存管理 new
new
可以分配一个新的内存地址
1 2 3 4 5 6 int * a = new int ;cout << a << endl; cout << *a << endl; *a = 1 ; cout << a << endl; cout << *a << endl;
delete
delete
可以释放这个内存地址
1 2 3 4 5 6 7 8 9 10 11 int * a = new int ;cout << a << endl; cout << *a << endl; delete a;cout << *a << endl; int * a = new int [1001 ](); a[10 ] = 1 ; cout << a[10 ] << endl; delete [] a;
注意
delete
只能用于释放被new
声明的内存,否则会出现segmentation fault
下面这个操作是错的,因为a++
改变了指针a
的指向,它不再指向之前被new
的那个内存地址,而且新的内存地址不能被delete
,因为你没有“合法”地拥有它
1 2 3 int * a = new int ;a++; delete a;
Lambda函数 匿名函数,相当于可以在函数里面定义的函数(正常来讲是不行的)。
基础用法 一般用auto
来声明,不然的话就要用std::function <void()>
之类的,比较麻烦。
1 2 3 4 5 6 7 8 9 int main () { int x = 0 ; auto fun = []() { cout << "HELLO Lambda" << endl; }; fun (); return 0 ; }
参数 和正常函数一样传参。
1 2 3 4 5 6 7 8 9 int main () { auto add = [](int a, int b) { return a + b; }; cout << add (1 , 1 ) << endl; return 0 ; }
捕获 正常来讲是不能用Lambda函数之外的变量的,需要“捕获”进去。
1 2 3 4 5 6 7 8 9 10 11 int main () { int a = 0 ; auto fun = [&a]() { a = 10 ; }; fun (); cout << a << endl; return 0 ; }
有四种捕获方式
1 2 3 4 auto fun = [&a](); auto fun = [=a](); auto fun = [&](); auto fun = [=]();
注意
使用捕获=
的时候,会复制一遍所有变量 ,可能造成时间复杂度爆炸
面向对象编程 Object-Oriented Programming (OOP)
原则:Don’t Repeat Yoursef (DRY),即一段代码就写一遍,不重复,便于维护和使用。
Class 类 创建一个对象,它既包含数据,也包含函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class myClass { public : int num1, num2; int add (int a, int b) { cout << num1 << endl; return a + b; } }; int main () { myClass test; cin >> test.num1 >> test.num2; cout << test.add (test.num1, test.num2) << endl; return 0 ; }
Class Constructor 构造器 Constructor是一种特殊的函数,会在类被创建的时候自动调用,名称要和Class名称相同,不返回任何东西。可以简单理解为初始化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class myClass { public : int num1, num2; myClass (int a, int b) { cout << "Hello myClass!" << endl; num1 = a, num2 = b; } }; int main () { myClass test (1 , 2 ) ; cout << test.num1 << endl; cout << test.num2 << endl; return 0 ; }
Access Specifier 访问控制符 在Class中有三种访问控制符:
public
在Class以外的都能访问
private
只有Class以内的能访问
protected
在Class以外的只能通过继承类来访问
这样做的意义是为了封装某些数据和函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class myClass { public : myClass (int a, int b) { num1 = a, num2 = b; } int add () { return num1 + num2; } private : int num1, num2; int num3; }; int main () { myClass test (1 , 2 ) ; cout << test.add () << endl; return 0 ; }
Inheritance 继承 可以理解为将这个类里的数据和函数继承到另一个类。
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 39 40 class myClass { public : int num1; }; class anotherClass : public myClass { public : int num2; }; class otherClass : public anotherClass { public : int num3; }; class hisClass { public : int hisnum; }; class herClass : public myClass, public hisClass { public : int hernum; }; int main () { otherClass test; test.num1 = 1 , test.num2 = 2 , test.num3 = 3 ; cout << test.num1 + test.num2 + test.num3 << endl; herClass a; a.hisnum = 1 , a.hernum = 2 ; cout << a.hisnum + a.hernum << endl; return 0 ; }
可以继承的访问控制符 protected
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class myClass { protected : int num1; }; class hisClass : public myClass{ public : int num2; int add () { num1 = 1 ; return num1 + num2; } }; int main () { hisClass test; test.num2 = 2 ; cout << test.add () << endl; return 0 ; }
Template 模板 模板可以写一个函数或者类,在不同的数据类型都适用。
一个Template只对后面跟着的那一个函数或类生效。
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 template <typename T>T add (T a, T b) { return a + b; } template <typename T1, typename T2> class myClass { public : T1 val1; T2 val2; myClass (T1 v) { val1 = v; val2 = (T2)val1/10 ; } void printVal () { cout << val1 << " " << val2 << endl; } }; int main () { cout << add <int >(1 , 2 ) << endl; cout << add <double >(1.2 , 1.3 ) << endl; myClass<int , double > a (1 ) ; a.printVal (); return 0 ; }
C++项目 头文件.h 头文件里面一般写函数和类的声明、常量和类型定义、模板函数和类的完整实现。
examtest.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #ifndef EXAMTEST_H #define EXAMTEST_H #define MAXN 100010 typedef long long LL;class myClass { public : myClass (int v); void fun () ; private : int num; }; template <typename T>T add (T a, T b) { return a + b; } #endif
examtest.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <bits/stdc++.h> #include "examtest.h" myClass::myClass (int v) { num = v; } void myClass::fun () { std::cout << num << std::endl; } int main () { LL a = 1 , b = 2 ; std::cout << add (a, b) << std::endl; myClass test (10 ) ; test.fun (); return 0 ; }
主函数参数 用于在命令行里传参给主函数,argc
表示参数的数量,argv
就是参数数组,其中,argv[0]
是可执行文件的名字它本身。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <bits/stdc++.h> int main (int argc, char * argv[]) { std::cout << argc << std::endl; for (int x = 0 ; x < argc; x++) std::cout << argv[x] << " " ; std::cout << std::endl; return 0 ; }
CMake