文章目录
C++ Primer Plus (第六版)
第1章 预备知识
第2章 开始学习C++
2.1 进入C++
C++大小写敏感。
2.2.1 main()指令
main()函数以函数头int main()开始。
在C++中,让括号空着与在括号中使用void等效(在C中,让括号空着意味着对是否接受参数保持沉默)。
编译器到达main()函数末尾时没有遇到返回语句,则认为main()函数以 return 0; 结尾。
2.2 C++语句
2.2.2 赋值语句
可以连续使用赋值运算符。
第3章 处理数据
3.1 简单变量
3.1.3 整形short、int、long和long long
#define编译指令的工作方式与文本编辑器或字处理器中的全局搜索并替换命令相似。
3.2 const限定符
使用const关键字来修改变量声明和初始化:
const int Month = 12;
可以在程序中使用Month,而不是12。此时Month为一个常量。
创建常量的通用格式:
const type name = value;
3.4 C++算数运算符
3.4.4 类型转换
强制类型转换:
//将存储在变量thorn中的int值转换为long类型:
(long) thorn
long (thorn)
强制转换的通用格式:
(typeName) value //该格式来自C语言
typeName (value) //纯粹的C++,要让强制转换就像是函数调用。
3.4.5 C++11中的auto声明
auto:让编译器根据初始值的类型推断变量的类型。
在初始化声明中,如果使用关键字auto,而不指定变量的类型,编译器将把变量的类型设置成与初始值相同。
3.6 复习题
6.如何使用C++来找出编码88表示的字符?指出至少两种方法。
#include<iostream>
using namespace std;
int main() {
char example = 88; //通过char类型变量直接输出
cout << example << endl;
cout << (char)88 << endl; //通过C风格的强制类型转换,将整形数据88转换为char类型输出
cout << char(88) <<endl; //通过C++风格的强制类型转换,将整形数据88转换为char类型输出
cout.put(char(88)) << endl; //通过cout.put()函数直接输出类型强制转换后的char数据
return 0;
}
3.7 编程练习
1.使用一个整数指出自己的身高,然后将身高转换为英尺和英寸。使用下划线字符来指示输入位置,使用一个符号常量const来表示转换因子。
#include<iostream>
using namespace std;
const int Trans = 12;
int main() {
int height;
cout << "Input your height: " << endl;
cin >> height;
cout << "Your height convert to " << height / Trans;
cout << " foot and ";
cout << height % Trans << " inch height." << endl;
return 0;
}
4.以整数方式输入秒数,然后以天、小时、分钟和秒的方式显示出这段时间。使用符号常量来表示每天有多少小时,每小时有多少分钟以及每分钟有多少秒。
#include<iostream>
using namespace std;
const int Day_hour = 24;
const int Hour_minute = 60;
const int Minute_second = 60;
int main() {
long long second;
cout << "Enter the number of seconds:" << endl;
cin >> second;
cout << second << " seconds = ";
int day = second / (Minute_second * Hour_minute * Day_hour);
second = second % (Minute_second * Hour_minute * Day_hour);
int hour = second / (Minute_second * Hour_minute);
second = second % (Minute_second * Hour_minute);
int minute = second / Minute_second;
second = second % Minute_second;
cout << day << " days, " << hour << " hours, ";
cout << minute << " minutes, " << second << " seconds." << endl;
return 0;
}
第4章 复合类型
4.4 结构简介
C++允许在声明结构变量时省略关键字struct。(C不允许省略struct)
4.7 指针和自由存储空间
面向对象编程与传统的过程性编程的区别在于:OOP强调在运行阶段(而不是编译阶段)进行决策。
4.7.4 使用new来分配内存
new将找到一个正确的内存块,并返回该内存块的地址。
为一个数据对象(可以是结构,也可以是基本类型)获得并指定分配内存的通用格式:
typeName * pointer_name = new typeName;
new分配的内存块通常与常规变量声明分配的内存块不同。new从堆区或自由存储区的内存区域分配内存,常规声明变量从栈区分配内存。
4.7.5 使用delete释放内存
一定要配对使用new和delete。
4.7.6 使用new来创建动态数组
静态联编:在编译时给数组分配内存;
动态联编:数组在程序运行时创建,需要则创建,不需要则不创建,还可以在程序运行时选择数组的长度(动态数组)。
第5章 循环和关系表达式
5.1 for循环
5.1.1 for循环的组成部分
C++常用的方式是:在for和括号之间加上一个空格,而省略函数名与括号之间的空格。
for (initialization; test-expression; update-expression)
body
对于其他控制语句(如if和while)处理方式与for相似。这样从视觉上强化了控制语句和函数调用之间的区别。
5.1.5 递增运算符(++)和递减运算符(–)
a++:使用a的当前值计算表达式,然后将a的值加1;
++a:先将a的值加1,然后使用新的值来计算表达式。
5.1.7 前缀格式和后缀格式
对于类而言,前缀版本(++x)的效率比后缀版本(x–)高。
5.4 基于范围的for循环(C++11)
C++新增一种循环:基于范围的for循环。
简化了一种常见的循环任务:对数组(或容器类,如vector和array)的每个元素执行相同的操作。
循环显示数组中的每个值,且不能改变数组元素的值:
double prices[5] = {4.99, 10.99, 6.87, 7.99, 8.49};
for (double x : prices)
cout << x << std::endl;
引用符号&可以修改数组的内容:
double prices[5] = {4.99, 10.99, 6.87, 7.99, 8.49};
for (double &x : prices)
x = x * 0.80;
第6章 分支语句和逻辑运算符
6.3 字符库函数cctype
**P148 表6.4 **
头文件cctype(ctype.h)
isalpha():检查字符是否为字母字符;
isdigit():测试字符是否为数字字符;
isspace():测试字符是否为空白,如换行符、空格、制表符;
ispunct():测试字符是否为标点符号。
6.4 ?: 运算符
条件运算符:
expression1 ? expression2 : expression3
如果expression1为true,则整个条件表达式的值为expression2的值;否则,整个条件表达式的值为expression3的值。
6.6 break和continue语句
break和continue语句都能使程序跳过部分代码。
可以在swith语句或任何循环中使用break语句,使程序跳到switch或循环后面的语句处执行。
continue语句用于循环中,让程序跳过循环体中余下的代码,并开始新一轮循环。
第7章 函数——C++的编程模块
7.1 复习函数的基本知识
7.1.1 定义函数
函数通过将返回值复制到指定的CPU寄存器或内存单元中将其返回。随后,调用程序将查看该内存单元。
7.1.2 函数原型和函数调用
在原型的参数列表中,可以包括变量名,也可以不包括。
void cheers(int); //函数原型
7.3 函数和数组
7.3.1 函数如何使用指针来处理数组
C++将数组名解释为其第一个元素的地址:
int cookies[8];
cookies == &cookies[0]; //该表达式成立
数组声明使用数组名来标记存储位置;其次,对数组名使用sizeof将得到整个数组的长度(以字节为单位);最后,将地址运算符&用于数组名时,将返回整个数组的地址,例如&cookies将返回一个32字节内存块的地址(如果int长4字节)。
两个恒等式:
arr[i] == *(arr + i)
&arr[i] == arr + i
7.3.5 指针和const
C++禁止将const的地址赋给非const指针。
尽可能使用const:
- 可以避免由于无意间修改数据而导致的编程错误;
- 使用const使得函数能够处理const和非const实参,否则将只能接受非const数据。
声明指向const对象的const指针:
double trouble = 2.0E30;
const double * const stick = &trouble;
其中,stick只能指向trouble,且stick不能用来修改trouble的值。
7.5 函数与C风格字符串
7.5.1 将C风格字符串作为参数的函数
假设要将字符串作为参数传递给函数,则表示字符串的方式有3种:
- char数组;
- 用引号括起的字符串常量(也称字符串字面值);
- 被设置为字符串的地址的char指针。
上述3种选择的类型都是char指针(准确的说是char*),因此可以将其作为字符串处理函数的参数。
char ghost[15] = "galloping";
char * str = "galloping";
int n1 = strlen(ghost); //ghost is &ghost[0]
int n2 = strlen(str); //pointer to char
int n3 = strlen("galloping"); //address of string
可以说是将字符串作为参数来传递,但实际传递的是字符串第一个字符的地址。字符串函数原型应将其表示字符串的形参声明为char * 类型。
7.10 函数指针
7.10.1 函数指针的基础知识
获取函数的地址:只要使用函数名(后面不跟参数)即可。
如果think()是一个函数,则think就是该函数的地址。
要将函数作为参数进行传递,必须传递函数名。
7.10.3 深入探讨函数指针
在函数原型中,可以省略标识符。
函数定义必须提供标识符。
自动类型推断只能用于单值初始化,而不能用于初始化列表。
7.10.4 使用typedef进行化简
第8章 函数探幽
8.1 C++内联函数
编译器将使用相应的函数代码替换函数调用。
使用内联函数的措施:
- 在函数声明前加上关键字inline;
- 在函数定义前加上关键字inline。
8.2 引用变量
8.2.1 创建引用变量
int rats;
int & rodents = rats;
上述引用声明允许将rats和rodents互换——它们指向相同的值和内存单元。
引用必须在声明时将其初始化。
引用更接近const指针,一旦与某个变量关联,就将一直效忠于它。
int * const pr = &rats;
8.2.2 将引用用作函数参数
按引用传递允许被调用的函数能够访问调用函数中的变量。
8.2.3 引用的属性和特别之处
如果接受引用参数的函数的意图时修改作为参数传递的变量,则创建临时变量将阻止这种意图的实现。解决方法是,禁止创建临时变量。
如果函数效用的参数不是左值或与相应的const引用参数的类型不匹配,则C++将创建类型正确的匿名变量,将函数调用的参数的值传递给该匿名变量,并让参数来引用该变量。
应尽可能使用const,将应用参数声明为常量数据的引用的理由:
- 使用const可以避免无意中修改数据的编程错误;
- 使用const使函数能够处理const和非const实参,否则将只能接受非const数据;
- 使用const引用使函数能够正确生成并使用临时变量。
8.2.4 将引用用于结构
//free_throws是一个结构
free_throws & accumulate(free_throws & target, const free_throws & source); //函数原型
dup = accumulate(team, five);
如果accumulate()函数返回一个结构,而不是指向结构的引用,将把整个结构复制到一个临时位置,再将这个拷贝复制给dup。但在返回值为引用时,将直接把team复制到dup,其效率更高。
将const用于引用返回类型
8.2.5 将引用用于类对象
使用引用的效率更高,因为函数不需要创建新的对象,并将原来对象中的数据复制到新对象中。
8.2.6 对象、继承和引用
继承:能够将特性从一个类传递给另一个类的语言特性。
8.2.7 何时使用引用参数
- 数据对象是类对象,则使用const引用。
8.3 默认参数
默认参数指的是当函数调用中省略了实参时自动使用的一个值。
通过函数原型设置默认值:
char * left(const char * str, int n = 1); //函数原型
对于带参数列表的函数,必须从右向左添加默认值。要为某个参数设置默认值,则必须为它右边的所有参数提供默认值。
8.4 函数重载
函数多态是C++在C语言的基础上新增的功能,默认参数能够使用不同数目的参数调用同一个函数,而函数多态(函数重载)能够使用多个同名的函数。
函数多态:允许函数有多种形式;
函数重载:可以有多个同名的函数。
函数重载的关键是函数的参数列表——函数特征标。
8.5 函数模板
函数模板:使用泛型定义函数。通过将类型作为参数传递给模板,使编译器生成该类型的函数。
函数模板允许以任意类型的方式来定义函数,例如:
template <typename AnyType> //可以使用关键字class代替typename
void swap(AnyType &a, AnyType &b)
{
AnyType temp;
temp = a;
a = b;
b = temp;
}
8.5.2 模板的局限性
为特性类型提供具体化的模板定义。
8.5.3 显示具体化
8.5.4 实例化和具体化
//模板原型
template <class T>
void Swap(T &, T &);
//显式实例化
template void Swap<int> (int, int);
//显式具体化
template <> void Swap<int>(int &, int &);
template <> void Swap(int &, int &);
8.5.5 编译器选择使用哪个函数版本
8.5.6 模板函数的发展
关键字decltype(C++11)
第9章 内存模型和名称空间
9.1 单独编译
文件名包含在尖括号中,则C++编译器将在存储标准头文件的主机系统的文件系统中查找;
文件名包含在双引号中,则编译器将首先查找当前的工作目录或源代码目录。如果没有在那里找到头文件,则将在标准位置查找。
因此在包含自己的头文件时,应使用引号而不是尖括号。
第10章 对象和类
10.2 抽象和类
10.2.2 C++中的类
数据项通常放在私有部分,组成类接口的成员函数放在公有部分。(隐藏数据)
类对象的默认访问控制:private。
10.3 类的构造函数和析构函数
10.3.3 默认构造函数
当且仅当没有定义任何构造函数时,编译器才会提供默认构造函数。
第18章 探讨C++新标准
18.1 复习前面介绍过的C++11功能
18.1.9 右值引用
C++11新增右值引用:使用&&表示。
右值引用可关联到右值。
18.4 Lambda函数
18.4.1 比较函数指针、函数符和Lambda函数
定义函数:
bool f3(int x) {return x % 3 == 0;}
与f3对应的lambda函数如下:
[](int x) {return x % 3 == 0;}
差别:
使用[]替代了函数名;
没有声明返回类型。返回类型相当于使用decltyp根据返回值推断得到的。
仅当lambda表达式完全由一条返回语句组成时,自动类型推断才管用,否则,需要使用新增的返回类型后置语法:
[](double x)->double{int y = x; return x - y;}