C++ 简介
C++ 是一种静态类型的、编译式的、通用的、大小写敏感的、不规则的编程语言,支持过程化编程、面向对象编程和泛型编程。是 C 的一个超集,事实上,任何合法的 C 程序都是合法的 C++ 程序。
注意:使用静态类型的编程语言是在编译时执行类型检查,而不是在运行时执行类型检查。
标准的 C++ 由三个重要部分组成:
- 核心语言,提供了所有构件块,包括变量、数据类型和常量,等等。
- C++ 标准库,提供了大量的函数,用于操作文件、字符串等。
- 标准模板库(STL),提供了大量的方法,用于操作数据结构等。
环境设置
- 文本编辑器
- C++ 编译器:GNU 的 gcc 编译器
MAC OSX
下载 Xcode 开发环境,并按照安装说明进行安装。一旦安装上 Xcode,您就能使用 GNU 编译器。
Xcode 目前可从 developer.apple.com/technologies/tools/ 上下载。
数据类型
#include <iostream>using namespace std;// main() 是程序开始执行的地方/* 这是注释 *//* C++ 注释也可以* 跨行*/#if 0code#endifint main(){cout << "Hello World"; // 输出 Hello Worldreturn 0;}
- 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位小数。![]() |
| 双浮点型 | double | 8个字节 | 双精度浮点值。双精度是1位符号,11位指数,52位小数。![]() |
| 无类型 | void | 表示类型的缺失。 | |
| 宽字符型 | wchar_t | 2或4个字节 | 宽字符类型。 |
#include<iostream>#include <limits>using namespace std;int main(){cout << "type: \t\t" << "************size**************"<< endl;cout << "bool: \t\t" << "所占字节数:" << sizeof(bool);cout << "\t最大值:" << (numeric_limits<bool>::max)();cout << "\t\t最小值:" << (numeric_limits<bool>::min)() << endl;cout << "char: \t\t" << "所占字节数:" << sizeof(char);cout << "\t最大值:" << (numeric_limits<char>::max)();cout << "\t\t最小值:" << (numeric_limits<char>::min)() << endl;cout << "signed char: \t" << "所占字节数:" << sizeof(signed char);cout << "\t最大值:" << (numeric_limits<signed char>::max)();cout << "\t\t最小值:" << (numeric_limits<signed char>::min)() << endl;cout << "unsigned char: \t" << "所占字节数:" << sizeof(unsigned char);cout << "\t最大值:" << (numeric_limits<unsigned char>::max)();cout << "\t\t最小值:" << (numeric_limits<unsigned char>::min)() << endl;cout << "wchar_t: \t" << "所占字节数:" << sizeof(wchar_t);cout << "\t最大值:" << (numeric_limits<wchar_t>::max)();cout << "\t\t最小值:" << (numeric_limits<wchar_t>::min)() << endl;cout << "short: \t\t" << "所占字节数:" << sizeof(short);cout << "\t最大值:" << (numeric_limits<short>::max)();cout << "\t\t最小值:" << (numeric_limits<short>::min)() << endl;cout << "int: \t\t" << "所占字节数:" << sizeof(int);cout << "\t最大值:" << (numeric_limits<int>::max)();cout << "\t最小值:" << (numeric_limits<int>::min)() << endl;cout << "unsigned: \t" << "所占字节数:" << sizeof(unsigned);cout << "\t最大值:" << (numeric_limits<unsigned>::max)();cout << "\t最小值:" << (numeric_limits<unsigned>::min)() << endl;cout << "long: \t\t" << "所占字节数:" << sizeof(long);cout << "\t最大值:" << (numeric_limits<long>::max)();cout << "\t最小值:" << (numeric_limits<long>::min)() << endl;cout << "unsigned long: \t" << "所占字节数:" << sizeof(unsigned long);cout << "\t最大值:" << (numeric_limits<unsigned long>::max)();cout << "\t最小值:" << (numeric_limits<unsigned long>::min)() << endl;cout << "double: \t" << "所占字节数:" << sizeof(double);cout << "\t最大值:" << (numeric_limits<double>::max)();cout << "\t最小值:" << (numeric_limits<double>::min)() << endl;cout << "long double: \t" << "所占字节数:" << sizeof(long double);cout << "\t最大值:" << (numeric_limits<long double>::max)();cout << "\t最小值:" << (numeric_limits<long double>::min)() << endl;cout << "float: \t\t" << "所占字节数:" << sizeof(float);cout << "\t最大值:" << (numeric_limits<float>::max)();cout << "\t最小值:" << (numeric_limits<float>::min)() << endl;cout << "size_t: \t" << "所占字节数:" << sizeof(size_t);cout << "\t最大值:" << (numeric_limits<size_t>::max)();cout << "\t最小值:" << (numeric_limits<size_t>::min)() << endl;cout << "string: \t" << "所占字节数:" << sizeof(string) << endl;// << "\t最大值:" << (numeric_limits<string>::max)() << "\t最小值:" << (numeric_limits<string>::min)() << endl;cout << "type: \t\t" << "************size**************"<< endl;return 0;}
- endl: 将在每一行后插入一个换行符
- << 运算符: 向屏幕传多个值
- sizeof() : 获取各种数据类型的大小
- typedef: 为一个已有的类型取一个新的名字.语法是
typedef``type newname;
枚举
枚举类型(enumeration)是一种派生数据类型,是由用户定义的若干枚举常量的集合。
enum 枚举名{标识符[=整型常数],标识符[=整型常数],...标识符[=整型常数]} 枚举变量;
如果枚举没有初始化, 即省掉”=整型常数”时, 则从第一个标识符开始。默认情况下,每个名称都会比它前面一个名称大 1.第一个名称的值为 0
enum color { red, green=5, blue } c;c = blue;
指针
数组
引用
数据结构
类
基本语法
变量定义
type variable_name = value; // 声明并初始化变量
不带初始化的定义:带有静态存储持续时间的变量会被隐式初始化为 NULL(所有字节的值都是 0),其他所有变量的初始值是未定义的。
extern int d = 3, f = 5; // d 和 f 的声明int d = 3, f = 5; // 定义并初始化 d 和 fbyte z = 22; // 定义并初始化 zchar x = 'x'; // 变量 x 的值为 'x'
#include <iostream>using namespace std;// 变量声明extern int a, b;extern int c;extern float f;int main (){// 变量定义int a, b;int c;float f;// 实际初始化a = 10;b = 20;c = a + b;cout << c << endl ;f = 70.0/3.0;cout << f << endl ;return 0;}// 函数声明int func();int main(){// 函数调用int i = func();}// 函数定义int func(){return 0;}
变量作用域
有三个地方可以定义变量:
- 局部变量:在函数或一个代码块内部声明的变量。局部变量和全局变量的名称可以相同,但在函数内会覆盖全局变量的值。
- 形式参数:在函数参数的定义中声明的变量
- 全局变量:在所有函数外部声明的变量。值在程序的整个生命周期内都是有效的。可以被任何函数访问。
```cpp
include
using namespace std;
// 全局变量声明 int g = 20;
int main () { // 局部变量声明 int g = 10;
cout << g; // 10
return 0; }
当局部变量被定义时,系统不会对其初始化,您必须自行对其初始化。定义全局变量时,系统会自动初始化为下列值:| **数据类型** | **初始化默认值** || --- | --- || int | 0 || char | '\\0' || float | 0 || double | 0 || pointer | NULL |<a name="KFS7b"></a>### 常量定义常量是固定值,在程序执行期间不会改变。又叫做**字面量。**- 整数常量:- **十六进制**: 0x 或 0X 作为前缀- **八进制**: 0 作为前缀- **十进制**: 不带前缀- **无符号整数**:U作为后缀- **长整数(long)**: L作为后缀- 浮点常量: 由整数部分、小数点、小数部分和指数部分组成- 布尔常量:- **true** 值代表真。1- **false** 值代表假。0- 字符常量:- 宽字符常量:必须存储在 **wchar_t** 类型的变量中- 窄字符常量:可以存储在 **char** 类型的简单变量中```bash85 // 十进制0213 // 八进制0x4b // 十六进制30 // 整数30u // 无符号整数30l // 长整数30ul // 无符号长整数3.14159 // 小数形式314159E-5L // 指数形式L'x' // 宽字符常量'x' // 窄字符常量
转义序列码:
| 转义序列 | 含义 |
|---|---|
| \\ | \ 字符 |
| \‘ | ‘ 字符 |
| \“ | “ 字符 |
| \? | ? 字符 |
| \a | 警报铃声 |
| \b | 退格键 |
| \f | 换页符 |
| \n | 换行符 |
| \r | 回车 |
| \t | 水平制表符 |
| \v | 垂直制表符 |
| \ooo | 一到三位的八进制数 |
| \xhh . . . | 一个或多个数字的十六进制数 |
#define identifier value // 使用 #define 预处理器定义常量const type variable = value; // 使用 const 前缀声明指定类型的常量
#include <iostream>using namespace std;#define LENGTH 10#define WIDTH 5#define NEWLINE '\n'int main(){const int LENGTH = 10;const int WIDTH = 5;const char NEWLINE = '\n';int area;area = LENGTH * WIDTH;cout << area;cout << NEWLINE;return 0;}
修饰符类型
允许在 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。 |
sizeof (data type)Exp1 ? Exp2 : Exp3;表达式1, 表达式2(type) expression
#include <iostream>using namespace std;struct Employee {char first_name[16];int age;} emp;int main(){double a = 21.09399;float b = 10.20;int c ;int var;int *ptr;int val;c = (int) a; // 强制转换运算符cout << "Line 1 - Value of (int)a is :" << c << endl ; // 21c = (int) b; // 强制转换运算符cout << "Line 2 - Value of (int)b is :" << c << endl ; // 10strcpy(emp.first_name, "zara"); // 点运算符,访问结构的成员strcpy(p_emp->first_name, "zara"); // 箭头运算符,通过指针访问结构的成员// 获取 var 的地址ptr = &var;// 获取 ptr 的值val = *ptr;cout << "Value of var :" << var << endl; // 3000cout << "Value of ptr :" << ptr << endl; // 0xbff64494cout << "Value of val :" << val << endl; // 3000return 0;}
函数
形式参数
形式参数就像函数内的其他局部变量,在进入函数时被创建,退出函数时被销毁
- 传值调用:默认。把参数的实际值赋值给函数的形式参数。在这种情况下,修改函数内的形式参数对实际参数没有影响。
- 指针调用:把参数的地址赋值给形式参数。在函数内,该地址用于访问调用中要用到的实际参数。这意味着,修改形式参数会影响实际参数。
- 引用调用:把参数的引用赋值给形式参数。在函数内,该引用用于访问调用中要用到的实际参数。这意味着,修改形式参数会影响实际参数。
Lambda
Lambda 表达式把函数看作对象。Lambda 表达式可以像对象一样使用,比如可以将它们赋给变量和作为参数传递,还可以像函数一样对其求值。
[capture](parameters)->return-type{body}
[](int x, int y){ return x < y ; }[]{ ++global_x; }[](int x, int y) -> int { int z = x + y; return z + x; }
在Lambda表达式内可以访问当前作用域的变量,这是Lambda表达式的闭包(Closure)行为。 与JavaScript闭包不同,C++变量传递有传值和传引用的区别。可以通过前面的[]来指定:
[] // 沒有定义任何变量。使用未定义变量会引发错误。[x, &y] // x以传值方式传入(默认),y以引用方式传入。[&] // 任何被使用到的外部变量都隐式地以引用方式加以引用。[=] // 任何被使用到的外部变量都隐式地以传值方式加以引用。[&, x] // x显式地以传值方式加以引用。其余变量以引用方式加以引用。[=, &z] // z显式地以引用方式加以引用。其余变量以传值方式加以引用。[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() 函数。 |
#include <iostream>#include <ctime>#include <cstdlib>using namespace std;int main (){int i,j;// 设置种子srand( (unsigned)time( NULL ) );/* 生成 10 个随机数 */for( i = 0; i < 10; i++ ){// 生成实际的随机数j= rand();cout <<"随机数: " << j << endl;}return 0;}
数组
type arrayName [ arraySize ];
#include <iostream>using namespace std;#include <iomanip>using std::setw;int main (){int n[ 10 ]; // n 是一个包含 10 个整数的数组// 初始化数组元素for ( int i = 0; i < 10; i++ ) {n[ i ] = i + 100; // 设置元素 i 为 i + 100}cout << "Element" << setw( 13 ) << "Value" << endl;// 输出数组中每个元素的值for ( int j = 0; j < 10; j++ ) {cout << setw( 7 )<< j << setw( 13 ) << n[ j ] << endl;}return 0;}
- 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 的第一次出现的位置。 |
#include <iostream>#include <string>using namespace std;int main (){string str1 = "Hello";string str2 = "World";string str3;int len ;// 复制 str1 到 str3str3 = str1;cout << "str3 : " << str3 << endl; // Hello// 连接 str1 和 str2str3 = str1 + str2;cout << "str1 + str2 : " << str3 << endl; // HelloWorld// 连接后,str3 的总长度len = str3.size();cout << "str3.size() : " << len << endl; // 10return 0;}
指针
指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址,是一个代表内存地址的长的十六进制数
#include <iostream>using namespace std;int main (){int var = 20; // 实际变量的声明int *ip; // 指针变量的声明ip = &var; // 在指针变量中存储 var 的地址cout << "Value of var variable: ";cout << var << endl; // 20// 输出在指针变量中存储的地址cout << "Address stored in ip variable: ";cout << ip << endl; // 0xbfc601ac// 访问指针中地址的值cout << "Value of *ip variable: ";cout << *ip << endl; // 20return 0;}
在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 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(); | 该函数可用于格式化日期和时间为指定的格式。 |
#include <iostream>#include <ctime>using namespace std;int main( ){// 基于当前系统的当前日期/时间time_t now = time(0);cout << "1970 到目前经过秒数:" << now << endl;tm *ltm = localtime(&now);// 输出 tm 结构的各个组成部分cout << "年: "<< 1900 + ltm->tm_year << endl;cout << "月: "<< 1 + ltm->tm_mon<< endl;cout << "日: "<< ltm->tm_mday << endl;cout << "时间: "<< ltm->tm_hour << ":";cout << ltm->tm_min << ":";cout << ltm->tm_sec << endl;}
基本的输入输出
I/O库头文件
| 头文件 | 描述 |
|---|---|
| 该文件定义了 cin、cout、cerr 和 clog 对象,分别对应于标准输入流、标准输出流、非缓冲标准错误流和缓冲标准错误流。使用 cerr 流来显示错误消息,而其他的日志消息则使用 clog 流来输出。 | |
| 该文件通过所谓的参数化的流操纵器(比如 setw 和 setprecision),来声明对执行标准化 I/O 有用的服务。 | |
| 该文件为用户控制的文件处理声明服务。该数据类型通常表示文件流,且同时具有 ofstream(CU) 和 ifstream(R) 两种功能,这意味着它可以创建文件,向文件写入信息,从文件读取信息。 |
void open(const char *filename, ios::openmode mode);
| 模式标志openmode | 描述 |
|---|---|
| ios::app | 追加模式。所有写入都追加到文件末尾。 |
| ios::ate | 文件打开后定位到文件末尾。 |
| ios::in | 打开文件用于读取。 |
| ios::out | 打开文件用于写入。 |
| ios::trunc | 如果该文件已经存在,其内容将在打开文件之前被截断,即把文件长度设为 0。 |
#include <fstream>#include <iostream>using namespace std;int main (){char data[100];// 以写模式打开文件ofstream outfile;outfile.open("afile.dat");cout << "Writing to the file" << endl;cout << "Enter your name: ";cin.getline(data, 100);// 向文件写入用户输入的数据outfile << data << endl;cout << "Enter your age: ";cin >> data;cin.ignore();// 再次向文件写入用户输入的数据outfile << data << endl;// 关闭打开的文件outfile.close();// 以读模式打开文件ifstream infile;infile.open("afile.dat");cout << "Reading from the file" << endl;infile >> data;// 在屏幕上写入数据cout << data << endl;// 再次从文件读取数据,并显示它infile >> data;cout << data << endl;// 关闭打开的文件infile.close();return 0;}
结构
结构是另一种用户自定义的可用的数据类型,它允许您存储不同类型的数据项,用于表示一条记录。
struct type_name {member_type1 member_name1;member_type2 member_name2;member_type3 member_name3;} object_names;
#include <iostream>#include <cstring>using namespace std;void printBook( struct Books *book );struct Books{char title[50];char author[50];char subject[100];int book_id;};int main( ){Books Book1; // 定义结构体类型 Books 的变量 Book1Books Book2; // 定义结构体类型 Books 的变量 Book2// Book1 详述strcpy( Book1.title, "C++ 教程");strcpy( Book1.author, "Runoob");strcpy( Book1.subject, "编程语言");Book1.book_id = 12345;// Book2 详述strcpy( Book2.title, "CSS 教程");strcpy( Book2.author, "Runoob");strcpy( Book2.subject, "前端技术");Book2.book_id = 12346;// 通过传 Book1 的地址来输出 Book1 信息printBook( &Book1 );// 通过传 Book2 的地址来输出 Book2 信息printBook( &Book2 );return 0;}// 该函数以结构指针作为参数void printBook( struct Books *book ){cout << "书标题 : " << book->title <<endl;cout << "书作者 : " << book->author <<endl;cout << "书类目 : " << book->subject <<endl;cout << "书 ID : " << book->book_id <<endl;}
面向对象
类用于指定对象的形式,它包含了数据表示法和用于处理数据的方法。类中的数据和方法称为类的成员。
使用范围解析运算符 :: 定义类成员函数
#include <iostream>using namespace std;class Box{public:double length; // 长度double breadth; // 宽度double height; // 高度// 成员函数声明double getVolume(void);void setLength( double len );void setBreadth( double bre );void setHeight( double hei );};// 成员函数定义double Box::getVolume(void){return length * breadth * height;}void Box::setLength( double len ){length = len;}void Box::setBreadth( double bre ){breadth = bre;}void Box::setHeight( double hei ){height = hei;}// 程序的主函数int main( ){Box Box1; // 声明 Box1,类型为 BoxBox Box2; // 声明 Box2,类型为 Boxdouble volume = 0.0; // 用于存储体积// box 1 详述Box1.setLength(6.0);Box1.setBreadth(7.0);Box1.setHeight(5.0);// box 2 详述Box2.setLength(12.0);Box2.setBreadth(13.0);Box2.setHeight(10.0);// box 1 的体积volume = Box1.getVolume();cout << "Box1 的体积:" << volume <<endl;// box 2 的体积volume = Box2.getVolume();cout << "Box2 的体积:" << volume <<endl;return 0;}
- public: 公有成员在程序中类的外部是可访问的。
- private: 私有成员变量或函数在类的外部是不可访问的,甚至是不可查看的。只有类和友元函数可以访问私有成员。
- protected: 保护成员变量或函数与私有成员十分相似,但有一点不同,保护成员在派生类(即子类)中是可访问的。 | 继承方式 | 基类的 public 成员 | 基类的 protected 成员 | 基类的 private 成员 | 继承引起的访问关系变化 | | —- | —- | —- | —- | —- | | public继承 | 仍为public成员 | 仍为protected成员 | 不可见 | 基类的非私有成员在子类的访问属性不变 | | protected继承 | 变为protected成员 | 变为protected成员 | 不可见 | 基类的非私有成员都为子类的保护成员 | | private继承 | 变为private成员 | 变为private成员 | 不可见 | 基类中的非私有成员都称为子类的私有成员 |
一个类可以派生自多个类:
class derived-class: access-specifier base-class
- 函数重载:可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同。当您调用一个重载函数或重载运算符时,编译器通过把您所使用的参数类型与定义中的参数类型进行比较,决定选用最合适的定义。选择最合适的重载函数或重载运算符的过程,称为重载决策。
- 多态:意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。
- 虚函数:是在基类中使用关键字 virtual 声明的函数。在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数。
- 使用类来定义抽象数据类型(ADT)。类的内部受到保护,不会因无意的用户级错误导致对象状态受损。类实现可能随着时间的推移而发生变化,以便应对不断变化的需求,或者应对那些要求不改变用户级代码的错误报告。在设计组件时,必须保持接口独立于实现,这样,如果改变底层实现,接口也将保持不变。我们都会设置类成员状态为私有(private),除非我们真的需要将其暴露,这样才能保证良好的封装性。
- 接口描述了类的行为和功能,而不需要完成类的特定实现。C++ 接口是使用抽象类来实现的,如果类中至少有一个函数被声明为纯虚函数,则这个类就是抽象类(ABC)。纯虚函数是通过在声明中使用 “= 0” 来指定的。抽象类不能被用于实例化对象,它只能作为接口使用。如果试图实例化一个抽象类的对象,会导致编译错误。
高级教程
异常

