C++实战笔记.PNG

C++ 简介

C++ 是一种静态类型的、编译式的、通用的、大小写敏感的、不规则的编程语言,支持过程化编程、面向对象编程和泛型编程。是 C 的一个超集,事实上,任何合法的 C 程序都是合法的 C++ 程序。
注意:使用静态类型的编程语言是在编译时执行类型检查,而不是在运行时执行类型检查。

标准的 C++ 由三个重要部分组成:

  • 核心语言,提供了所有构件块,包括变量、数据类型和常量,等等。
  • C++ 标准库,提供了大量的函数,用于操作文件、字符串等。
  • 标准模板库(STL),提供了大量的方法,用于操作数据结构等。

环境设置

  • 文本编辑器
  • C++ 编译器:GNU 的 gcc 编译器


MAC OSX

下载 Xcode 开发环境,并按照安装说明进行安装。一旦安装上 Xcode,您就能使用 GNU 编译器。
Xcode 目前可从 developer.apple.com/technologies/tools/ 上下载。

数据类型

  1. #include <iostream>
  2. using namespace std;
  3. // main() 是程序开始执行的地方
  4. /* 这是注释 */
  5. /* C++ 注释也可以
  6. * 跨行
  7. */
  8. #if 0
  9. code
  10. #endif
  11. int main()
  12. {
  13. cout << "Hello World"; // 输出 Hello World
  14. return 0;
  15. }
  • C++ 语言定义了一些头文件,这些头文件包含了程序中必需的或有用的信息。上面这段程序中,包含了头文件
  • 下一行 using namespace std; 告诉编译器使用 std 命名空间。命名空间是 C++ 中一个相对新的概念。
  • 下一行 // main() 是程序开始执行的地方 是一个单行注释。单行注释以 // 开头,在行末结束。
  • 下一行 int main() 是主函数,程序从这里开始执行。
  • 下一行 cout << “Hello World”; 会在屏幕上显示消息 “Hello World”。
  • 下一行 return 0; 终止 main( )函数,并向调用进程返回值 0。
  • 分号是语句结束符。也就是说,每个语句必须以分号结束。它表明一个逻辑实体的结束。
  • 语句块是一组使用大括号括起来的按逻辑连接的语句。


基本数据类型

七种基本的 C++ 数据类型

类型 关键字 描述
布尔型 bool 4个字节 存储值 true 或 false。
字符型 char 1个字节
整型 int 4个字节
浮点型 float 4个字节 单精度浮点值。单精度是这样的格式,1位符号,8位指数,23位小数。
深入浅出 C++ - 图3
双浮点型 double 8个字节 双精度浮点值。双精度是1位符号,11位指数,52位小数。
深入浅出 C++ - 图4
无类型 void 表示类型的缺失。
宽字符型 wchar_t 2或4个字节 宽字符类型。
  1. #include<iostream>
  2. #include <limits>
  3. using namespace std;
  4. int main()
  5. {
  6. cout << "type: \t\t" << "************size**************"<< endl;
  7. cout << "bool: \t\t" << "所占字节数:" << sizeof(bool);
  8. cout << "\t最大值:" << (numeric_limits<bool>::max)();
  9. cout << "\t\t最小值:" << (numeric_limits<bool>::min)() << endl;
  10. cout << "char: \t\t" << "所占字节数:" << sizeof(char);
  11. cout << "\t最大值:" << (numeric_limits<char>::max)();
  12. cout << "\t\t最小值:" << (numeric_limits<char>::min)() << endl;
  13. cout << "signed char: \t" << "所占字节数:" << sizeof(signed char);
  14. cout << "\t最大值:" << (numeric_limits<signed char>::max)();
  15. cout << "\t\t最小值:" << (numeric_limits<signed char>::min)() << endl;
  16. cout << "unsigned char: \t" << "所占字节数:" << sizeof(unsigned char);
  17. cout << "\t最大值:" << (numeric_limits<unsigned char>::max)();
  18. cout << "\t\t最小值:" << (numeric_limits<unsigned char>::min)() << endl;
  19. cout << "wchar_t: \t" << "所占字节数:" << sizeof(wchar_t);
  20. cout << "\t最大值:" << (numeric_limits<wchar_t>::max)();
  21. cout << "\t\t最小值:" << (numeric_limits<wchar_t>::min)() << endl;
  22. cout << "short: \t\t" << "所占字节数:" << sizeof(short);
  23. cout << "\t最大值:" << (numeric_limits<short>::max)();
  24. cout << "\t\t最小值:" << (numeric_limits<short>::min)() << endl;
  25. cout << "int: \t\t" << "所占字节数:" << sizeof(int);
  26. cout << "\t最大值:" << (numeric_limits<int>::max)();
  27. cout << "\t最小值:" << (numeric_limits<int>::min)() << endl;
  28. cout << "unsigned: \t" << "所占字节数:" << sizeof(unsigned);
  29. cout << "\t最大值:" << (numeric_limits<unsigned>::max)();
  30. cout << "\t最小值:" << (numeric_limits<unsigned>::min)() << endl;
  31. cout << "long: \t\t" << "所占字节数:" << sizeof(long);
  32. cout << "\t最大值:" << (numeric_limits<long>::max)();
  33. cout << "\t最小值:" << (numeric_limits<long>::min)() << endl;
  34. cout << "unsigned long: \t" << "所占字节数:" << sizeof(unsigned long);
  35. cout << "\t最大值:" << (numeric_limits<unsigned long>::max)();
  36. cout << "\t最小值:" << (numeric_limits<unsigned long>::min)() << endl;
  37. cout << "double: \t" << "所占字节数:" << sizeof(double);
  38. cout << "\t最大值:" << (numeric_limits<double>::max)();
  39. cout << "\t最小值:" << (numeric_limits<double>::min)() << endl;
  40. cout << "long double: \t" << "所占字节数:" << sizeof(long double);
  41. cout << "\t最大值:" << (numeric_limits<long double>::max)();
  42. cout << "\t最小值:" << (numeric_limits<long double>::min)() << endl;
  43. cout << "float: \t\t" << "所占字节数:" << sizeof(float);
  44. cout << "\t最大值:" << (numeric_limits<float>::max)();
  45. cout << "\t最小值:" << (numeric_limits<float>::min)() << endl;
  46. cout << "size_t: \t" << "所占字节数:" << sizeof(size_t);
  47. cout << "\t最大值:" << (numeric_limits<size_t>::max)();
  48. cout << "\t最小值:" << (numeric_limits<size_t>::min)() << endl;
  49. cout << "string: \t" << "所占字节数:" << sizeof(string) << endl;
  50. // << "\t最大值:" << (numeric_limits<string>::max)() << "\t最小值:" << (numeric_limits<string>::min)() << endl;
  51. cout << "type: \t\t" << "************size**************"<< endl;
  52. return 0;
  53. }
  • endl: 将在每一行后插入一个换行符
  • << 运算符: 向屏幕传多个值
  • sizeof() : 获取各种数据类型的大小
  • typedef: 为一个已有的类型取一个新的名字.语法是typedef``type newname;

