C++ Primer 第1到6章详细讲解
第1章 开始
1.1 编写一个简单的C++程序
-
程序结构:每个C++程序都包含一个或多个函数,其中必须有一个名为
main的函数 -
基本形式:
#include <iostream> int main() { std::cout << "Hello, World!" << std::endl; return 0; } -
关键点:
-
#include是预处理指令,用于包含头文件 -
int main()是程序入口点 -
std::cout是标准输出流 -
<<是流插入运算符 -
std::endl是行结束符,会刷新输出缓冲区 -
return 0;表示程序正常结束
-
1.2 初识输入输出
-
标准输入输出对象:
-
std::cin:标准输入(通常是键盘) -
std::cout:标准输出(通常是显示器) -
std::cerr:标准错误(无缓冲) -
std::clog:标准日志(有缓冲)
-
-
输入操作:
int v1 = 0, v2 = 0; std::cout << "Enter two numbers: " << std::endl; std::cin >> v1 >> v2; std::cout << "The sum of " << v1 << " and " << v2 << " is " << v1 + v2 << std::endl; -
命名空间:
std是标准库的命名空间,使用::作用域运算符访问其中的名称
1.3 注释简介
-
单行注释:以
//开始,到行尾结束 -
多行注释:以
/*开始,以*/结束,可以跨越多行
1.4 控制流
-
while循环:
int sum = 0, val = 1; while (val <= 10) { sum += val; // 等价于 sum = sum + val ++val; // 前置递增运算符 } -
for循环:
int sum = 0; for (int i = 1; i <= 10; ++i) { sum += i; } -
if语句:
if (condition) { // 条件为真时执行 } else { // 条件为假时执行 }
1.5 类简介
-
Sales_item类:表示C++程序设计中书籍销售的数据
-
使用类:
#include <iostream> #include "Sales_item.h" int main() { Sales_item book; std::cin >> book; std::cout << book << std::endl; return 0; } -
关键点:
-
类定义了数据成员和成员函数
-
使用类需要包含相应的头文件
-
类对象可以像内置类型一样使用输入输出运算符
-
第2章 变量和基本类型
2.1 基本内置类型
-
算术类型:
-
整型:
-
bool:布尔类型(true/false) -
char:字符(1字节) -
wchar_t:宽字符 -
char16_t/char32_t:Unicode字符 -
short:短整型(至少16位) -
int:整型(至少16位) -
long:长整型(至少32位) -
long long:长长整型(至少64位,C++11引入)
-
-
浮点型:
-
float:单精度浮点数(通常32位) -
double:双精度浮点数(通常64位) -
long double:扩展精度浮点数
-
-
-
类型大小:使用
sizeof运算符获取类型占用的字节数std::cout << "int size: " << sizeof(int) << " bytes" << std::endl; -
带符号与无符号类型:
-
signed和unsigned可以修饰整型 -
unsigned只能表示非负值,范围是0到正数最大值 -
默认情况下,
int、short、long、long long是带符号的
-
2.2 变量
-
变量定义:类型说明符 + 一个或多个变量名(用逗号分隔)+ 分号
int sum = 0, value; -
初始化:变量在创建时获得一个初始值
-
列表初始化(C++11):使用花括号
int units_sold{0}; int units_sold = {0}; -
直接初始化:使用圆括号
int units_sold(0); -
拷贝初始化:使用等号
int units_sold = 0;
-
-
变量声明与定义:
-
定义:为变量分配存储空间,可能初始化
-
声明:使名字为程序所知,使用
extern关键字且不分配存储空间extern int i; // 声明i但不定义i int j; // 声明并定义j
-
-
标识符:变量、函数和其他实体的名称
-
只能由字母、数字和下划线组成
-
必须以字母或下划线开头
-
区分大小写
-
不能使用关键字作为标识符
-
2.3 复合类型
-
引用:对象的别名(C++中引用必须初始化且不能改变绑定的对象)
int ival = 1024; int &refVal = ival; // refVal指向ival int &refVal2; // 错误:引用必须初始化 -
指针:存储内存地址的变量
int ival = 42; int *p = &ival; // p指向ival,&是取地址运算符 cout << *p; // *是解引用运算符,输出42 -
指针和引用的区别:
-
引用必须初始化且不能重新绑定
-
指针可以不初始化(但不推荐),可以改变指向的对象
-
引用本身不是对象,没有引用的引用
-
指针是一个对象,可以有指向指针的指针
-
-
空指针:
int *p1 = nullptr; // C++11引入 int *p2 = 0; int *p3 = NULL; // 传统方式,实际上是预处理宏 -
void指针*:可以指向任意类型对象,但不能直接操作它指向的对象
2.4 const限定符
-
const对象:值不能被修改的变量
const int bufSize = 512; -
const的特性:
-
必须初始化
-
默认情况下,const对象仅在文件内有效
-
要在多个文件中共享const对象,需要在定义和声明前加
extern
-
-
constexpr和常量表达式(C++11):
-
常量表达式是编译时就能计算出结果的表达式
-
constexpr变量是常量表达式
-
-
指针和const:
-
指向常量的指针:
const double *cptr -
常量指针:
double *const ptr -
指向常量的常量指针:
const double *const ptr
-
2.5 处理类型
-
类型别名:
-
使用
typedef:typedef double wages; -
使用
using(C++11):using SI = Sales_item;
-
-
auto类型说明符(C++11):让编译器根据初始值推断变量类型
auto item = val1 + val2; // item的类型是val1和val2相加结果的类型 -
decltype类型指示符(C++11):选择并返回操作数的数据类型
decltype(f()) sum = x; // sum的类型就是函数f的返回类型
2.6 自定义数据结构
-
struct定义:
struct Sales_data { std::string bookNo; unsigned units_sold = 0; double revenue = 0.0; }; -
类的定义:在C++中,struct和class基本相同,主要区别在于默认访问权限
第3章 字符串、向量和数组
3.1 命名空间的using声明
-
using声明:使特定标识符可用而不需要加命名空间前缀
using std::cin; using std::cout; using std::endl; -
using指示(不推荐过度使用):使命名空间中所有名字都可用
using namespace std;
3.2 标准库类型string
-
定义和初始化string对象:
string s1; // 默认初始化,s1是一个空字符串 string s2(s1); // s2是s1的副本 string s3 = s1; // 等价于s3(s1),s3是s1的副本 string s4("value"); // s4是字面值"value"的副本,不包括末尾的空字符 string s5 = "value";// 等价于s5("value") string s6(10, 'c'); // s6的内容是cccccccccc -
string对象上的操作:
-
os << s:将s写到输出流os当中,返回os -
is >> s:从is中读取字符串赋给s,字符串以空白分隔,返回is -
getline(is, s):从is中读取一行赋给s,返回is -
s.empty():s为空返回true,否则返回false -
s.size():返回s中字符的个数 -
s[n]:返回s中第n个字符的引用 -
s1 + s2:返回s1和s2连接后的结果 -
s1 = s2:用s2的副本代替s1中原来的字符 -
s1 == s2:如果s1和s2中所含的字符完全一样,则它们相等 -
s1 != s2:比较两个string对象是否不相等 -
<, <=, >, >=:利用字符在字典中的顺序进行比较
-
-
处理string对象中的字符:
-
使用基于范围的for循环遍历字符串中的每个字符
-
使用
cctype头文件中的函数处理字符(如isalpha(),isdigit(),tolower()等)
-
3.3 标准库类型vector
-
定义和初始化vector对象:
vector<T> v1; // v1是一个空vector,它潜在的元素是T类型的,执行默认初始化 vector<T> v2(v1); // v2中包含有v1所有元素的副本 vector<T> v2 = v1; // 等价于v2(v1) vector<T> v3(n, val); // v3包含了n个重复的元素,每个元素的值都是val vector<T> v4(n); // v4包含了n个重复地执行了值初始化的对象 vector<T> v5{a, b, c...}; // v5包含了初始值数量的元素,每个元素被赋予相应的初始值 vector<T> v5 = {a, b, c...}; // 等价于v5{a, b, c...} -
向vector对象中添加元素:
vector<int> v; for (int i = 0; i != 100; ++i) { v.push_back(i); // 依次把整数值放到v的末尾 } -
其他vector操作:
-
v.empty():如果v不含有任何元素,返回真;否则返回假 -
v.size():返回v中元素的个数 -
v.push_back(t):向v的尾端添加一个值为t的元素 -
v[n]:返回v中第n个位置上元素的引用 -
v1 = v2:用v2中的元素拷贝替换v1中的元素 -
v1 = {a, b, c...}:用列表中的元素拷贝替换v1中的元素 -
v1 == v2:v1和v2相等当且仅当它们的元素数量相同且对应位置的元素值都相同 -
!=, <, <=, >, >=:保持这些操作符惯有的含义
-
3.4 迭代器介绍
-
使用迭代器:
-
begin和end运算符:begin成员负责返回指向第一个元素(或第一个字符)的迭代器,end成员负责返回指向容器(或string对象)"尾元素的下一位置"的迭代器 -
迭代器类型:如
vector<int>::iterator it; -
const_iterator:只能读元素,不能写元素
-
-
迭代器运算:
-
*iter:返回迭代器iter所指元素的引用 -
iter->mem:解引用iter并获取该元素的名为mem的成员,等价于(*iter).mem -
++iter:令iter指示容器中的下一个元素 -
--iter:令iter指示容器中的前一个元素 -
iter1 == iter2:判断两个迭代器是否相等(不相等) -
iter1 != iter2:判断两个迭代器是否不相等(相等)
-
3.5 数组
-
定义和初始化内置数组:
int arr[10]; // 10个未初始化的int int arr[10] = {0,1,2,3,4,5,6,7,8,9}; // 列表初始化 int arr[] = {0,1,2,3,4,5,6,7,8,9}; // 维度是10的数组 int arr[5] = {0,1,2}; // 等价于{0,1,2,0,0} int arr[4] = {0}; // 所有元素初始化为0 char arr1[] = {'C', '+', '+'}; // 列表初始化,没有空字符 char arr2[] = {'C', '+', '+', '\0'}; // 列表初始化,含有显式的空字符 char arr3[] = "C++"; // 自动添加表示字符串结束的空字符 const unsigned sz = 3; int arr[sz]; // 错误:不能用变量定义数组维度(C++11之前) -
访问数组元素:通过下标运算符
[]访问 -
指针和数组:
-
使用数组的时候编译器一般会把它转换成指针
-
指针也是迭代器:支持递增、递减、解引用等操作
-
标准库函数
begin和end(C++11,定义在<iterator>头文件中)可以获取数组的首元素指针和尾后指针
-
-
C风格字符串:
-
C风格字符串存放在字符数组中并以空字符结束('\0')
-
相关函数定义在
<cstring>头文件中:strlen(p)、strcmp(p1, p2)、strcat(p1, p2)、strcpy(p1, p2)
-
-
与旧代码的接口:
-
混用string对象和C风格字符串
-
使用数组初始化vector对象
-
第4章 表达式
4.1 基础
-
基本概念:
-
一元运算符:只作用于一个操作数(如
-、+、*(解引用)、&(取地址)、++、--) -
二元运算符:有两个操作数(如
+、-、*、/、%) -
运算对象:运算符作用的值
-
求值顺序:表达式中各个子表达式的计算顺序
-
优先级:决定运算符的执行顺序
-
结合律:决定相同优先级的运算符的执行顺序
-
-
左值和右值:
-
当一个对象被用作右值的时候,用的是对象的值(内容)
-
当对象被用作左值的时候,用的是对象的身份(在内存中的位置)
-
大多数情况下,左值可以当作右值使用,反之则不行
-
4.2 算术运算符
-
基本算术运算符:
+、-、*、/、%(取模/求余) -
一元正负运算符:
+、- -
除法运算:整数相除结果仍是整数,小数部分被截断
-
取模运算:两个操作数都必须是整数
4.3 逻辑和关系运算符
-
关系运算符:
>、>=、<、<=、==、!= -
逻辑运算符:
&&(逻辑与)、||(逻辑或)、`!'(逻辑非) -
短路求值:对于
&&,如果左侧表达式为假,则不会计算右侧表达式;对于||,如果左侧表达式为真,则不会计算右侧表达式
4.4 赋值运算符
-
赋值运算符:
=,具有右结合性 -
复合赋值运算符:
+=、-=、*=、/=、%=等 -
赋值运算符的要求:左侧运算对象必须是一个可修改的左值
4.5 递增和递减运算符
-
前置版本:
++i,先递增再返回递增后的值 -
后置版本:
i++,先返回当前值再递增 -
建议:除非必须,否则不用递增递减运算符的后置版本
4.6 成员访问运算符
-
点运算符:
.,用于获取类、结构体或联合体的成员 -
箭头运算符:
->,相当于对指针解引用后再使用点运算符(ptr->mem等价于(*ptr).mem)
4.7 条件运算符
-
条件运算符:
cond ? expr1 : expr2,是C++中唯一的三元运算符 -
嵌套条件运算符:可以嵌套使用,但可读性会变差
4.8 位运算符
-
位运算符:作用于整数类型的运算对象,把运算对象看成是固定数量的二进制位
-
~:位求反 -
&:位与 -
|:位或 -
^:位异或 -
<<:左移 -
>>:右移
-
-
移位运算符:左侧运算对象按右侧运算对象指定的位数移动
4.9 sizeof运算符
-
sizeof运算符:返回一条表达式或一个类型名字所占的字节数
-
sizeof(type) -
sizeof expr
-
4.10 逗号运算符
-
逗号运算符:含有两个运算对象,按照从左向右的顺序依次求值,首先对左侧的表达式求值,然后丢弃求值结果,真正的结果是右侧表达式的值
4.11 类型转换
-
隐式类型转换:
-
算术转换:在混合类型的表达式中,较小类型的运算对象会被转换成较大的类型
-
其他隐式转换:数组转换成指针、指针的转换、表达式转换成布尔类型等
-
-
显式转换(强制类型转换):
-
static_cast:用于良性转换,如基本数据类型之间的转换
-
const_cast:用于删除const性质
-
reinterpret_cast:通常为运算对象的位模式提供较低层次上的重新解释
-
dynamic_cast:支持运行时类型识别(本书不介绍)
-
第5章 语句
5.1 简单语句
-
表达式语句:表达式后面跟一个分号
-
空语句:只有一个分号,表示什么也不做
-
复合语句(块):用花括号括起来的语句和声明的序列,也称为块
5.2 语句作用域
-
在if、switch、while和for语句的控制结构内定义的变量,只在相应语句的内部可见
5.3 条件语句
-
if语句:
if (condition) statement else statement -
switch语句:
switch (expression) { case value1: statement(s); break; case value2: statement(s); break; ... default: statement(s); }-
break语句:用于中断switch语句的执行
-
default标签:当没有匹配的case时执行
-
5.4 迭代语句
-
while循环:
while (condition) statement -
传统的for循环:
for (init-statement; condition; expression) statement -
范围for循环(C++11):
for (declaration : expression) statement -
do while循环:
do statement while (condition);
5.5 跳转语句
-
break语句:终止离它最近的while、do while、for或switch语句,并从这些语句之后的第一条语句开始继续执行
-
continue语句:结束本次循环,跳过循环体中尚未执行的语句,接着执行下一次循环
-
goto语句:无条件跳转到同一函数内的另一条标号语句(不推荐使用)
5.6 try语句块和异常处理
-
throw表达式:引发异常,执行throw类似于执行了一个返回语句,但它不返回任何值而是抛出一个异常
-
try语句块:
try { program-statements } catch (exception-declaration) { handler-statements } catch (exception-declaration) { handler-statements } -
标准异常:C++标准库定义了一组类,用于报告在标准库函数中遇到的问题
第6章 函数
6.1 函数基础
-
函数的定义:返回类型、函数名字、由0个或多个形参组成的列表以及函数体
返回类型 函数名(参数列表) { 函数体 } -
形参和实参:
-
形参:函数定义时声明的参数
-
实参:函数调用时传递的参数
-
-
函数调用:包括函数名和括号括起来的实参列表
-
局部对象:
-
自动对象:普通局部变量,只存在于块执行期间的对象
-
静态局部对象:使用
static关键字声明,在程序的执行路径第一次经过对象定义语句时初始化,并且直到程序终止才被销毁
-
-
函数声明:函数的三要素(返回类型、函数名、形参类型)可以单独声明,通常放在头文件中
返回类型 函数名(参数类型1, 参数类型2, ...); -
分离式编译:允许将程序分割为多个文件
6.2 参数传递
-
传值参数:函数对形参做的所有操作都不会影响实参
-
传引用参数:使用引用形参可以直接操作实参,避免拷贝
void reset(int &i) { i = 0; } -
const形参和实参:顶层const不影响传入函数的对象,一个拥有底层const的形参无法使用普通实参初始化
-
数组形参:数组的两个特殊性质(不允许拷贝数组、使用数组时会将其转换成指针)使得我们不能以值传递的方式使用数组参数,通常使用指针或引用传递数组
-
main函数的参数:
int main(int argc, char *argv[])或int main(int argc, char **argv)
6.3 return语句
-
无返回值函数:返回类型是void的函数
-
有返回值函数:返回类型不为void的函数,必须使用return语句返回一个值
-
值是如何被返回的:返回一个值的方式和初始化一个变量或形参的方式完全一样
-
返回数组指针:可以使用类型别名、尾置返回类型或decltype简化返回数组指针的函数声明
6.4 函数重载
-
重载函数:同一作用域内的几个函数名字相同但形参列表不同
-
区分重载函数:编译器根据函数调用中实参的类型推断应该调用哪个函数
-
const重载:顶层const不影响传入函数的对象,底层const可以用于区分重载函数
-
调用重载函数:名字查找发生在类型检查之前
6.5 特殊用途语言特性
-
默认实参:为形参提供默认值,调用函数时可以省略这些形参
string screen(sz ht = 24, sz wid = 80, char backgrnd = ' '); -
内联函数和constexpr函数:
-
内联函数:建议编译器在调用点"内联地"展开函数体,避免函数调用的开销
-
constexpr函数:可以用于常量表达式的函数,函数体中必须有且只有一条return语句(C++11起有所放松)
-
-
调试帮助:使用预处理器定义
NDEBUG来禁用assert宏
6.6 函数匹配
-
函数匹配过程:确定候选函数和可行函数,然后从可行函数中选择最佳匹配,或者由于没有最佳匹配而报错
-
实参类型转换:为了匹配候选函数,实参可能需要进行类型转换
6.7 函数指针
-
函数指针:指向函数的指针,其类型由函数的返回类型和形参类型共同决定
bool (*pf)(const string &, const string &); // 未初始化的函数指针 pf = lengthCompare; // pf指向名为lengthCompare的函数 pf = &lengthCompare; // 等价的赋值语句,取地址运算符是可选的 bool b1 = pf("hello", "goodbye"); // 通过指针调用函数 bool b2 = (*pf)("hello", "goodbye"); // 等价的调用 bool b3 = lengthCompare("hello", "goodbye"); // 直接调用函数 -
函数指针形参:可以用函数指针作为形参,调用这样的函数时,既可以传递函数名,也可以传递函数指针
-
返回函数指针:函数可以返回函数指针,使用类型别名或尾置返回类型可以使声明更清晰
以上是对《C++ Primer》第1到6章的非常详细讲解。这些章节涵盖了C++编程的基础知识,包括基本语法、变量和基本类型、标准库类型、表达式、语句和函数。掌握这些内容对于进一步学习C++至关重要。
C++ Primer前六章核心解析
550

被折叠的 条评论
为什么被折叠?