#include <iostream>#include <exception>using namespace std;struct MyException : public exception {const char * what () const throw () {return "C++ Exception";}};int main() {try {throw MyException();}catch(MyException& e) {std::cout << "MyException caught" << std::endl;std::cout << e.what() << std::endl;}catch(std::exception& e) {//其他的错误}}
动态内存
- 栈:在函数内部声明的所有变量都将占用栈内存。
- 堆:这是程序中未使用的内存,在程序运行时可用于动态分配内存。
new 运算符为给定类型的变量在运行时分配堆内的内存,这会返回所分配的空间地址。
delete 运算符,释放之前由 new 运算符分配的内存。
#include <iostream>using namespace std;class Box {public:Box() {cout << "调用构造函数!" <<endl;}~Box() {cout << "调用析构函数!" <<endl;}};int main() {Box* myBoxArray = new Box[4];delete [] myBoxArray; // 删除数组return 0;}
命名空间

#include <iostream>using namespace std;// 第一个命名空间namespace first_space{void func(){cout << "Inside first_space" << endl;}}// 第二个命名空间namespace second_space{void func(){cout << "Inside second_space" << endl;}}using namespace first_space;int main () {func(); // 调用第一个命名空间中的函数return 0;}
模板
模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。
泛型即只有在运行时才知道是什么类型,定义时并不知道。
#include <iostream>#include <string>using namespace std;template <typename T>inline T const& Max (T const& a, T const& b) {return a < b ? b:a;}int main () {int i = 39;int j = 20;cout << "Max(i, j): " << Max(i, j) << endl; // 39double f1 = 13.5;double f2 = 20.7;cout << "Max(f1, f2): " << Max(f1, f2) << endl; // 20.7string s1 = "Hello";string s2 = "World";cout << "Max(s1, s2): " << Max(s1, s2) << endl; // Worldreturn 0;}
#include <iostream>#include <vector>#include <cstdlib>#include <string>#include <stdexcept>using namespace std;template <class T>class Stack {private:vector<T> elems; // 元素public:void push(T const&); // 入栈void pop(); // 出栈T top() const; // 返回栈顶元素bool empty() const{ // 如果为空则返回真。return elems.empty();}};template <class T>void Stack<T>::push (T const& elem) {// 追加传入元素的副本elems.push_back(elem);}template <class T>void Stack<T>::pop () {if (elems.empty()) {throw out_of_range("Stack<>::pop(): empty stack");}// 删除最后一个元素elems.pop_back();}template <class T>T Stack<T>::top () const {if (elems.empty()) {throw out_of_range("Stack<>::top(): empty stack");}// 返回最后一个元素的副本return elems.back();}int main() {try {Stack<int> intStack; // int 类型的栈Stack<string> stringStack; // string 类型的栈// 操作 int 类型的栈intStack.push(7);cout << intStack.top() <<endl;// 操作 string 类型的栈stringStack.push("hello");cout << stringStack.top() << std::endl;stringStack.pop();stringStack.pop();}catch (exception const& ex) {cerr << "Exception: " << ex.what() <<endl;return -1;}}
预处理器
预处理器是一些指令,指示编译器在实际编译之前所需完成的预处理。以井号(#)开头,不会以分号(;)结尾。
- #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; }
**预定义宏:**| **宏** | **描述** || --- | --- || __LINE__ | 这会在程序编译时包含当前行号。 || __FILE__ | 这会在程序编译时包含当前文件名。 || __DATE__ | 这会包含一个形式为 month/day/year 的字符串,它表示把源文件转换为目标代码的日期。 || __TIME__ | 这会包含一个形式为 hour:minute:second 的字符串,它表示程序被编译的时间。 |```cpp#include <iostream>using namespace std;int main () {cout << "Value of __LINE__ : " << __LINE__ << endl; // 6cout << "Value of __FILE__ : " << __FILE__ << endl; // test.cppcout << "Value of __DATE__ : " << __DATE__ << endl; // Feb 28 2020cout << "Value of __TIME__ : " << __TIME__ << endl; // 18:52:48return 0;}
信号处理
定义在 C++ 头文件
| 信号 | 描述 |
|---|---|
| SIGABRT | 程序的异常终止,如调用 abort。 |
| SIGFPE | 错误的算术运算,比如除以零或导致溢出的操作。 |
| SIGILL | 检测非法指令。 |
| SIGINT | 程序终止(interrupt)信号。 |
| SIGSEGV | 非法访问内存。 |
| SIGTERM | 发送到程序的终止请求。 |
using namespace std;
void signalHandler(int signum) { cout << “Interrupt signal (“ << signum << “) received.\n”;
// 清理并关闭// 终止程序
exit(signum);
}
int main () {
// 注册信号 SIGINT 和信号处理程序
signal(SIGINT, signalHandler);
while(1){
cout << “Going to sleep….” << endl;
sleep(1);
}
return 0;
}
<a name="3pZc5"></a>### 多线程- **pthread_create(): **创建一个新的线程,并让它可执行| **参数** | **描述** || --- | --- || thread | 指向线程标识符指针。 || attr | 一个不透明的属性对象,可以被用来设置线程属性。您可以指定线程属性对象,也可以使用默认值 NULL。 || start_routine | 线程运行函数起始地址,一旦线程被创建就会执行。 || arg | 运行函数的参数。它必须通过把引用作为指针强制转换为 void 类型进行传递。如果没有传递参数,则使用 NULL。 |```cpp#include <iostream>// 必须的头文件#include <pthread.h>using namespace std;#define NUM_THREADS 5// 线程的运行函数void* say_hello(void* args) {cout << "Hello Runoob!" << endl;return 0;}int main() {// 定义线程的 id 变量,多个变量使用数组pthread_t tids[NUM_THREADS];for(int i = 0; i < NUM_THREADS; ++i) {//参数依次是:创建的线程id,线程参数,调用的函数,传入的函数参数int ret = pthread_create(&tids[i], NULL, say_hello, NULL);if (ret != 0){cout << "pthread_create error: error_code=" << ret << endl;}}//等各个线程退出后,进程才结束,否则进程强制结束了,线程可能还没反应过来;pthread_exit(NULL);}
web 编程
公共网关接口(CGI):是一种用于外部网关程序与信息服务器(如 HTTP 服务器)对接的接口标准
/var/www/cgi-bin/cplusplus.cgi
#include <iostream>using namespace std;int main (){cout << "Content-type:text/html\r\n\r\n";cout << "<html>\n";cout << "<head>\n";cout << "<title>Hello World - 第一个 CGI 程序</title>\n";cout << "</head>\n";cout << "<body>\n";cout << "<h2>Hello World! 这是我的第一个 CGI 程序</h2>\n";cout << "</body>\n";cout << "</html>\n";return 0;}
/cgi-bin/cpp_get.cgi?first_name=ZARA&last_name=ALI
#include <iostream>#include <vector>#include <string>#include <stdio.h>#include <stdlib.h>#include <cgicc/CgiDefs.h>#include <cgicc/Cgicc.h>#include <cgicc/HTTPHTMLHeader.h>#include <cgicc/HTMLClasses.h>using namespace std;using namespace cgicc;int main (){Cgicc formData;cout << "Content-type:text/html\r\n\r\n";cout << "<html>\n";cout << "<head>\n";cout << "<title>使用 GET 和 POST 方法</title>\n";cout << "</head>\n";cout << "<body>\n";form_iterator fi = formData.getElement("first_name");if( !fi->isEmpty() && fi != (*formData).end()) {cout << "名:" << **fi << endl;}else{cout << "No text entered for first name" << endl;}cout << "<br/>\n";fi = formData.getElement("last_name");if( !fi->isEmpty() &&fi != (*formData).end()) {cout << "姓:" << **fi << endl;}else{cout << "No text entered for last name" << endl;}cout << "<br/>\n";cout << "</body>\n";cout << "</html>\n";return 0;}
设置 Cookies
#include <iostream>using namespace std;int main (){cout << "Set-Cookie:UserID=XYZ;\r\n";cout << "Set-Cookie:Password=XYZ123;\r\n";cout << "Set-Cookie:Domain=www.w3cschool.cc;\r\n";cout << "Set-Cookie:Path=/perl;\n";cout << "Content-type:text/html\r\n\r\n";cout << "<html>\n";cout << "<head>\n";cout << "<title>CGI 中的 Cookies</title>\n";cout << "</head>\n";cout << "<body>\n";cout << "设置 cookies" << endl;cout << "<br/>\n";cout << "</body>\n";cout << "</html>\n";return 0;}
获取 cookies
#include <iostream>#include <vector>#include <string>#include <stdio.h>#include <stdlib.h>#include <cgicc/CgiDefs.h>#include <cgicc/Cgicc.h>#include <cgicc/HTTPHTMLHeader.h>#include <cgicc/HTMLClasses.h>using namespace std;using namespace cgicc;int main (){Cgicc cgi;const_cookie_iterator cci;cout << "Content-type:text/html\r\n\r\n";cout << "<html>\n";cout << "<head>\n";cout << "<title>CGI 中的 Cookies</title>\n";cout << "</head>\n";cout << "<body>\n";cout << "<table border = \"0\" cellspacing = \"2\">";// 获取环境变量const CgiEnvironment& env = cgi.getEnvironment();for( cci = env.getCookieList().begin();cci != env.getCookieList().end();++cci ){cout << "<tr><td>" << cci->getName() << "</td><td>";cout << cci->getValue();cout << "</td></tr>\n";}cout << "</table><\n";cout << "<br/>\n";cout << "</body>\n";cout << "</html>\n";return 0;}
资源
- 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、语言工具、系统编程等。