枚举

枚举类型(enumeration)是一种派生数据类型,是由用户定义的若干枚举常量的集合。

  1. enum 枚举名{
  2. 标识符[=整型常数],
  3. 标识符[=整型常数],
  4. ...
  5. 标识符[=整型常数]
  6. } 枚举变量;

如果枚举没有初始化, 即省掉”=整型常数”时, 则从第一个标识符开始。默认情况下,每个名称都会比它前面一个名称大 1.第一个名称的值为 0

  1. enum color { red, green=5, blue } c;
  2. c = blue;

指针

数组

引用

数据结构

基本语法

变量定义

  1. type variable_name = value; // 声明并初始化变量

不带初始化的定义:带有静态存储持续时间的变量会被隐式初始化为 NULL(所有字节的值都是 0),其他所有变量的初始值是未定义的。

  1. extern int d = 3, f = 5; // d 和 f 的声明
  2. int d = 3, f = 5; // 定义并初始化 d 和 f
  3. byte z = 22; // 定义并初始化 z
  4. char x = 'x'; // 变量 x 的值为 'x'
  1. #include <iostream>
  2. using namespace std;
  3. // 变量声明
  4. extern int a, b;
  5. extern int c;
  6. extern float f;
  7. int main ()
  8. {
  9. // 变量定义
  10. int a, b;
  11. int c;
  12. float f;
  13. // 实际初始化
  14. a = 10;
  15. b = 20;
  16. c = a + b;
  17. cout << c << endl ;
  18. f = 70.0/3.0;
  19. cout << f << endl ;
  20. return 0;
  21. }
  22. // 函数声明
  23. int func();
  24. int main()
  25. {
  26. // 函数调用
  27. int i = func();
  28. }
  29. // 函数定义
  30. int func()
  31. {
  32. return 0;
  33. }

变量作用域

有三个地方可以定义变量:

  • 局部变量:在函数或一个代码块内部声明的变量。局部变量和全局变量的名称可以相同,但在函数内会覆盖全局变量的值。
  • 形式参数:在函数参数的定义中声明的变量
  • 全局变量:在所有函数外部声明的变量。值在程序的整个生命周期内都是有效的。可以被任何函数访问。 ```cpp

    include

    using namespace std;

// 全局变量声明 int g = 20;

int main () { // 局部变量声明 int g = 10;

cout << g; // 10

return 0; }

  1. 当局部变量被定义时,系统不会对其初始化,您必须自行对其初始化。定义全局变量时,系统会自动初始化为下列值:
  2. | **数据类型** | **初始化默认值** |
  3. | --- | --- |
  4. | int | 0 |
  5. | char | '\\0' |
  6. | float | 0 |
  7. | double | 0 |
  8. | pointer | NULL |
  9. <a name="KFS7b"></a>
  10. ### 常量定义
  11. 常量是固定值,在程序执行期间不会改变。又叫做**字面量。**
  12. - 整数常量:
  13. - **十六进制**: 0x 0X 作为前缀
  14. - **八进制**: 0 作为前缀
  15. - **十进制**: 不带前缀
  16. - **无符号整数**:U作为后缀
  17. - **长整数(long)**: L作为后缀
  18. - 浮点常量: 由整数部分、小数点、小数部分和指数部分组成
  19. - 布尔常量:
  20. - **true** 值代表真。1
  21. - **false** 值代表假。0
  22. - 字符常量:
  23. - 宽字符常量:必须存储在 **wchar_t** 类型的变量中
  24. - 窄字符常量:可以存储在 **char** 类型的简单变量中
  25. ```bash
  26. 85 // 十进制
  27. 0213 // 八进制
  28. 0x4b // 十六进制
  29. 30 // 整数
  30. 30u // 无符号整数
  31. 30l // 长整数
  32. 30ul // 无符号长整数
  33. 3.14159 // 小数形式
  34. 314159E-5L // 指数形式
  35. L'x' // 宽字符常量
  36. 'x' // 窄字符常量

转义序列码:

转义序列 含义
\\ \ 字符
\‘ ‘ 字符
\“ “ 字符
\? ? 字符
\a 警报铃声
\b 退格键
\f 换页符
\n 换行符
\r 回车
\t 水平制表符
\v 垂直制表符
\ooo 一到三位的八进制数
\xhh . . . 一个或多个数字的十六进制数
  1. #define identifier value // 使用 #define 预处理器定义常量
  2. const type variable = value; // 使用 const 前缀声明指定类型的常量
  1. #include <iostream>
  2. using namespace std;
  3. #define LENGTH 10
  4. #define WIDTH 5
  5. #define NEWLINE '\n'
  6. int main()
  7. {
  8. const int LENGTH = 10;
  9. const int WIDTH = 5;
  10. const char NEWLINE = '\n';
  11. int area;
  12. area = LENGTH * WIDTH;
  13. cout << area;
  14. cout << NEWLINE;
  15. return 0;
  16. }

修饰符类型

允许在 char、int 和 double 数据类型前放置修饰符。修饰符用于改变基本类型的含义。

修饰符 整型int 字符型char 双精度型double
signed(有符号)
- [x]

| [x] | | | unsigned(无符号) | [x] | [x] | | | long | [x] | | [x] | | short | [x] | | |

类型限定符:

const const 类型的对象在程序执行期间不能被修改改变。
volatile 修饰符 volatile 告诉编译器不需要优化volatile声明的变量,让程序可以直接从内存中读取变量。对于一般的变量编译器会对变量进行优化,将内存中的变量值放在寄存器中以加快读写效率。
restrict restrict 修饰的指针是唯一一种访问它所指向的对象的方式。只有 C99 增加了新的类型限定符 restrict。

存储类

定义变量/函数的范围(可见性)和生命周期。

  • auto(废): 声明变量时根据初始化表达式自动推断该变量的类型、声明函数时函数返回值的占位符。
  • register(废):定义存储在寄存器中而不是 RAM 中的局部变量。即变量的最大尺寸等于寄存器的大小。寄存器只用于需要快速访问的变量,比如计数器
  • static:编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。当 static 修饰全局变量时,会使变量的作用域限制在声明它的文件内。当 static 用在类数据成员上时,会导致仅有一个该成员的副本被类的所有对象共享。
  • extern:提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。通常用于当有两个或多个文件共享相同的全局变量或函数的时候。
  • mutable:仅适用于类的对象。允许对象的成员替代常量,即mutable 成员可以通过 const 成员函数修改。
  • thread_local:仅应用于数据声明和定义不能用于函数声明或定义。变量仅可在它在其上创建的线程上访问


运算符

  • 算术运算符:+-*/%++—
  • 关系运算符:== != > < >= <=
  • 逻辑运算符:&& || !
  • 位运算符:&|^~<<>>
  • 杂项运算符: | 杂项运算符 | 描述 | | —- | —- | | sizeof | sizeof 运算符返回变量的大小。例如,sizeof(a) 将返回 4,其中 a 是整数。 | | Condition ? X : Y | 条件运算符。如果 Condition 为真 ? 则值为 X : 否则值为 Y。 | | , | 逗号运算符会顺序执行一系列运算。整个逗号表达式的值是以逗号分隔的列表中的最后一个表达式的值。 | | .(点)和 ->(箭头) | 成员运算符用于引用类、结构和共用体的成员。访问结构的成员时使用点运算符,而通过指针访问结构的成员时,则使用箭头运算符。 | | Cast | 强制转换运算符把一种数据类型转换为另一种数据类型。例如,int(2.2000) 将返回 2。 | | & | 指针运算符 & 返回变量的地址。例如 &a; 将给出变量的实际地址。 | | | [指针运算符 ](https://www.runoob.com/cplusplus/cpp-pointer-operators.html) 指向一个变量。例如,*var; 将指向变量 var。 |
  1. sizeof (data type)
  2. Exp1 ? Exp2 : Exp3;
  3. 表达式1, 表达式2
  4. (type) expression
  1. #include <iostream>
  2. using namespace std;
  3. struct Employee {
  4. char first_name[16];
  5. int age;
  6. } emp;
  7. int main()
  8. {
  9. double a = 21.09399;
  10. float b = 10.20;
  11. int c ;
  12. int var;
  13. int *ptr;
  14. int val;
  15. c = (int) a; // 强制转换运算符
  16. cout << "Line 1 - Value of (int)a is :" << c << endl ; // 21
  17. c = (int) b; // 强制转换运算符
  18. cout << "Line 2 - Value of (int)b is :" << c << endl ; // 10
  19. strcpy(emp.first_name, "zara"); // 点运算符,访问结构的成员
  20. strcpy(p_emp->first_name, "zara"); // 箭头运算符,通过指针访问结构的成员
  21. // 获取 var 的地址
  22. ptr = &var;
  23. // 获取 ptr 的值
  24. val = *ptr;
  25. cout << "Value of var :" << var << endl; // 3000
  26. cout << "Value of ptr :" << ptr << endl; // 0xbff64494
  27. cout << "Value of val :" << val << endl; // 3000
  28. return 0;
  29. }

函数

形式参数

形式参数就像函数内的其他局部变量,在进入函数时被创建,退出函数时被销毁

  • 传值调用:默认。把参数的实际值赋值给函数的形式参数。在这种情况下,修改函数内的形式参数对实际参数没有影响。
  • 指针调用:把参数的地址赋值给形式参数。在函数内,该地址用于访问调用中要用到的实际参数。这意味着,修改形式参数会影响实际参数。
  • 引用调用:把参数的引用赋值给形式参数。在函数内,该引用用于访问调用中要用到的实际参数。这意味着,修改形式参数会影响实际参数。


Lambda

Lambda 表达式把函数看作对象。Lambda 表达式可以像对象一样使用,比如可以将它们赋给变量和作为参数传递,还可以像函数一样对其求值。

  1. [capture](parameters)->return-type{body}
  1. [](int x, int y){ return x < y ; }
  2. []{ ++global_x; }
  3. [](int x, int y) -> int { int z = x + y; return z + x; }

在Lambda表达式内可以访问当前作用域的变量,这是Lambda表达式的闭包(Closure)行为。 与JavaScript闭包不同,C++变量传递有传值和传引用的区别。可以通过前面的[]来指定:

  1. [] // 沒有定义任何变量。使用未定义变量会引发错误。
  2. [x, &y] // x以传值方式传入(默认),y以引用方式传入。
  3. [&] // 任何被使用到的外部变量都隐式地以引用方式加以引用。
  4. [=] // 任何被使用到的外部变量都隐式地以传值方式加以引用。
  5. [&, x] // x显式地以传值方式加以引用。其余变量以引用方式加以引用。
  6. [=, &z] // z显式地以引用方式加以引用。其余变量以传值方式加以引用。
  7. [this] // 对于[=]或[&]的形式,显式传入this指针,

内置数学函数

函数 描述
double cos(double); 该函数返回弧度角(double 型)的余弦。
double sin(double); 该函数返回弧度角(double 型)的正弦。
double tan(double); 该函数返回弧度角(double 型)的正切。
double log(double); 该函数返回参数的自然对数。
double pow(double, double); 假设第一个参数为 x,第二个参数为 y,则该函数返回 x 的 y 次方。
double hypot(double, double); 该函数返回两个参数的平方总和的平方根,也就是说,参数为一个直角三角形的两个直角边,函数会返回斜边的长度。
double sqrt(double); 该函数返回参数的平方根。
int abs(int); 该函数返回整数的绝对值。
double fabs(double); 该函数返回任意一个浮点数的绝对值。
double floor(double); 该函数返回一个小于或等于传入参数的最大整数。
rand() 返回一个伪随机数,生成随机数之前必须先调用 srand() 函数。
  1. #include <iostream>
  2. #include <ctime>
  3. #include <cstdlib>
  4. using namespace std;
  5. int main ()
  6. {
  7. int i,j;
  8. // 设置种子
  9. srand( (unsigned)time( NULL ) );
  10. /* 生成 10 个随机数 */
  11. for( i = 0; i < 10; i++ )
  12. {
  13. // 生成实际的随机数
  14. j= rand();
  15. cout <<"随机数: " << j << endl;
  16. }
  17. return 0;
  18. }

数组

  1. type arrayName [ arraySize ];
  1. #include <iostream>
  2. using namespace std;
  3. #include <iomanip>
  4. using std::setw;
  5. int main ()
  6. {
  7. int n[ 10 ]; // n 是一个包含 10 个整数的数组
  8. // 初始化数组元素
  9. for ( int i = 0; i < 10; i++ ) {
  10. n[ i ] = i + 100; // 设置元素 i 为 i + 100
  11. }
  12. cout << "Element" << setw( 13 ) << "Value" << endl;
  13. // 输出数组中每个元素的值
  14. for ( int j = 0; j < 10; j++ ) {
  15. cout << setw( 7 )<< j << setw( 13 ) << n[ j ] << endl;
  16. }
  17. return 0;
  18. }
  • setw() :格式化输出

    字符串

    内置字符串函数

    | 函数 | 描述 | | —- | —- | | strcpy(s1, s2); | 复制字符串 s2 到字符串 s1。 | | strcat(s1, s2); | 连接字符串 s2 到字符串 s1 的末尾。 | | strlen(s1); | 返回字符串 s1 的长度。 | | strcmp(s1, s2); | 如果 s1 和 s2 是相同的,则返回 0;如果 s1s2 则返回值大于 0 | | strchr(s1, ch); | 返回一个指针,指向字符串 s1 中字符 ch 的第一次出现的位置。 | | strstr(s1, s2); | 返回一个指针,指向字符串 s1 中字符串 s2 的第一次出现的位置。 |
  1. #include <iostream>
  2. #include <string>
  3. using namespace std;
  4. int main ()
  5. {
  6. string str1 = "Hello";
  7. string str2 = "World";
  8. string str3;
  9. int len ;
  10. // 复制 str1 到 str3
  11. str3 = str1;
  12. cout << "str3 : " << str3 << endl; // Hello
  13. // 连接 str1 和 str2
  14. str3 = str1 + str2;
  15. cout << "str1 + str2 : " << str3 << endl; // HelloWorld
  16. // 连接后,str3 的总长度
  17. len = str3.size();
  18. cout << "str3.size() : " << len << endl; // 10
  19. return 0;
  20. }

指针

指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址,是一个代表内存地址的长的十六进制数

  1. #include <iostream>
  2. using namespace std;
  3. int main ()
  4. {
  5. int var = 20; // 实际变量的声明
  6. int *ip; // 指针变量的声明
  7. ip = &var; // 在指针变量中存储 var 的地址
  8. cout << "Value of var variable: ";
  9. cout << var << endl; // 20
  10. // 输出在指针变量中存储的地址
  11. cout << "Address stored in ip variable: ";
  12. cout << ip << endl; // 0xbfc601ac
  13. // 访问指针中地址的值
  14. cout << "Value of *ip variable: ";
  15. cout << *ip << endl; // 20
  16. return 0;
  17. }

在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。NULL 指针是一个定义在标准库中的值为零的常量.

引用

引用变量是一个别名,它是某个已存在变量的另一个名字。

  • 不存在空引用。引用必须连接到一块合法的内存。
  • 一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
  • 引用必须在创建时被初始化。指针可以在任何时间被初始化。


日期和时间

函数 描述
time_t time(time_t *time); 该函数返回系统的当前日历时间,自 1970 年 1 月 1 日以来经过的秒数。如果系统没有时间,则返回 .1
char ctime(const time_t time); 该返回一个表示当地时间的字符串指针,字符串形式 day month year hours:minutes:seconds year\n\0。
struct tm localtime(const time_t time); 该函数返回程序执行起(一般为程序的开头),处理器时钟所使用的时间。如果时间不可用,则返回 .1。
clock_t clock(void); 该函数返回程序执行起(一般为程序的开头),处理器时钟所使用的时间。如果时间不可用,则返回 .1。
char asctime ( const struct tm time ); 该函数返回一个指向字符串的指针,字符串包含了 time 所指向结构中存储的信息,返回形式为:day month date hours:minutes:seconds year\n\0。
struct tm gmtime(const time_t time); 该函数返回一个指向 time 的指针,time 为 tm 结构,用协调世界时(UTC)也被称为格林尼治标准时间(GMT)表示。
time_t mktime(struct tm *time); 该函数返回日历时间,相当于 time 所指向结构中存储的时间。
double difftime ( time_t time2, time_t time1 ); 该函数返回 time1 和 time2 之间相差的秒数。
size_t strftime(); 该函数可用于格式化日期和时间为指定的格式。
  1. #include <iostream>
  2. #include <ctime>
  3. using namespace std;
  4. int main( )
  5. {
  6. // 基于当前系统的当前日期/时间
  7. time_t now = time(0);
  8. cout << "1970 到目前经过秒数:" << now << endl;
  9. tm *ltm = localtime(&now);
  10. // 输出 tm 结构的各个组成部分
  11. cout << "年: "<< 1900 + ltm->tm_year << endl;
  12. cout << "月: "<< 1 + ltm->tm_mon<< endl;
  13. cout << "日: "<< ltm->tm_mday << endl;
  14. cout << "时间: "<< ltm->tm_hour << ":";
  15. cout << ltm->tm_min << ":";
  16. cout << ltm->tm_sec << endl;
  17. }

基本的输入输出

I/O库头文件

头文件 描述
该文件定义了 cin、cout、cerr 和 clog 对象,分别对应于标准输入流、标准输出流、非缓冲标准错误流和缓冲标准错误流。使用 cerr 流来显示错误消息,而其他的日志消息则使用 clog 流来输出。
该文件通过所谓的参数化的流操纵器(比如 setw 和 setprecision),来声明对执行标准化 I/O 有用的服务。
该文件为用户控制的文件处理声明服务。该数据类型通常表示文件流,且同时具有 ofstream(CU) 和 ifstream(R) 两种功能,这意味着它可以创建文件,向文件写入信息,从文件读取信息。
  1. void open(const char *filename, ios::openmode mode);
模式标志openmode 描述
ios::app 追加模式。所有写入都追加到文件末尾。
ios::ate 文件打开后定位到文件末尾。
ios::in 打开文件用于读取。
ios::out 打开文件用于写入。
ios::trunc 如果该文件已经存在,其内容将在打开文件之前被截断,即把文件长度设为 0。
  1. #include <fstream>
  2. #include <iostream>
  3. using namespace std;
  4. int main (){
  5. char data[100];
  6. // 以写模式打开文件
  7. ofstream outfile;
  8. outfile.open("afile.dat");
  9. cout << "Writing to the file" << endl;
  10. cout << "Enter your name: ";
  11. cin.getline(data, 100);
  12. // 向文件写入用户输入的数据
  13. outfile << data << endl;
  14. cout << "Enter your age: ";
  15. cin >> data;
  16. cin.ignore();
  17. // 再次向文件写入用户输入的数据
  18. outfile << data << endl;
  19. // 关闭打开的文件
  20. outfile.close();
  21. // 以读模式打开文件
  22. ifstream infile;
  23. infile.open("afile.dat");
  24. cout << "Reading from the file" << endl;
  25. infile >> data;
  26. // 在屏幕上写入数据
  27. cout << data << endl;
  28. // 再次从文件读取数据,并显示它
  29. infile >> data;
  30. cout << data << endl;
  31. // 关闭打开的文件
  32. infile.close();
  33. return 0;
  34. }

结构

结构是另一种用户自定义的可用的数据类型,它允许您存储不同类型的数据项,用于表示一条记录。

  1. struct type_name {
  2. member_type1 member_name1;
  3. member_type2 member_name2;
  4. member_type3 member_name3;
  5. } object_names;
  1. #include <iostream>
  2. #include <cstring>
  3. using namespace std;
  4. void printBook( struct Books *book );
  5. struct Books
  6. {
  7. char title[50];
  8. char author[50];
  9. char subject[100];
  10. int book_id;
  11. };
  12. int main( )
  13. {
  14. Books Book1; // 定义结构体类型 Books 的变量 Book1
  15. Books Book2; // 定义结构体类型 Books 的变量 Book2
  16. // Book1 详述
  17. strcpy( Book1.title, "C++ 教程");
  18. strcpy( Book1.author, "Runoob");
  19. strcpy( Book1.subject, "编程语言");
  20. Book1.book_id = 12345;
  21. // Book2 详述
  22. strcpy( Book2.title, "CSS 教程");
  23. strcpy( Book2.author, "Runoob");
  24. strcpy( Book2.subject, "前端技术");
  25. Book2.book_id = 12346;
  26. // 通过传 Book1 的地址来输出 Book1 信息
  27. printBook( &Book1 );
  28. // 通过传 Book2 的地址来输出 Book2 信息
  29. printBook( &Book2 );
  30. return 0;
  31. }
  32. // 该函数以结构指针作为参数
  33. void printBook( struct Books *book )
  34. {
  35. cout << "书标题 : " << book->title <<endl;
  36. cout << "书作者 : " << book->author <<endl;
  37. cout << "书类目 : " << book->subject <<endl;
  38. cout << "书 ID : " << book->book_id <<endl;
  39. }

面向对象

类用于指定对象的形式,它包含了数据表示法和用于处理数据的方法。类中的数据和方法称为类的成员。
使用范围解析运算符 :: 定义类成员函数

  1. #include <iostream>
  2. using namespace std;
  3. class Box
  4. {
  5. public:
  6. double length; // 长度
  7. double breadth; // 宽度
  8. double height; // 高度
  9. // 成员函数声明
  10. double getVolume(void);
  11. void setLength( double len );
  12. void setBreadth( double bre );
  13. void setHeight( double hei );
  14. };
  15. // 成员函数定义
  16. double Box::getVolume(void){
  17. return length * breadth * height;
  18. }
  19. void Box::setLength( double len ){
  20. length = len;
  21. }
  22. void Box::setBreadth( double bre ){
  23. breadth = bre;
  24. }
  25. void Box::setHeight( double hei ){
  26. height = hei;
  27. }
  28. // 程序的主函数
  29. int main( ){
  30. Box Box1; // 声明 Box1,类型为 Box
  31. Box Box2; // 声明 Box2,类型为 Box
  32. double volume = 0.0; // 用于存储体积
  33. // box 1 详述
  34. Box1.setLength(6.0);
  35. Box1.setBreadth(7.0);
  36. Box1.setHeight(5.0);
  37. // box 2 详述
  38. Box2.setLength(12.0);
  39. Box2.setBreadth(13.0);
  40. Box2.setHeight(10.0);
  41. // box 1 的体积
  42. volume = Box1.getVolume();
  43. cout << "Box1 的体积:" << volume <<endl;
  44. // box 2 的体积
  45. volume = Box2.getVolume();
  46. cout << "Box2 的体积:" << volume <<endl;
  47. return 0;
  48. }
  • public: 公有成员在程序中类的外部是可访问的。
  • private: 私有成员变量或函数在类的外部是不可访问的,甚至是不可查看的。只有类和友元函数可以访问私有成员。
  • protected: 保护成员变量或函数与私有成员十分相似,但有一点不同,保护成员在派生类(即子类)中是可访问的。 | 继承方式 | 基类的 public 成员 | 基类的 protected 成员 | 基类的 private 成员 | 继承引起的访问关系变化 | | —- | —- | —- | —- | —- | | public继承 | 仍为public成员 | 仍为protected成员 | 不可见 | 基类的非私有成员在子类的访问属性不变 | | protected继承 | 变为protected成员 | 变为protected成员 | 不可见 | 基类的非私有成员都为子类的保护成员 | | private继承 | 变为private成员 | 变为private成员 | 不可见 | 基类中的非私有成员都称为子类的私有成员 |

一个类可以派生自多个类:

  1. class derived-class: access-specifier base-class
  • 函数重载:可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同。当您调用一个重载函数重载运算符时,编译器通过把您所使用的参数类型与定义中的参数类型进行比较,决定选用最合适的定义。选择最合适的重载函数或重载运算符的过程,称为重载决策
  • 多态:意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。
  • 虚函数:是在基类中使用关键字 virtual 声明的函数。在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数。
  • 使用来定义抽象数据类型(ADT)。类的内部受到保护,不会因无意的用户级错误导致对象状态受损。类实现可能随着时间的推移而发生变化,以便应对不断变化的需求,或者应对那些要求不改变用户级代码的错误报告。在设计组件时,必须保持接口独立于实现,这样,如果改变底层实现,接口也将保持不变。我们都会设置类成员状态为私有(private),除非我们真的需要将其暴露,这样才能保证良好的封装性
  • 接口描述了类的行为和功能,而不需要完成类的特定实现。C++ 接口是使用抽象类来实现的,如果类中至少有一个函数被声明为纯虚函数,则这个类就是抽象类(ABC)。纯虚函数是通过在声明中使用 “= 0” 来指定的。抽象类不能被用于实例化对象,它只能作为接口使用。如果试图实例化一个抽象类的对象,会导致编译错误。


高级教程

异常

image.png

  1. #include <iostream>
  2. #include <exception>
  3. using namespace std;
  4. struct MyException : public exception {
  5. const char * what () const throw () {
  6. return "C++ Exception";
  7. }
  8. };
  9. int main() {
  10. try {
  11. throw MyException();
  12. }
  13. catch(MyException& e) {
  14. std::cout << "MyException caught" << std::endl;
  15. std::cout << e.what() << std::endl;
  16. }
  17. catch(std::exception& e) {
  18. //其他的错误
  19. }
  20. }

动态内存

  • 栈:在函数内部声明的所有变量都将占用栈内存。
  • 堆:这是程序中未使用的内存,在程序运行时可用于动态分配内存。

new 运算符为给定类型的变量在运行时分配堆内的内存,这会返回所分配的空间地址。
delete 运算符,释放之前由 new 运算符分配的内存。

  1. #include <iostream>
  2. using namespace std;
  3. class Box {
  4. public:
  5. Box() {
  6. cout << "调用构造函数!" <<endl;
  7. }
  8. ~Box() {
  9. cout << "调用析构函数!" <<endl;
  10. }
  11. };
  12. int main() {
  13. Box* myBoxArray = new Box[4];
  14. delete [] myBoxArray; // 删除数组
  15. return 0;
  16. }

命名空间

image.png

  1. #include <iostream>
  2. using namespace std;
  3. // 第一个命名空间
  4. namespace first_space{
  5. void func(){
  6. cout << "Inside first_space" << endl;
  7. }
  8. }
  9. // 第二个命名空间
  10. namespace second_space{
  11. void func(){
  12. cout << "Inside second_space" << endl;
  13. }
  14. }
  15. using namespace first_space;
  16. int main () {
  17. func(); // 调用第一个命名空间中的函数
  18. return 0;
  19. }

模板

模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。
泛型即只有在运行时才知道是什么类型,定义时并不知道。

  1. #include <iostream>
  2. #include <string>
  3. using namespace std;
  4. template <typename T>
  5. inline T const& Max (T const& a, T const& b) {
  6. return a < b ? b:a;
  7. }
  8. int main () {
  9. int i = 39;
  10. int j = 20;
  11. cout << "Max(i, j): " << Max(i, j) << endl; // 39
  12. double f1 = 13.5;
  13. double f2 = 20.7;
  14. cout << "Max(f1, f2): " << Max(f1, f2) << endl; // 20.7
  15. string s1 = "Hello";
  16. string s2 = "World";
  17. cout << "Max(s1, s2): " << Max(s1, s2) << endl; // World
  18. return 0;
  19. }
  1. #include <iostream>
  2. #include <vector>
  3. #include <cstdlib>
  4. #include <string>
  5. #include <stdexcept>
  6. using namespace std;
  7. template <class T>
  8. class Stack {
  9. private:
  10. vector<T> elems; // 元素
  11. public:
  12. void push(T const&); // 入栈
  13. void pop(); // 出栈
  14. T top() const; // 返回栈顶元素
  15. bool empty() const{ // 如果为空则返回真。
  16. return elems.empty();
  17. }
  18. };
  19. template <class T>
  20. void Stack<T>::push (T const& elem) {
  21. // 追加传入元素的副本
  22. elems.push_back(elem);
  23. }
  24. template <class T>
  25. void Stack<T>::pop () {
  26. if (elems.empty()) {
  27. throw out_of_range("Stack<>::pop(): empty stack");
  28. }
  29. // 删除最后一个元素
  30. elems.pop_back();
  31. }
  32. template <class T>
  33. T Stack<T>::top () const {
  34. if (elems.empty()) {
  35. throw out_of_range("Stack<>::top(): empty stack");
  36. }
  37. // 返回最后一个元素的副本
  38. return elems.back();
  39. }
  40. int main() {
  41. try {
  42. Stack<int> intStack; // int 类型的栈
  43. Stack<string> stringStack; // string 类型的栈
  44. // 操作 int 类型的栈
  45. intStack.push(7);
  46. cout << intStack.top() <<endl;
  47. // 操作 string 类型的栈
  48. stringStack.push("hello");
  49. cout << stringStack.top() << std::endl;
  50. stringStack.pop();
  51. stringStack.pop();
  52. }
  53. catch (exception const& ex) {
  54. cerr << "Exception: " << ex.what() <<endl;
  55. return -1;
  56. }
  57. }

预处理器

预处理器是一些指令,指示编译器在实际编译之前所需完成的预处理。以井号(#)开头,不会以分号(;)结尾。

  • #include :把头文件包含到源文件中
  • #define:创建符号常量
  • #if:有选择地对部分程序源代码进行编译
  • #else:
  • #line: ```cpp

    include

    using namespace std;

define concat(a, b) a ## b

int main() { int xy = 100;

cout << concat(x, y); return 0; }

  1. **预定义宏:**
  2. | **宏** | **描述** |
  3. | --- | --- |
  4. | __LINE__ | 这会在程序编译时包含当前行号。 |
  5. | __FILE__ | 这会在程序编译时包含当前文件名。 |
  6. | __DATE__ | 这会包含一个形式为 month/day/year 的字符串,它表示把源文件转换为目标代码的日期。 |
  7. | __TIME__ | 这会包含一个形式为 hour:minute:second 的字符串,它表示程序被编译的时间。 |
  8. ```cpp
  9. #include <iostream>
  10. using namespace std;
  11. int main () {
  12. cout << "Value of __LINE__ : " << __LINE__ << endl; // 6
  13. cout << "Value of __FILE__ : " << __FILE__ << endl; // test.cpp
  14. cout << "Value of __DATE__ : " << __DATE__ << endl; // Feb 28 2020
  15. cout << "Value of __TIME__ : " << __TIME__ << endl; // 18:52:48
  16. return 0;
  17. }

信号处理

定义在 C++ 头文件 的信号:

信号 描述
SIGABRT 程序的异常终止,如调用 abort。
SIGFPE 错误的算术运算,比如除以零或导致溢出的操作。
SIGILL 检测非法指令。
SIGINT 程序终止(interrupt)信号。
SIGSEGV 非法访问内存。
SIGTERM 发送到程序的终止请求。
  • signal(): 用来捕获突发事件
  • raise() :生成信号 ```cpp

    include

    include

    include

using namespace std;

void signalHandler(int signum) { cout << “Interrupt signal (“ << signum << “) received.\n”;

  1. // 清理并关闭
  2. // 终止程序

exit(signum);

}

int main () { // 注册信号 SIGINT 和信号处理程序 signal(SIGINT, signalHandler);
while(1){ cout << “Going to sleep….” << endl; sleep(1); } return 0; }

  1. <a name="3pZc5"></a>
  2. ### 多线程
  3. - **pthread_create(): **创建一个新的线程,并让它可执行
  4. | **参数** | **描述** |
  5. | --- | --- |
  6. | thread | 指向线程标识符指针。 |
  7. | attr | 一个不透明的属性对象,可以被用来设置线程属性。您可以指定线程属性对象,也可以使用默认值 NULL。 |
  8. | start_routine | 线程运行函数起始地址,一旦线程被创建就会执行。 |
  9. | arg | 运行函数的参数。它必须通过把引用作为指针强制转换为 void 类型进行传递。如果没有传递参数,则使用 NULL。 |
  10. ```cpp
  11. #include <iostream>
  12. // 必须的头文件
  13. #include <pthread.h>
  14. using namespace std;
  15. #define NUM_THREADS 5
  16. // 线程的运行函数
  17. void* say_hello(void* args) {
  18. cout << "Hello Runoob!" << endl;
  19. return 0;
  20. }
  21. int main() {
  22. // 定义线程的 id 变量,多个变量使用数组
  23. pthread_t tids[NUM_THREADS];
  24. for(int i = 0; i < NUM_THREADS; ++i) {
  25. //参数依次是:创建的线程id,线程参数,调用的函数,传入的函数参数
  26. int ret = pthread_create(&tids[i], NULL, say_hello, NULL);
  27. if (ret != 0)
  28. {
  29. cout << "pthread_create error: error_code=" << ret << endl;
  30. }
  31. }
  32. //等各个线程退出后,进程才结束,否则进程强制结束了,线程可能还没反应过来;
  33. pthread_exit(NULL);
  34. }

web 编程

公共网关接口(CGI):是一种用于外部网关程序与信息服务器(如 HTTP 服务器)对接的接口标准
image.png
/var/www/cgi-bin/cplusplus.cgi

  1. #include <iostream>
  2. using namespace std;
  3. int main ()
  4. {
  5. cout << "Content-type:text/html\r\n\r\n";
  6. cout << "<html>\n";
  7. cout << "<head>\n";
  8. cout << "<title>Hello World - 第一个 CGI 程序</title>\n";
  9. cout << "</head>\n";
  10. cout << "<body>\n";
  11. cout << "<h2>Hello World! 这是我的第一个 CGI 程序</h2>\n";
  12. cout << "</body>\n";
  13. cout << "</html>\n";
  14. return 0;
  15. }

/cgi-bin/cpp_get.cgi?first_name=ZARA&last_name=ALI

  1. #include <iostream>
  2. #include <vector>
  3. #include <string>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <cgicc/CgiDefs.h>
  7. #include <cgicc/Cgicc.h>
  8. #include <cgicc/HTTPHTMLHeader.h>
  9. #include <cgicc/HTMLClasses.h>
  10. using namespace std;
  11. using namespace cgicc;
  12. int main ()
  13. {
  14. Cgicc formData;
  15. cout << "Content-type:text/html\r\n\r\n";
  16. cout << "<html>\n";
  17. cout << "<head>\n";
  18. cout << "<title>使用 GET 和 POST 方法</title>\n";
  19. cout << "</head>\n";
  20. cout << "<body>\n";
  21. form_iterator fi = formData.getElement("first_name");
  22. if( !fi->isEmpty() && fi != (*formData).end()) {
  23. cout << "名:" << **fi << endl;
  24. }else{
  25. cout << "No text entered for first name" << endl;
  26. }
  27. cout << "<br/>\n";
  28. fi = formData.getElement("last_name");
  29. if( !fi->isEmpty() &&fi != (*formData).end()) {
  30. cout << "姓:" << **fi << endl;
  31. }else{
  32. cout << "No text entered for last name" << endl;
  33. }
  34. cout << "<br/>\n";
  35. cout << "</body>\n";
  36. cout << "</html>\n";
  37. return 0;
  38. }

设置 Cookies

  1. #include <iostream>
  2. using namespace std;
  3. int main ()
  4. {
  5. cout << "Set-Cookie:UserID=XYZ;\r\n";
  6. cout << "Set-Cookie:Password=XYZ123;\r\n";
  7. cout << "Set-Cookie:Domain=www.w3cschool.cc;\r\n";
  8. cout << "Set-Cookie:Path=/perl;\n";
  9. cout << "Content-type:text/html\r\n\r\n";
  10. cout << "<html>\n";
  11. cout << "<head>\n";
  12. cout << "<title>CGI 中的 Cookies</title>\n";
  13. cout << "</head>\n";
  14. cout << "<body>\n";
  15. cout << "设置 cookies" << endl;
  16. cout << "<br/>\n";
  17. cout << "</body>\n";
  18. cout << "</html>\n";
  19. return 0;
  20. }

获取 cookies

  1. #include <iostream>
  2. #include <vector>
  3. #include <string>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <cgicc/CgiDefs.h>
  7. #include <cgicc/Cgicc.h>
  8. #include <cgicc/HTTPHTMLHeader.h>
  9. #include <cgicc/HTMLClasses.h>
  10. using namespace std;
  11. using namespace cgicc;
  12. int main ()
  13. {
  14. Cgicc cgi;
  15. const_cookie_iterator cci;
  16. cout << "Content-type:text/html\r\n\r\n";
  17. cout << "<html>\n";
  18. cout << "<head>\n";
  19. cout << "<title>CGI 中的 Cookies</title>\n";
  20. cout << "</head>\n";
  21. cout << "<body>\n";
  22. cout << "<table border = \"0\" cellspacing = \"2\">";
  23. // 获取环境变量
  24. const CgiEnvironment& env = cgi.getEnvironment();
  25. for( cci = env.getCookieList().begin();
  26. cci != env.getCookieList().end();
  27. ++cci )
  28. {
  29. cout << "<tr><td>" << cci->getName() << "</td><td>";
  30. cout << cci->getValue();
  31. cout << "</td></tr>\n";
  32. }
  33. cout << "</table><\n";
  34. cout << "<br/>\n";
  35. cout << "</body>\n";
  36. cout << "</html>\n";
  37. return 0;
  38. }

资源

  • C++ Programming Language Tutorials − C++ 编程语言教程。
  • C++ Programming − 这本书涵盖了 C++ 语言编程、软件交互设计、C++ 语言的现实生活应用。
  • C++ FAQ − C++ 常见问题
  • Free Country − Free Country 提供了免费的 C++ 源代码和 C++ 库,这些源代码和库涵盖了压缩、存档、游戏编程、标准模板库和 GUI 编程等 C++ 编程领域。
  • C and C++ Users Group − C 和 C++ 的用户团体提供了免费的涵盖各种编程领域 C++ 项目的源代码,包括 AI、动画、编译器、数据库、调试、加密、游戏、图形、GUI、语言工具、系统编程等。