c++基础知识(C++Primer4th第四版中文版)

学习C++使用的两种开发工具
1、codeblocks
如果你希望开发工具的容量很小,建议使用这个工具。系统较小但功能很强,非常适合教学用。
2、VS2015(自带Update2)

安装文件容量比较大,如果你希望学习和实际用的开发工具一致,建议使用这个开发工具。

Win32控制台应用程序、Win32项目、MFC应用程序的区别与联系 - CSDN博客  http://blog.csdn.net/zhao1999qian/article/details/57084143

什么是运算符?C++中算数运算符、关系运算符、逻辑运算符等常用运算符讲解 - CSDN博客  http://blog.csdn.net/kingvon_liwei/article/details/65936927

C++控制台应用程序窗口暂停
只需要在main函数里添加
第一种方式:system("pause");
第二种方式:getchar();
第三种方式:sleep();
第四种方式:cin.get();


【C++】第1章 在VS2015中用C++编写控制台应用程序 - rainmj - 博客园  https://www.cnblogs.com/rainmj/p/5578656.html
在VS2015中用C++编写控制台应用程序
1、新建项目
运行VS2015,在起始页中选择【新建项目】,在弹出的新建项目窗口中,选择【其他语言】->【C++】->【Win32】->【Win32控制台应用程序】
2、编写代码
3、调试运行
按<F5>键调试运行。

代码格式
删除最后一个大括号,然后重新键入,它就会自动重新调整代码的格式。
4、生成32位的exe还是64位的exe
调试时有两种生成方式,一种是生成32位的本机代码,另一种是生成64位的本机代码。

如果希望生成64位本机代码,只需要单击x32右侧的下拉框,选择为x64即可:

读书笔记:



1.2. 初窥输入/输出
C++ 并没有直接定义进行输入或输出(IO)的任何语句,这种功能是由标准库提供的。IO 库提供了大量的设施。处理格式化输入和输出的 iostream 库。
iostream 库的基础是两种命名为 istream 和 ostream 的类型,分别表示输入流和输出流。流是指要从某种 IO 设备上读入或写出的字符序列。术语“流”试图说明字符是随着时间顺序生成或消耗的。
1.2.1. 标准输入与输出对象
标准库定义了 4 个 IO 对象。cin、cout、cerr、clog。
一般情况下,系统将这些对象与执行程序的窗口联系起来。这样,当我们从cin 读入时,数据从执行程序的窗口读入。
运行程序时,大部分操作系统都提供了重定向输入或输出流的方法。利用重定向可以将这些流与所选择的文件联系起来。
endl 是一个特殊值,称为操纵符,将它写入输出流时,具有输出换行的效果,并刷新与设备相关联的 缓冲区。通过刷新缓冲区,用户可立即看到写入到流中的输出。

输入操作符(>> 操作符)行为与输出操作符相似。它接受一个 istream 对象作为其左操作数,接受一个对象作为其右操作数,它从 istream 操作数读取数据并保存到右操作数中。像输出操作符一样,输入操作符返回其左操作数作为结果。

Sales_item.h
C++中我们通过定义类来定义自己的数据结构。类机制是 C++ 中最重要的特征之一。
事实上, C++ 设计的主要焦点就是使所定义的类类型的行为可以像内置类型一样自然。我们前面已看到的像 istream 和 ostream 这样的库类型,都是定义为类的,也就是说,它们严格说来不是语言的一部分。

我们假定类命名为 Sales_item 且类定义在命名为Sales_item.h 的头文件中。

1.5.1.Sales_item 类
Sales_item 类的目的是存储 ISBN 并保存该书的销售册数、销售收入和平均售价。我们不关心如何存储或计算这些数据。使用类时我们不需要知道这个类是怎样实现的,相反,我们需要知道的是该类提供什么操作。正如我们所看到的,使用像 IO 一样的库工具,必须包含相关的头文件。类似地,对于自定义的类,必须使得编译器可以访问和类相关的定义。这几乎可以采用同样的方式。一般来说,我们将类定义放入一个文件中,要使用该类的任何程序都必须包含这个文件。
依据惯例,类类型存储在一个文件中,其文件名如同程序的源文件名一样,由文件名和文件后缀两部分组成。通常文件名和定义在头文件中的类名是一样的。通常后缀是.h,但也有一些程序员用.H、.hpp 或.hxx。编译器通常并不挑剔头文件名,但 IDE 有时会。假设我们的类定义在名为 Sale_item.h 的文件中。
Sales_item 对象上的操作
每个类定义一种类型,类型名与类名相同。因此,我们的 Sales_item 类定义了一种命名为 Sales_item 的类型。像使用内置类型一样,可以定义类类型的变量。当写下Sales_item item; 就表示 item 是类型 Sales_item 的一个对象。通常将“类型 Sales_item的一个对象”简称为“一个 Sales_item 对象”,或者更简单地简称为“一个Sales_item”。除了可以定义 Sales_item 类型的变量,我们还可以执行 Sales_item 对象的以下操作:
• 使用加法操作符, + ,将两个 Sales_item 相加。
• 使用输入操作符, << ,来读取一个 Sales_item 对象。
• 使用输出操作符, >> ,来输出一个 Sales_item 对象
• 使用赋值操作符, = ,将一个 Sales_item 对象赋值给另一个 Sales_item对象。
调用 same_isbn 函数确定两个 Sales_item 是否指同一本书
调用命名为 item1 的 Sales_item 对象的成员函数。 成员函数是由类定义的函数,有时称为类方法。
成员函数只定义一次,但被视为每个对象的成员。我们将这些操作称为成员函数,是因为它们(通常)在特定对象上操作。在这个意义上,它们是对象的成员,即使同一类型的所有对象共享同一个定义也是如此。

当调用成员函数时,(通常)指定函数要操作的对象。语法是使用点操作符(.):(p44)

一些程序设计语言,特别是Smalltalk 和 Python,在运行时才检查语句中对象的类型。相反,C++ 是静态
类型(statically typed)语言,在编译时执行类型检查。结果是程序中使用某
个名字之前,必须先告知编译器该名字的类型。


布尔字面值和字符字面值(p63):
单词 true 和 false 是布尔型的字面值:bool test = false;
可打印的字符型字面值通常用一对单引号来定义:'a' '2' ',' ' ' // blank
这些字面值都是 char 类型的。在字符字面值前加 L 就能够得到 wchar_t类型的宽字符字面值。如:L'a'
非打印字符的转义序列:
有些字符是不可打印的。不可打印字符实际上是不可显示的字符,比如退格
或者控制符。还有一些在语言中有特殊意义的字符,例如单引号、双引号和反斜
线符号。不可打印字符和特殊字符都用转义字符书写。转义字符都以反斜线符号
开始,C++ 语言中定义了如下转义字符:
换行符 \n 水平制表符 \t
纵向制表符 \v 退格符 \b
回车符 \r 进纸符 \f
报警(响铃)符 \a 反斜线 \\
疑问号 \? 单引号 \'
双引号 \
\ooo
这里 ooo 表示三个八进制数字,这三个数字表示字符的数字值。下面的例
子是用 ASCII 码字符集表示字面值常量:
\7 (bell) \12 (newline) \40 (blank)
\0 (null) \062 ('2') \115 ('M')
字符’\0’通常表示“空字符(null character)”,我们将会看到它有着
非常特殊的意义。
同样也可以用十六进制转义字符来定义字符:\xddd
它由一个反斜线符、一个 x 和一个或者多个十六进制数字组成。

字符串字面值:
之前见过的所有字面值都有基本内置类型。 还有一种字面值(字符串字面值)
更加复杂。字符串字面值是一串常量字符,这种类型将在第 4.3 节详细说明。
字符串字面值常量用双引号括起来的零个或者多个字符表示。不可打印字符
表示成相应的转义字符。
"Hello World!"
C++ 关键字:
C++ 操作符替代名:
变量命名习惯:

变量命名有许多被普遍接受的习惯,遵循这些习惯可以提高程序的可读性。
• 变量名一般用小写字母。例如,通常会写成 index,而不写成 Index 或INDEX。
• 标识符应使用能帮助记忆的名字,也就是说,能够提示其在程序中的用法的名字,如 on_loan 或 salary。
• 包含多个词的标识符书写为在每个词之间添加一个下划线, 或者每个内嵌的词的第一个字母都大写。例如通常会写成 student_loan 或studentLoan,而不写成 studentloan。
变量初始化(p75,78):
初始化:变量定义指定了变量的类型和标识符,也可以为对象提供初始值。定义时指定了初始值的对象被称为是已初始化的。C++ 支持两种初始化变量的形式: 复制初始化和直接初始化。复制初始化语法用等号(=),直接初始化则是把初始化
式放在括号中:
int ival(1024); // direct-initialization
int ival = 1024; // copy-initialization
这两种情形中,ival 都被初始化为 1024。

使用多个初始化式
初始化内置类型的对象只有一种方法:提供一个值,并且把这个值复制到新定义的对象中。对内置类型来说,复制初始化和直接初始化几乎没有差别。
对类类型的对象来说,有些初始化仅能用直接初始化完成。要想理解其中缘由,需要初步了解类是如何控制初始化的。
警告:未初始化的变量引起运行问题
内置类型变量的初始化(p77)
类类型变量的初始化
变量声明和定义(p79)
声明和定义
正如将在第 2.9 节所看到的那样,C++ 程序通常由许多文件组成。为了让多个文件访问相同的变量,C++ 区分了声明和定义。
变量的定义用于为变量分配存储空间,还可以为变量指定初始值。在一个程序中,变量有且仅有一个定义。
声明用于向程序表明变量的类型和名字。定义也是声明:当定义变量时我们声明了它的类型和名字。可以通过使用 extern 关键字声明变量名而不定义它。
不定义变量的声明包括对象名、对象类型和对象类型前的关键字 extern:
extern int i; // declares but does not define i
int i; // declares and defines i
extern 声明不是定义,也不分配存储空间。事实上,它只是说明变量定义在程序的其他地方。程序中变量可以声明多次,但只能定义一次。
名字的作用域:
第七章将详细讨论局部作用域和全局作用域,第六章将讨论语句作用域。C++ 还有另外两种不同级别的作用域:类作用域(第十二章将介绍)和命名空间作用域(第 17.2 节将介绍)。

2.5. 引用(&用法p88)
引用就是对象的另一个名字。 任何对 id 的操作都会转变为对object 的操作。在实际程序中, 引们将在第 7.2.2 节 再详细介绍引用参数。在这并举例说明引用的用法。

引用是一种复合类型,通过在变量名前添加“&”符号来定义。复合类型是指用其他类型定义的类型。在引用的情况下,每一种引用类型都“关联到”某一其他类型。不能定义引用类型的引用,但可以定义任何其他类型的引用。

引用必须用与该引用同类型的对象初始化:

int ival = 1024;
int &refVal = ival; // ok: refVal refers to ival
int &refVal2; // error: a reference must be initialized
int &refVal3 = 10; // error: initializer must be an object
refVal += 2;
将 refVal 指向的对象 ival 加 2。

const 引用(p90)
const 引用是指向 const 对象的引用:
const int ival = 1024;
const int &refVal = ival;
可以读取但不能修改 refVal ,因此,任何对 refVal 的赋值都是不合法的。
double dval = 3.14;
const int &ri = dval;
编译器会把这些代码转换成如以下形式的编码:
int temp = dval; // create temporary int from the double
const int &ri = temp; // bind ri to that temporary
ri的值是3。
如果 ri 不是 const,那么可以给 ri 赋一新值。这样做不会修改 dval,而是修改了 temp。期望对 ri 的赋值会修改 dval 的程序员会发现 dval 并没有被修改。仅允许 const 引用绑定到需要临时使用的值完全避免了这个问题,
因为 const 引用是只读的。
非 const 引用只能绑定到与该引用同类型的对象。

const 引用则可以绑定到不同但相关的类型的对象或绑定到右值。

int i, &ri = i;
i = 5; ri =10;

std::cout << i << " " << ri << std::endl;

\\i、ri的值都为10。
对ri赋值10,就是对i赋值。

2.6. typedef 名字91
typedef 可以用来定义类型的同义词:
typedef double wages; // wages is a synonym for double
typedef 通常被用于以下三种目的:
• 为了隐藏特定类型的实现,强调使用类型的目的。
• 简化复杂的类型定义,使其更易理解。
• 允许一种类型用于多个目的,同时使得每次使用该类型的目的明确。

2.7. 枚举
定义和初始化枚举
枚举的定义包括关键字 enum,其后是一个可选的枚举类型名,和一个用花括号括起来、用逗号分开的枚举成员列表。
// input is 0, output is 1, and append is 2
enum open_modes {input, output, append};
默认地,第一个枚举成员赋值为 0,后面的每个枚举成员赋的值比前面的大1。

枚举成员值可以是不唯一的。每个 enum 都定义了一种新的类型。和其他类型一样,可以定义和初始化Points 类型的对象,也可以以不同的方式使用这些对象。枚举类型的对象的初始化或赋值,只能通过其枚举成员或同一枚举类型的其他对象来进行。

2.8. 类类型(p93)
C++ 中,通过定义类来自定义数据类型。类定义了该类型的对象包含的数据和该类型的对象可以执行的操作。标准库类型 string、istream 和 ostream 都定义成类。

类定义以关键字 class 开始,其后是该类的名字标识符。类体位于花括号里面。
花括号后面必须要跟一个分号。!!!!!!!!!!!!!
类体可以为空。类体定义了组成该类型的数据和操作。这些操作和数据是类的一部分,也称为类的成员。操作称为成员函数(第 1.5.2 节),而数据则称为数据成员。
类也可以包含 0 个到多个 private 或 public 访问标号。访问标号控制类的成员在类外部是否可访问。使用该类的代码可能只能访问 public 成员。
定义了类,也就定义了一种新的类型。类名就是该类型的名字。而且程序也可以定义该类型的变量。
每一个类都定义了它自己的作用域(第 2.3.6 节)。也就是说,数据和操作的名字在类的内部必须唯一,但可以重用定义在类外的名字。
class Sales_item {
public:
// operations on Sales_item objects will go here
private:
std::string isbn;
unsigned units_sold;
double revenue;
};//特别注意:花括号后面必须要跟一个分号!!!

定义类的数据成员和定义普通变量有些相似。但区别重大!!
定义变量和定义数据成员存在非常重要的区别:一般不能把类成员的初始化作为其定义的一部分。当定义数据成员时,只能指定该数据成员的名字和类型。类不是在类定义里定义数据成员时初始化数据成员,而是通过称为构造函数(第2.3.3 节)的特殊成员函数控制初始化。我们将在第 7.7.3 节定义 Sales_item的构造函数。
访问标号public、private:
访问标号负责控制使用该类的代码是否可以使用给定的成员。类的成员函数可以使用类的任何成员,而不管其访问级别。访问标号 public、private 可以多次出现在类定义中。给定的访问标号应用到下一个访问标号出现时为止。
类中 public 部分定义的成员在程序的任何部分都可以访问。一般把操作放在 public 部分,这样程序的任何代码都可以执行这些操作。
不是类的组成部分的代码不能访问 private 成员。

使用 struct 关键字(p96)
C++ 支持另一个关键字 struct,它也可以定义类类型。struct 关键字是从C 语言中继承过来的。
如果使用 class 关键字来定义类,那么定义在第一个访问标号前的任何成员都隐式指定为 private;如果使用 struct 关键字,那么这些成员都是public。使用 class 还是 struct 关键字来定义类,仅仅影响默认的初始访问级别。
2.9. 编写自己的头文件
一般类定义都会放入头文件。

头文件为相关声明提供了一个集中存放的位置。头文件一般包含类的定义、extern 变量的声明和函数的声明。函数的声明将在第 7.4 节介绍。使用或定义这些实体的文件要包含适当的头文件。
头文件的正确使用能够带来两个好处:保证所有文件使用给定实体的同一声明;当声明需要修改时,只有头文件需要更新。
设计头文件还需要注意以下几点:头文件中的声明在逻辑上应该是统一的。
编译头文件需要一定的时间。如果头文件太大,程序员可能不愿意承受包含该头文件所带来的编译时代价。
为了减少处理头文件的编译时间,有些 C++的实现支持预编译头文件。欲进一步了解详细情况,请参考你的 C++ 实现的手册。
头文件用于声明而不是用于定义
当设计头文件时, 记住定义和声明的区别是很重要的。 定义只可以出现一次,而声明则可以出现多次(第 2.3.5 节)。下列语句是一些定义,所以不应该放在头文件里:
extern int ival = 10; // initializer, so it's a definition
double fica_rate; // no extern, so it's a definition
虽然 ival 声明为 extern,但是它有初始化式,代表这条语句是一个定义。
类似地,fica_rate 的声明虽然没有初始化式,但也是一个定义,因为没有关键字 extern。同一个程序中有两个以上文件含有上述任一个定义都会导致多重定义链接错误。
因为头文件包含在多个源文件中,所以不应该含有变量或函数的定义。
对于头文件不应该含有定义这一规则,有三个例外。
头文件可以定义类、值在编译时就已知道的 const 对象和 inline 函数(第 7.6 节介绍 inline 函数)。这些实体可在多个源文件中定义,只要每个源文件中的定义是相同的。
在头文件中定义这些实体,是因为编译器需要它们的定义(不只是声明)来产生代码。例如:为了产生能定义或使用类的对象的代码,编译器需要知道组成该类型的数据成员。同样还需要知道能够在这些对象上执行的操作。类定义提供所需要的信息。在头文件中定义 const 对象则需要更多的解释。
一些 const 对象定义在头文件中
回想一下,const 变量(第 2.4 节)默认时是定义该变量的文件的局部变量。正如我们现在所看到的,这样设置默认情况的原因在于允许 const 变量定义在头文件中。
在 C++ 中,有些地方需要放置常量表达式(第 2.7 节)。例如,枚举成员的初始化式必须是常量表达式。在以后的章节中将会看到其他需要常量表达式的例子。
一般来说,常量表达式是编译器在编译时就能够计算出结果的表达式。当const 整型变量通过常量表达式自我初始化时,这个 const 整型变量就可能是常量表达式。而 const 变量要成为常量表达式,初始化式必须为编译器可见。
为了能够让多个文件使用相同的常量值, const 变量和它的初始化式必须是每个文件都可见的。而要使初始化式可见,一般都把这样的 const 变量定义在头文件中。那样的话,无论该 const 变量何时使用,编译器都能够看见其初始化式。(p101)
但是,C++ 中的任何变量都只能定义一次(第 2.3.5 节)。定义会分配存储空间,而所有对该变量的使用都关联到同一存储空间。因为 const 对象默认为定义它的文件的局部变量,所以把它们的定义放在头文件中是合法的。
这种行为有一个很重要的含义:当我们在头文件中定义了 const 变量后,每个包含该头文件的源文件都有了自己的 const 变量,其名称和值都一样。
当该 const 变量是用常量表达式初始化时,可以保证所有的变量都有相同的值。但是在实践中,大部分的编译器在编译时都会用相应的常量表达式替换这些 const 变量的任何使用。所以,在实践中不会有任何存储空间用于存储用常量表达式初始化的 const 变量。
如果 const 变量不是用常量表达式初始化,那么它就不应该在头文件中定义。相反,和其他的变量一样,该 const 变量应该在一个源文件中定义并初始化。应在头文件中为它添加 extern 声明,以使其能被多个文件共享。

预处理器(P103)
#include 设施是 C++ 预处理器的一部分。
#include 指示只接受一个参数:头文件名。预处理器用指定的头文件的内容替代每个 #include。

头文件经常需要其他头文件
头文件经常 #include 其他头文件。
设计头文件时,应使其可以多次包含在同一源文件中,这一点很重要。我们必须保证多次包含同一头文件不会引起该头文件定义的类和对象被多次定义。使得头文件安全的通用做法,是使用预处理器定义头文件保护符。头文件保护符用于避免在已经见到头文件的情况下重新处理该头文件的内容。

为了避免名字冲突,预处理器变量经常用全大写字母表示。
预处理器变量有两种状态:已定义或未定义。定义预处理器变量和检测其状态所用的预处理器指示不同。#define 指示接受一个名字并定义该名字为预处理器变量。#ifndef 指示检测指定的预处理器变量是否未定义。如果预处理器变量未定义,那么跟在其后的所有指示都被处理,直到出现 #endif。
#ifndef SALESITEM_H
#define SALESITEM_H
// Definition of Sales_itemclass and related functions goes here
#endif
使用自定义的头文件
#include 指示接受以下两种形式:
#include <standard_header>
#include "my_file.h"
如果头文件名括在尖括号(< >)里,那么认为该头文件是标准头文件。编译器将会在预定义的位置集查找该头文件, 这些预定义的位置可以通过设置查找路径环境变量或者通过命令行选项来修改。使用的查找方法因编译器的不同而差别迥异。建议你咨询同事或者查阅编译器用户指南来获得更多的信息。如果头文件名括在一对引号里,那么认为它是非系统头文件,非系统头文件的查找通常开始于源文件所在的路径。


小结
类型是 C++ 程序设计的基础。105
每种类型都定义了其存储空间要求和可以在该类型的所有对象上执行的操作。C++ 提供了一组基本内置类型,如 int、char 等。这些类型与它们在机器硬件上的表示方式紧密相关。
类型可以为 const 或非 const;const 对象必须要初始化,且其值不能被修改。另外,我们还可以定义复合类型,如引用。引用为对象提供了另一个名字。复合类型是用其他类型定义的类型。
C++ 语言支持通过定义类来自定义类型。标准库使用类设施来提供一组高级的抽象概念,如 IO 和 string 类型。


C++ 是一种静态类型语言:变量和函数在使用前必须先声明。变量可以声明多次但是只能定义一次。定义变量时就进行初始化几乎总是个好主意。

术语:

run time(运行时)指程序正执行的那段时间。
void type(空类型)
用于特殊目的的没有操作也没有值的类型。不可能定义一个 void 类型的变量。最经常用作不返回结果的函数的返回类型。
word(字)

机器上的自然的整型计算单元。通常一个字足以容纳一个地址。一般在 32位的机器上,机器字长为 4 个字节。

术语(C++Primer4th第四版中文版p53页)

操作符、操作数:"."、"<<"、">>"等操作符,操作符左右为操作数。

argument(实参):传递给被调用函数的值
class:用于自定义数据结构的 C++ 机制。如 istream 和 ostream,都是类。
header(头文件):使得类或其他名字的定义在多个程序中可用的一种机制。程序中通过#include 指示包含头文件。
curly brace(花括号)
main function(主函数):执行 C++ 程序时,操作系统调用的函数。每一个程序有且仅有一个主函数 main。
manipulator(操纵符):在读或写时“操纵”流本身的对象,如 std::endl。A.3.1 节详细讲述操纵符。
member function(成员函数):类定义的操作。成员函数通常在特定的对象上进行操作。
method(方法):成员函数的同义词。
namespace(命名空间):将库所定义的名字放至单独一个地方的机制。命名空间有助于避免无意的命名冲突。C++ 标准库所定义的名字在命名空间 std 中。
ostream(输出流):提供面向流的输出的库类型。
parameter list(形参表):函数定义的组成部分。指明可以用什么参数来调用函数,可能为空。
preprocessor directive(预处理指示):C++ 预处理器的指示。#include 是一个预处理器指示。预处理器指示必须出现在单独的行中。第 2.9.2 节将对预处理器作详细的介绍。
standard input(标准输入):和程序执行窗口相关联的输入流,通常这种关联由操作系统设定。
standard library(标准库):每个 C++ 编译器必须支持的类型和函数的集合。标准库提供了强大的功能,包括支持 IO 的类型。C++ 程序员谈到的“标准库”,是指整个标准库,当提到某个标准库类型时也指标准库中某个特定的部分。例如,程序员提到的“iostream 库”, 专指标准库中由 iostream 类定义的那部分。
standard output(标准输出):和程序执行窗口相关联的输出流,通常这种关联由操作系统设定。
statement(语句):C++ 程序中最小的独立单元,类似于自然语言中的句子。C++ 中的语句一般以分号结束。
std:标准库命名空间的名字,std::cout 表明正在使用定义在 std 命名空间中的名字 cout。
string literal(字符串字面值):以双引号括起来的字符序列。
uninitialized variable(未初始化变量):没有指定初始值的变量。类类型没有未初始化变量。没有指定初始值的类类型变量由类定义初始化。在使用变量值之前必须给未初始化的变量赋值。未初始化变量是造成 bug 的主要原因之一。未实始化的变量赋值,可能由系统分配一个随机值,导致系统发生错误
variable(变量):有名字的对象。
while statement(while 语句):一种迭代控制语句, 只要指定的条件为真就执行 while环体执行 0 次还是多次,依赖于条件的真值
() operator[()操作符]:调用操作符。跟在函数名后且成对出现的圆括号。该操作符导致函数被调用,给函数的实参可在括号里传递。
++ operator(++操作符):自增操作符。将操作数加 1,++i 等价于 i = i + 1。
+= operator(+= 操作符):复合赋值操作符,将右操作数和左操作数相加,并将结果存储到左操作数中;a += b 等价于 a = a + b。
. operator(. 操作符):点操作符。接受两个操作数:左操作数是一个对象,而右边是该对象的一个成员的名字。这个操作符从指定对象中取得成员。
:: operator(:: 操作符):作用域操作符。在 第二章中,我们将看到更多关于作用域的介绍。在其他的使用过程中, :: 操作符用于在命名空间中访问名字。例如, std::cout表示使用命名空间 std 中的名字 cout。
= operator(= 操作符):表示把右操作数的值赋给左操作数表示的对象。
<< operator(<< 操作符):
输出操作符。把右操作数写到左操作数指定的输出流: cout << "hi" 把 hi写入到标准输出流。输出操作可以链接在一起使用:cout << "hi << "bye"输出 hibye。

>> operator(>> 操作符):输入操作符。从左操作数指定的输入流读入数据到右操作数:cin >> i 把标准输入流中的下一个值读入到 i 中。输入操作能够链接在一起使用:cin >> i >> j 先读入 i 然后再读入 j。


一些程序设计语言,特别是Smalltalk 和 Python,在运行时才检查语句中对象的类型。相反,C++ 是静态
类型(statically typed)语言,在编译时执行类型检查。结果是程序中使用某
个名字之前,必须先告知编译器该名字的类型。



--------------------------------------------------------------------------

第三章 标准库类型


除第二章介绍的基本数据类型外,C++ 还定义了一个内容丰富的抽象数据类型标准库。
其中 最重要的标准库类型是 string 和 vector,它们分别定义了大小可变的字符串和集合。string 和 vector 往往将迭代器用作配套类型(companion type),用于访问 string 中的字符,或者 vector 中的元素。这些标准库类型是语言组成部分中更基本的那些数据类型( 如数组和指针)的抽象。
另一种标准库类型 bitset,提供了一种抽象方法来操作位的集合。与整型值上的内置位操作符相比,bitset 类类型提供了一种更方便的处理位的方式。
本章将介绍标准库中的 vector、string 和 bitset 类型。
第四章将讨论数组和指针,第五章将讲述内置位操作符
第二章所涉及的类型都是低层数据类型:这些类型表示数值或字符的抽象,并根据其具体机器表示来定义。
3.1. 命名空间的 using 声明
使用 using 声明可以在不需要加前缀 namespace_name:: 的情况下访问命名空间中的名字。using 声明的形式如下:
using namespace::name;
using std::cin;
using std::string;
没有 using 声明,而直接使用命名空间中名字的未限定版本是错误的,尽管有些编译器也许无法检测出这种错误。
一个 using 声明一次只能作用于一个命名空间成员。using 声明可用来明确指定在程序中用到的命名空间中的名字,如果希望使用 std(或其他的命名空间)中的几个名字,则必须为要用到的每个名字都提供一个 using 声明。


有一种情况下,必须总是使用完全限定的标准库名字:在头文件中。理由是头文件的内容会被预处理器复制到程序中。用 #include 包含文件时,相当于头文件中的文本将成为我们编写的文件的一部分。如果在头文件中放置 using 声明,就相当于在包含该头文件 using 的每个程序中都放置了同一 using,不论该程序是否需要 using 声明。

通常,头文件中应该只定义确实必要的东西。请养成这个好习惯。
3.2. 标准库 string 类型
string 类型支持长度可变的字符串。
与其他的标准库类型一样,用户程序要使用 string 类型对象,必须包含相关头文件。如果提供了合适的 using 声明,那么编写出来的程序将会变得简短些:
#include <string>
using std::string;
3.2.1. string 对象的定义和初始化(p115)
string 标准库支持几个构造函数(第 2.3.3 节)。构造函数是一个特殊成员函数,定义如何初始化该类型的对象。表 3.1 列出了几个 string 类型常用的构造函数。当没有明确指定对象初始化式时,系统将使用默认构造函数(第2.3.4 节)。
几种初始化 string 对象的方式
string s1; 默认构造函数 s1 为空串
string s2(s1); 将 s2 初始化为 s1 的一个副本
string s3("value"); 将 s3 初始化为一个字符串字面值副本
string s4(n, 'c'); 将 s4 初始化为字符 'c' 的 n 个副本
警告:标准库 string 类型和字符串字面值(p116)
因为历史原因以及为了与 C 语言兼容, 字符串字面值标准库 string 类型不是同一种类型。这一点很容易引起混乱,编程时一定要注意区分字符串字面值和 string 数据类型的使用,这很重要。
string s;
cout << "please input a string:";
cin >> s;
cout <<"s is:" << s  <<endl;
从标准输入读取 string 并将读入的串存储在 s 中。string 类型的输入操作符:
• 读取并忽略开头所有的空白字符(如空格,换行符,制表符)。
• 读取字符直至再次遇到空白字符,读取终止。
如果给定和上一个程序同样的输入,则输出的结果是"Hello World!"(注意到开头和结尾的空格),则屏幕上将输出"Hello",而不含任何空格。

读入未知数目的 string 对象
下面的程序将从标准输入读取一组 string 对象,然后在标准
输出上逐行输出:
string s;
cout << "please input a string:";
        while (cin >> s)
cout <<"s is:" << s  <<endl;
如果输入:a b c
输出:
s is a
s is b
s is c
上例中,用输入操作符来读取 string 对象。该操作符返回所读的 istream 对象,并在读取结束后,作为 while 的判断条件。如果输入流是有效的,即还未到达文件尾且未遇到无效输入,则执行 while 循环体,并将读取到的字符串输出到标准输出。如果到达了文件尾,则跳出 while 循环。

使用 getline 读取整行文本(p118)

使用 getline 读取整行文本
另外还有一个有用的 string IO 操作: getline。这个函数接受两个参数:一个输入流对象和一个 string 对象。
getline(cin, line)
由于 line 不含换行符, 若要逐行输出需要自行添加。照常, 我们用 endl 来输出一个换行符并刷新输出缓冲区。
由于 getline 函数返回时丢弃换行符,换行符将不会存储在 string 对象中。

3.2.4. string 对象中字符的处理(p125)
我们经常要对 string 对象中的单个字符进行处理,例如,通常需要知道某个特殊字符是否为空白字符、字母或数字。表 3.3 列出了各种字符操作函数,适用于 string 对象的字符(或其他任何 char 值),这些函数都在 cctype 头文件中定义。

建议:采用 C 标准库头文件的 C++ 版本
C++ 标准库除了定义了一些选定于 C++ 的设施外,还包括 C 标准库。C++ 中的头文件 cctype 其实就是利用了 C 标准库函数, 这些库函数就定义在 C 标准库的 ctype.h 头文件中。
C 标准库头文件命名形式为 name 而 C++ 版本则命名为 cname ,少了后缀, .h 而在头文件名前加了 c 表示这个头文件源自 C 标准库。因此,cctype 与 ctype.h 文件的内容是一样的,只是采用了更适合 C++程序的形式。特别地, cname 头文件中定义的名字都定义在命名空间 std 内,而 .h 版本中的名字却不是这样。
通常,C++ 程序中应采用 cname 这种头文件的版本,而不采用 name.h 版本,这样,标准库中的名字在命名空间 std 中保持一致。
使用 .h 版本会给程序员带来负担,因为他们必须记得哪些标准库名字是从 C 继承来的,而哪些是 C++ 所特有的。

3.3. 标准库 vector 类型
vector 是同一种类型的对象的集合,每个对象都有一个对应的整数索引值。
和 string 对象一样, 标准库将负责管理与存储元素相关的内存。我们把 vector
称为容器,是因为它可以包含其他对象。一个容器中的所有对象都必须是同一种
类型的。我们将在第九章更详细地介绍容器。
使用 vector 之前,必须包含相应的头文件。本书给出的例子,都是假设已
作了相应的 using 声明:
#include <vector>
using std::vector;
vector 是一个类模板(class template) 。使用模板可以编写一个类定义或函数定义,而用于多个不同的数据类型。因此,我
们可以定义保存 string 对象的 vector,或保存 int 值的 vector,又或是保存自定义的类类型对象(如Sales_items 对象)
的 vector。将在第十六章介绍如何定义程序员自己的类模板。
声明从类模板产生的某种类型的对象,需要提供附加信息,信息的种类取决于模板。以 vector 为例,必须说明 vector 保存何
种对象的类型,通过将类型放在类型放在类模板名称后面的尖括号中来指定类型:
vector<int> ivec; // ivec holds objects of type int
vector<Sales_item> Sales_vec; // holds Sales_items
和其他变量定义一样,定义 vector 对象要指定类型和一个变量的列表。上面的第一个定义,类型是 vector<int>,该类型即是
含有若干 int 类型对象的vector,变量名为 ivec。第二个定义的变量名是 Sales_vec,它所保存的元素是 Sales_item 类型的对象。
vector 不是一种数据类型,而只是一个类模板,可用来定义任意多种数据类型。vector 类型的每一种都指定了其保存元素的
类型。因此,vector<int> 和 vector<string> 都是数据类型。
3.3.1. vector 对象的定义和初始化
vector 类定义了好几种构造函数(2.3.3 节),用来定义和初始化 vector对象。表 3.4 列出了这些构造函数。129
表 3.4. 初始化 vector
vector<T> v1; vector 保存类型为 T 对象。
默认构造函数 v1 为空。
vector<T> v2(v1); v2 是 v1 的一个副本。
vector<T> v3(n, i); v3 包含 n 个值为 i 的元素。
vector<T> v4(n); v4 含有值初始化的元素的 n 个副本
值初始化
如果没有指定元素的初始化式,那么标准库将自行提供一个元素初始值进行值初始化(value initializationd) 。这个由库生成的初始值将用来初始化容器中的每个元素,具体值为何,取决于存储在 vector 中元素的数据类型。
如果 vector 保存内置类型(如 int 类型)的元素,那么标准库将用 0 值创建元素初始化式:
如果 vector 保存的是含有构造函数的类类型(如 string)的元素,标准库将用该类型的默认构造函数创建元素初始化式:
第十二章将介绍一些有自定义构造函数但没有默认构造函数的类,在初始化这种类型的 vector 对象时,程序员就不能仅提供元素个数,还需要提供元素初始值。
还有第三种可能性:元素类型可能是没有定义任何构造函数的类类型。这种情况下,标准库仍产生一个带初始值的对象,这个对象的每个成员进行了值初始化。
3.3.2. vector 对象的操作
vector 标准库提供了许多类似于 string 对象的操作,表 3.5 列出了几种
最重要的 vector 操作。
表 3.5. vector 操作
v.empty() 如果 v 为空,则返回 true,否则返回 false。
v.size() 返回 v 中元素的个数。
v.empty() 如果 v 为空,则返回 true,否则返回 false。
v.push_back(t) 在 v 的末尾增加一个值为 t 的元素。
v[n] 返回 v 中位置为 n 的元素。
v1 = v2 把 v1 的元素替换为 v2 中元素的副本。
v1 == v2 如果 v1 与 v2 相等,则返回 true。
!=, <, <=,>, and >=保持这些操作符惯有的含义。
vector 对象的 size
empty 和 size 操作类似于 string 的相关操作(3.2.3 节)。成员函数
size 返回相应 vector 类定义的 size_type 的值。
使用 size_type 类型时,必须指出该类型是在哪里定义的。
vector 类型总是包括总是包括 vector 的元素类型:
vector<int>::size_type // ok
vector::size_type // error
vector 的下标操作
关键概念:安全的泛型编程
习惯于 C 或 Java 编程的 C++ 程序员可能会觉得难以理解,for 循环的判断条件用 != 而不是用 < 来测试 vector 下标值是否越界。C 程序员难以理解的还有, 上例中没有在 for 循环之前就调用 size 成员函数并保存其返回的值,而是在 for 语句头中调用 size 成员函数。
C++ 程序员习惯于优先选用 != 而不是 < 来编写循环判断条件。在上例中,选用或不用某种操作符并没有特别的取舍理由。学习完本书第二部分的泛型编程后,你将会明白这种习惯的合理性。
调用 size 成员函数而不保存它返回的值,在这个例子中同样不是必需的,但这反映了一种良好的编程习惯。在 C++ 中,有些数据结构(如vector)可以动态增长。上例中循环仅需要读取元素,而不需要增加新的元素。但是,循环可以容易地增加新元素,如果确实增加了新元素的话,那么测试已保存的 size 值作为循环的结束条件就会有问题,因为没有将新加入的元素计算在内。所以我们倾向于在每次循环中测试 size的当前值,而不是在进入循环前,存储 size 值的副本。
我们将在第七章学习到,C++ 中有些函数可以声明为内联(inline)函数。编译器遇到内联函数时就会直接扩展相应代码,而不是进行实际的函数调用。像 size 这样的小库函数几乎都定义为内联函数,所以每次循环过程中调用它的运行时代价是比较小的。
3.4. 迭代器简介
除了使用下标来访问 vector 对象的元素外,标准库还提供了另一种访问元素的方法:使用迭代器(iterator) 。迭代器是一种检查容器内元素并遍历元素的数据类型。
标准库为每一种标准容器(包括 vector)定义了一种迭代器类型。迭代器类型提供了比下标操作更通用化的方法: 所有的标准库容器都定义了相应的迭代器类型,而只有少数的容器支持下标操作。因为迭代器对所有的容器都适用,现代 C++ 程序更倾向于使用迭代器而不是下标操作访问容器元素,即使对支持下标操作的 vector 类型也是这样。

容器的 iterator 类型每种容器类型都定义了自己的迭代器类型,如 vector:

vector<int>::iterator iter;
术语:迭代器和迭代器类型
程序员首次遇到有关迭代器的术语时可能会困惑不解,原因之一是由于同一个术语 iterator 往往表示两个不同的事物。一般意义上指的是迭代器的概念;而具体而言时指的则是由容器定义的具体的 iterator 类型,如 vector<int>。
重点要理解的是,有许多用作迭代器的类型,这些类型在概念上是相关的。若一种类型支持一组确定的操作(这些操作可用来遍历容器内的元素,并访问这些元素的值),我们就称这种类型为迭代器。
各容器类都定义了自己的 iterator 类型,用于访问容器内的元素。换句话说,每个容器都定义了一个名为 iterator 的类型,而这种类型支持(概念上的)迭代器的各种操作。
begin 和 end 操作:每种容器都定义了一对命名为 begin 和 end 的函数,用于返回迭代器。如果容器中有元素的话,由 begin 返回的迭代器指向第一个元素:
vector<int>::iterator iter = ivec.begin();
上述语句把 iter 初始化为由名为 vector 操作返回的值。假设 vector 不空,初始化后,iter 即指该元素为 ivec[0]。
由 end 操作返回的迭代器指向 vector 的“末端元素的下一个”。 “超出末端迭代器”(off-the-end iterator) 。表明它指向了一个不存在的元素。
如果 vector 为空,begin 返回的迭代器与 end 返回的迭代器相同。
由 end 操作返回的迭代器并不指向 vector 中任何实际的元素,相反,它只是起一个哨兵(sentinel) 的作用,表示我们已处理完 vector 中所有元素。


vector 迭代器的自增和解引用运算
迭代器类型定义了一些操作来获取迭代器所指向的元素,并允许程序员将迭代器从一个元素移动到另一个元素。
迭代器类型可使用解引用操作符(dereference operator)(*)来访问迭代器所指向的元素:*iter = 0;
解引用操作符返回迭代器当前所指向的元素假设 iter 指向 vector 对象 ivec 的第一元素,那么 *iter 和 ivec[0] 就是指向同一个元素。上面这个语句的效果就是把这个元素的值赋为 0。
迭代器使用自增操作符(1.4.1 节)向前移动迭代器指向容器中下一个元素。
从逻辑上说,迭代器的自增操作和 int 型对象的自增操作类似。对 int 对象来说,操作结果就是把 int 型值“加 1”,而对迭代器对象则是把容器中的迭代器“向前移动一个位置”。因此,如果 iter 指向第一个元素,则 ++iter 指向第二个元素。
由于 end 操作返回的迭代器不指向任何元素,因此不能对它进行解引用或自增操作。

迭代器的其他操作
另一对可执行于迭代器的操作就是比较:用 == 或 != 操作符来比较两个迭代器,如果两个迭代器对象指向同一个元素,则它们相等,否则就不相等。


const_iterator
前面的程序用 vector::iterator 改变 vector 中的元素值。每种容器类型还定义了一种名为 const_iterator 的类型,该类型只能用于读取容器内元素,但不能改变其值。


3.4.1. 迭代器的算术操作(p142)
除了一次移动迭代器的一个元素的增量操作符外,vector 迭代器(其他标准库容器迭代器很少)也支持其他的算术操作。这些操作称为迭代器算术操作(iterator arithmetic)

3.5. 标准库 bitset

有些程序要处理二进制位的有序集,每个位可能包含 0(关)1(开)值。
位是用来保存一组项或条件的 yes/no 信息(有时也称标志)的简洁方法。标准库提供的 bitset 类简化了位集的处理。要使用 bitset 类就必须包含相关的头文件。在本书提供的例子中,假设都使用 std::bitset 的 using 声明:
#include <bitset>
using std::bitset;


-------------------------------------------------------------------------------------------------------

第四章 数组和指针


C++ 语言提供了两种类似于 vector 和迭代器类型的低级复合类型——数组和指针。与 vector 类型相似,数组也可以保存某种类型的一组对象;而它们的区别在于,数组的长度是固定的。数组一经创建,就不允许添加新的元素。指针则可以像迭代器一样用于遍历和检查数组中的元素。
现代 C++ 程序应尽量使用 vector 和迭代器类型,而避免使用低级的数组和指针。设计良好的程序只有在强调速度时才在类实现的内部使用数组和指针。

数组是 C++ 语言中类似于标准库 vector 类型的内置数据结构。与 vector类似,数组也是一种存储单一数据类型对象的容器,其中每个对象都没有单独的名字,而是通过它在数组中的位置对它进行访问。
vector 类型相比,数组的显著缺陷在于:数组的长度是固定的,而且程序员无法知道一个给定数组的长度。数组没有获取其容量大小的 size 操作,也不提供 push_back 操作在其中自动添加元素。如果需要更改数组的长度,程序员只能创建一个更大的新数组,然后把原数组的所有元素复制到新数组空间中去。
4.1. 数组
4.1.1. 数组的定义和初始化
字符数组既可以用一组由花括号括起来、逗号隔开的字符字面值进行初始
化,也可以用一个字符串字面值进行初始化。然而,要注意这两种初始化形式并
不完全相同,字符串字面值(第 2.2 节)包含一个额外的空字符(null)用于
结束字符串。当使用字符串字面值来初始化创建的新数组时,将在新数组中加入
空字符:
char ca1[] = {'C', '+', '+'}; // no null
char ca2[] = {'C', '+', '+', '\0'}; // explicit null
char ca3[] = "C++"; // null terminator added automatically


ca1 的维数是 3,而 ca2 和 ca3 的维数则是 4。使用一组字符字面值初始化字符数组时,一定要记得添加结束字符串的空字符。例如,下面的初始化将导致编译时的错误:
不允许数组直接复制和赋值
警告:数组的长度是固定的
与 vector 类型不同,数组不提供 push_back 或者其他的操作在数组中添加新元素,数组一经定义,就不允许再添加新元素。
如果必须在数组中添加新元素,程序员就必须自己管理内存:要求系统重新分配一个新的内存空间用于存放更大的数组,然后把原数组的所有元素复制到新分配的内存空间中。我们将会在第 4.3.1 节学习如何去实现。
4.1.2. 数组操作


4.2. 指针的引入(p163)
vector 的遍历可使用下标或迭代器实现,同理,也可用下标或指针来遍历数组。 指针是指向某种类型对象的复合数据类型,是用于数组的迭代器:指向数组中的一个元素。在指向数组元素的指针上使用解引用操作符 *(dereference operator)和自增操作符 ++(increment operator),与在迭代器上的用法类似。对指针进行解引用操作,可获得该指针所指对象的值。而当指针做自增操作时,则移动指针使其指向数组中的下一个元素。在使用指针编写程序之前,我们需进一步了解一下指针。
4.2.1. 什么是指针
指针的概念很简单: 指针用于 指向对象。与迭代器一样,指针提供对其所指对象的间接访问,只是指针结构更通用一些。与迭代器不同的是,指针用于指向单个对象,而 迭代器 只能用于访问容器内的元素
具体来说,指针保存的是另一个对象的地址:
string s("hello world");
string *sp = &s; // sp holds the address of s
第二条语句定义了一个指向 string 类型的指针 sp,并初始化 sp 使其指向 string 类型的对象 s。*sp 中的 * 操作符表明 sp 是一个指针变量,&s 中的 & 符号是取地址操作符,当此操作符用于一个对象上时,返回的是该对象的存储地址。取地址操作符只能用于左值(第 2.3.1 节),因为只有当变量用作左值时,才能取其地址。同样地,由于用于 vector 类型、string 类型或内置数组的下标操作和解引用操作生成左值, 因此可对这两种操作的结果做取地址操作,这样即可获取某一特定对象的存储地址。
左值_百度百科  https://baike.baidu.com/item/%E5%B7%A6%E5%80%BC/2327412?fr=aladdin
C/C++中的左值  http://www.caole.net/diary/lvalue.html
建议:尽量避免使用指针和数组
指针变量的定义
C++ 语言使用 * 符号把一个标识符声明为指针:double *dp; // dp can point to a double
理解指针声明语句时,请从右向左阅读。
string *pstring;
语句把 pstring 定义为一个指向 string 类型对象的指针变量。
另一种声明指针的风格
在定义指针变量时,可用空格将符号 * 与其后的标识符分隔开来。下面的
写法是合法的:
string* ps; // legal but can be misleading该语句把 ps 定义为一个指向 string 类型对象的指针。

指针可能的取值
一个有效的指针必然是以下三种状态之一:保存一个特定对象的地址;指向某个对象后面的另一对象;或者是 0 值。若指针保存 0 值,表明它不指向任何对象。未初始化的指针是无效的,直到给该指针赋值后,才可使用它。
对大多数的编译器来说,如果使用未初始化的指针,会将指针中存放的不确定值视为地址,然后操纵该内存地址中存放的位内容。使用未初始化的指针相当于操纵这个不确定地址中存储的基础数据。因此,在对未初始化的指针进行解引用时,通常会导致程序崩溃。
C++ 语言无法检测指针是否未被初始化,也无法区分有效地址和由指针分配到的存储空间中存放的二进制位形成的地址。建议程序员在使用之前初始化所有的变量,尤其是指针。
如果可能的话,除非所指向的对象已经存在,否则不要先定义指针,这样可避免定义一个未初始化的指针。
如果必须分开定义指针和其所指向的对象,则将指针初始化为 0。因为编译器可检测出 0 值的指针,程序可判断该指针并未指向一个对象。
指针初始化和赋值操作的约束
对指针进行初始化或赋值只能使用以下四种类型的值:
1. 0 值常量表达式(第 2.7 节), 例如, 在编译时可获得 0 值的整型 const对象或字面值常量 0。
2. 类型匹配的对象的地址。
3. 另一对象末的下一地址。
4. 同类型的另一个有效指针。
把 int 型变量赋给指针是非法的,尽管此 int 型变量的值可能为 0。但允许把数值 0 或在编译时可获得 0 值的 const 量赋给指针。
除了使用数值 0 或在编译时值为 0 的 const 量外,还可以使用 C++ 语言从 C 语言中继承下来的预处理器变量 NULL(第 2.9.2 节) , 该变量在 cstdlib头文件中定义,其值为 0。如果在代码中使用了这个预处理器变量,则编译时会自动被数值 0 替换。因此,把指针初始化为 NULL 等效于初始化为 0 值。正如其他的预处理器变量一样(第 2.9.2 节),不可以使用 NULL 这个标识符给自定义的变量命名。
预处理器变量不是在 std 命名空间中定义的,因此其名字应为NULL,而非 std::NULL。


除了将在第 4.2.5 节和第 15.3 节介绍的两种例外情况之外,指针只能初
始化或赋值为同类型的变量地址或另一指针:
double dval;
double *pd = &dval; // ok: initializer is address of a double
double *pd2 = pd; // ok: initializer is a pointer to double

指针用于间接访问对象,并基于指针的类型提供可执行的操作,例如,int 型指针只能把其指向的对象当作 int 型数据来处理,如果该指针确实指向了其他类型(如 double 类型)的对象,则在指针上执行的任何操作都有可能出错。
void* 指针:C++ 提供了一种特殊的指针类型 void*,它可以保存任何类型对象的地址。
void* 表明该指针与一地址值相关,但不清楚存储在此地址上的对象的类型。
void* 指针只支持几种有限的操作:与另一个指针进行比较;向函数传递void* 指针或从函数返回 void* 指针;给另一个 void* 指针赋值。不允许使用void* 指针操纵它所指向的对象。我们将在第 5.12.4 节讨论如何重新获取存储在 void* 指针中的地址。


4.2.3. 指针操作
指针提供间接操纵其所指对象的功能。与对迭代器进行解引用操作(第 3.4节)一样,对指针进行解引用可访问它所指的对象,* 操作符(解引用操作符)将获取指针所指的对象:
string s("hello world");
string *sp = &s; // sp holds the address of s
cout <<*sp; // prints hello world

















VS2015IDE中C++编程问题集:

1、VS2015 编译程序时“无法查找或打开PDB文件”解决方法:调试-选项-符号-Microsoft符号服务器打钩,然后确定,就OK了。

2、C++中创建一个控制台程序,运行提示:error C2976: “std::array”: 模板 参数太少。
追踪到int main(array<System::String ^> ^args)这个语句位置,这个语法不是c++的,是c++.net的,也就是微软的.net平台针对c++语言的一种语法。实际上很少人用,大部分都去用C#了。只是C++.net的一个main函数定义而已。

本来目的是创建一个Win32控制台应用程序,却在创建项目时选择了CLR程序(注:通用语言运行时),造成以上结果。




托管C++ - CSDN博客  http://blog.csdn.net/gao271003105/article/details/72875093
1、什么是托管C++?
  在回答这个问题,首先要搞清楚什么是"托管"(Managed)。托管是.NET的一个专门概念,它是融于通用语言运行时(CLR)中的一种新的编程理念,因此我们完全可以把"托管"视为".NET"。那么什么是"通用语言运行时"?通用语言运行时是.NET 框架应用程序的执行引挚。它提供了许多服务,其中包括:代码管理(装入和执行)、类型安全性验证、元数据(高级类型信息)访问、为管理对象管理内存、管理代码,COM对象和预生成的DLLs(非管理代码和数据)的交互操作性、对开发人员服务的支持等等。
  也就是说,使用托管C++意味着,我们的代码可以被CLR所管理,并能开发出具有最新特性如垃圾自动收集、程序间相互访问等的.NET框架应用程序。
  由托管概念所引发的C++应用程序包括托管代码、托管数据和托管类三个组成部分。



C/C++中*和&的用法 - CSDN博客  http://blog.csdn.net/caozixuan98724/article/details/73395598

C++中运算符 &和&&、|和|| 的区别 - CSDN博客  http://blog.csdn.net/violet_echo_0908/article/details/47395875
C++ 位运算 & | << >> ^ ~ % - CSDN博客  http://blog.csdn.net/fox64194167/article/details/20692645

C++ 中 * 和 *& 的区别 - kala111的博客 - CSDN博客  http://blog.csdn.net/kala111/article/details/52442752

C++类成员指针(指向类成员的指针) - prettyshuang - 博客园  https://www.cnblogs.com/prettyshuang/p/5427689.html


所谓野指针:指向一个已删除的对象或未申请访问受限内存区域的指针。
与空指针不同,野指针无法通过简单地判断是否为 NULL避免,而只能通过养成良好的编程习惯来尽力减少。对野指针进行操作很容易造成程序错误。
野指针的成因主要有两种: 
    (1)指针变量没有被初始化。任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的,它会乱指一气。所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。 
    (2)指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针。别看free和delete的名字恶狠狠的(尤其是delete),它们只是把指针所指的内存给释放掉,但并没有把指针本身干掉。通常会用语句if (p != NULL)进行防错处理。很遗憾,此时if语句起不到防错作用,因为即便p不是NULL指针,它也不指向合法的内存块。
例: 
char *p = (char *) malloc(100); 
strcpy(p, “hello”); 
free(p); // p 所指的内存被释放,但是p所指的地址仍然不变 
if(p != NULL) // 没有起到防错作用 
strcpy(p, “world”); // 出错

C程序中可怕的野指针  https://zhuanlan.zhihu.com/p/24764641

http://blog.csdn.net/soonfly/article/details/51131141

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【原书名】 C++ Primer (4th Edition) 【原出社】 Addison Wesley/Pearson 【作者】 (美)Stanley B.Lippman,Josée LaJoie,Barbara E.Moo 【译者】 李师贤 蒋爱军 梅晓勇 林瑛 【丛书名】 图灵计算机科学丛书 【出社】 人民邮电出社 【书号】 7-115-14554-7 【开本】 16开 【页码】 900 【出日期】 2006-3-1 【次】 4-1 【内容简介】 本书是久负盛名的C++经典教程,其内容是C++大师Stanley B. Lippman丰富的实践经验和C++标准委员会原负责人Josée Lajoie对C++标准深入理解的完美结合,已经帮助全球无数程序员学会了C++。本对前一进行了彻底的修订,内容经过了重新组织,更加入了C++ 先驱Barbara E. Moo在C++教学方面的真知灼见。既显著改善了可读性,又充分体现了C++语言的最新进展和当前的业界最佳实践。书中不但新增大量教学辅助内容,用于强调重要的知识点,提醒常见的错误,推荐优秀的编程实践,给出使用提示,还包含大量来自实战的示例和习题。对C++基本概念和技术全面而且权威的阐述,对现代C++编程风格的强调,使本书成为C++初学者的最佳指南;对于中高级程序员,本书也是不可或缺的参考书。本书的前言阐述了 第4和前一的不同之处。 【目录信息】 第1章 快速入门 1 1.1 编写简单的C++程序 2 1.2 初窥输入/输出 5 1.2.1 标准输入与输出对象 5 1.2.2 一个使用IO库的程序 5 1.3 关于注释 8 1.4 控制结构 10 1.4.1 while语句 10 1.4.2 for语句 12 1.4.3 if语句 14 1.4.4 读入未知数目的输入 15 1.5 类的简介 17 1.5.1 Sales_item类 17 1.5.2 初窥成员函数 19 1.6 C++程序 21 小结 22 术语 22 第一部分 基本语言 第2章 变量和基本类型 29 2.1 基本内置类型 30 2.1.1 整型 30 2.1.2 浮点型 32 2.2 字面值常量 34 2.3 变量 38 2.3.1 什么是变量 39 2.3.2 变量名 40 2.3.3 定义对象 42 2.3.4 变量初始化规则 44 2.3.5 声明和定义 45 2.3.6 名字的作用域 46 2.3.7 在变量使用处定义变量 48 2.4 const限定符 49 2.5 引用 50 2.6 typedef名字 53 2.7 枚举 53 2.8 类类型 54 2.9 编写自己的头文件 57 2.9.1 设计自己的头文件 58 2.9.2 预处理器的简单介绍 60 小结 62 术语 62 第3章 标准库类型 67 3.1 命名空间的using声明 68 3.2 标准库string类型 70 3.2.1 string对象的定义和初始化 70 3.2.2 String对象的读写 71 3.2.3 string对象的操作 72 3.2.4 string对象中字符的处理 76 3.3 标准库vector类型 78 3.3.1 vector对象的定义和初始化 79 3.3.2 vector对象的操作 81 3.4 迭代器简介 83 3.5 标准库bitset类型 88 3.5.1 bitset对象的定义和初始化 88 3.5.2 bitset对象上的操作 90 小结 92 术语 92 第4章 数组和指针 95 4.1 数组 96 4.1.1 数组的定义和初始化 96 4.1.2 数组操作 99 4.2 指针的引入 100 4.2.1 什么是指针 100 4.2.2 指针的定义和初始化 101 4.2.3 指针操作 104 4.2.4 使用指针访问数组元素 106 4.2.5 指针和const限定符 110 4.3 C风格字符串 113 4.3.1 创建动态数组 117 4.3.2 新旧代码的兼容 120 4.4 多维数组 122 小结 124 术语 125 第5章 表达式 127 5.1 算术操作符 129 5.2 关系操作符和逻辑操作符 131 5.3 位操作符 134 5.3.1 bitset对象或整型值的使用 135 5.3.2 将移位操作符用于IO 137 5.4 赋值操作符 137 5.4.1 赋值操作的右结合性 138 5.4.2 赋值操作具有低优先级 138 5.4.3 复合赋值操作符 139 5.5 自增和自减操作符 140 5.6 箭头操作符 142 5.7 条件操作符 143 5.8 sizeof操作符 144 5.9 逗号操作符 145 5.10 复合表达式的求值 145 5.10.1 优先级 145 5.10.2 结合性 146 5.10.3 求值顺序 148 5.11 new和delete表达式 150 5.12 类型转换 154 5.12.1 何时发生隐式类型转换 154 5.12.2 算术转换 155 5.12.3 其他隐式转换 156 5.12.4 显式转换 158 5.12.5 何时需要强制类型转换 158 5.12.6 命名的强制类型转换 158 5.12.7 旧式强制类型转换 160 小结 161 术语 162 第6章 语句 165 6.1 简单语句 166 6.2 声明语句 167 6.3 复合语句(块) 167 6.4 语句作用域 168 6.5 if语句 169 6.6 switch语句 172 6.6.1 使用switch 173 6.6.2 switch中的控制流 173 6.6.3 default标号 175 6.6.4 switch表达式与case标号 176 6.6.5 switch内部的变量定义 176 6.7 while语句 177 6.8 for循环语句 179 6.8.1 省略for语句头的某些部分 180 6.8.2 for语句头中的多个定义 181 6.9 do while语句 182 6.10 break语句 183 6.11 continue语句 184 6.12 goto语句 185 6.13 try块和异常处理 186 6.13.1 throw表达式 186 6.13.2 try块 187 6.13.3 标准异常 189 6.14 使用预处理器进行调试 190 小结 192 术语 192 第7章 函数 195 7.1 函数的定义 196 7.1.1 函数返回类型 197 7.1.2 函数形参表 198 7.2 参数传递 199 7.2.1 非引用形参 199 7.2.2 引用形参 201 7.2.3 vector和其他容器类型的形参 206 7.2.4 数组形参 206 7.2.5 传递给函数的数组的处理 209 7.2.6 main:处理命令行选项 210 7.2.7 含有可变形参的函数 211 7.3 return语句 211 7.3.1 没有返回值的函数 212 7.3.2 具有返回值的函数 212 7.3.3 递归 216 7.4 函数声明 217 7.5 局部对象 220 7.5.1 自动对象 220 7.5.2 静态局部对象 220 7.6 内联函数 221 7.7 类的成员函数 222 7.7.1 定义成员函数的函数体 223 7.7.2 在类外定义成员函数 225 7.7.3 编写Sales_item类的构造 函数 225 7.7.4 类代码文件的组织 227 7.8 重载函数 228 7.8.1 重载与作用域 230 7.8.2 函数匹配与实参转换 231 7.8.3 重载确定的三个步骤 232 7.8.4 实参类型转换 234 7.9 指向函数的指针 237 小结 239 术语 240 第8章 标准IO库 243 8.1 面向对象的标准库 244 8.2 条件状态 247 8.3 输出缓冲区的管理 249 8.4 文件的输入和输出 251 8.4.1 文件流对象的使用 251 8.4.2 文件模式 254 8.4.3 一个打开并检查输入文件的 程序 256 8.5 字符串流 257 小结 259 术语 259 第二部分 容器和算法 第9章 顺序容器 263 9.1 顺序容器的定义 264 9.1.1 容器元素的初始化 265 9.1.2 容器内元素的类型约束 267 9.2 迭代器和迭代器范围 268 9.2.1 迭代器范围 270 9.2.2 使迭代器失效的容器操作 271 9.3 顺序容器的操作 272 9.3.1 容器定义的类型别名 272 9.3.2 begin和end成员 273 9.3.3 在顺序容器中添加元素 273 9.3.4 关系操作符 277 9.3.5 容器大小的操作 278 9.3.6 访问元素 279 9.3.7 删除元素 280 9.3.8 赋值与swap 282 9.4 vector容器的自增长 284 9.5 容器的选用 287 9.6 再谈string类型 289 9.6.1 构造string对象的其他方法 290 9.6.2 修改string对象的其他方法 292 9.6.3 只适用于string类型的操作 293 9.6.4 string类型的查找操作 295 9.6.5 string对象的比较 298 9.7 容器适配器 300 9.7.1 栈适配器 301 9.7.2 队列和优先级队列 302 小结 303 术语 303 第10章 关联容器 305 10.1 引言:pair类型 306 10.2 关联容器 308 10.3 map类型 309 10.3.1 map对象的定义 309 10.3.2 map定义的类型 310 10.3.3 给map添加元素 311 10.3.4 使用下标访问map对象 311 10.3.5 map::insert的使用 313 10.3.6 查找并读取map中的元素 315 10.3.7 从map对象中删除元素 316 10.3.8 map对象的迭代遍历 316 10.3.9 “单词转换”map对象 317 10.4 set类型 319 10.4.1 set容器的定义和使用 319 10.4.2 创建“单词排除”集 321 10.5 multimap和multiset类型 322 10.5.1 元素的添加和删除 322 10.5.2 在multimap和multiset 中查找元素 323 10.6 容器的综合应用:文本查询程序 325 10.6.1 查询程序的设计 326 10.6.2 TextQuery类 327 10.6.3 TextQuery类的使用 328 10.6.4 编写成员函数 330 小结 332 术语 332 第11章 泛型算法 335 11.1 概述 336 11.2 初窥算法 339 11.2.1 只读算法 339 11.2.2 写容器元素的算法 341 11.2.3 对容器元素重新排序的算法 343 11.3 再谈迭代器 347 11.3.1 插入迭代器 348 11.3.2 iostream迭代器 349 11.3.3 反向迭代器 353 11.3.4 const迭代器 355 11.3.5 五种迭代器 356 11.4 泛型算法的结构 358 11.4.1 算法的形参模式 359 11.4.2 算法的命名规范 359 11.5 容器特有的算法 361 小结 362 术语 363 第三部分 类和数据抽象 第12章 类 367 12.1 类的定义和声明 368 12.1.1 类定义:扼要重述 368 12.1.2 数据抽象和封装 369 12.1.3 关于类定义的更多内容 372 12.1.4 类声明与类定义 374 12.1.5 类对象 375 12.2 隐含的this指针 376 12.3 类作用域 380 类作用域中的名字查找 382 12.4 构造函数 385 12.4.1 构造函数初始化式 387 12.4.2 默认实参与构造函数 391 12.4.3 默认构造函数 392 12.4.4 隐式类类型转换 393 12.4.5 类成员的显式初始化 396 12.5 友元 396 12.6 static类成员 398 12.6.1 static成员函数 400 12.6.2 static数据成员 400 小结 403 术语 403 第13章 复制控制 405 13.1 复制构造函数 406 13.1.1 合成的复制构造函数 409 13.1.2 定义自己的复制构造函数 409 13.1.3 禁止复制 410 13.2 赋值操作符 411 13.3 析构函数 412 13.4 消息处理示例 415 13.5 管理指针成员 419 13.5.1 定义智能指针类 421 13.5.2 定义值型类 425 小结 427 术语 427 第14章 重载操作符与转换 429 14.1 重载操作符的定义 430 14.2 输入和输出操作符 435 14.2.1 输出操作符<>的重载 437 14.3 算术操作符和关系操作符 439 14.3.1 相等操作符 440 14.3.2 关系操作符 441 14.4 赋值操作符 441 14.5 下标操作符 442 14.6 成员访问操作符 443 14.7 自增操作符和自减操作符 446 14.8 调用操作符和函数对象 449 14.8.1 将函数对象用于标准库算法 450 14.8.2 标准库定义的函数对象 451 14.8.3 函数对象的函数适配器 453 14.9 转换与类类型 454 14.9.1 转换为什么有用 454 14.9.2 转换操作符 455 14.9.3 实参匹配和转换 458 14.9.4 重载确定和类的实参 461 14.9.5 重载、转换和操作符 464 小结 466 术语 467 第四部分 面向对象编程与泛型编程 第15章 面向对象编程 471 15.1 面向对象编程:概述 472 15.2 定义基类和派生类 473 15.2.1 定义基类 474 15.2.2 protected成员 475 15.2.3 派生类 476 15.2.4 virtual与其他成员函数 479 15.2.5 公用、私有和受保护的继承 482 15.2.6 友元关系与继承 486 15.2.7 继承与静态成员 486 15.3 转换与继承 487 15.3.1 派生类到基类的转换 487 15.3.2 基类到派生类的转换 489 15.4 构造函数和复制控制 490 15.4.1 基类构造函数和复制控制 490 15.4.2 派生类构造函数 490 15.4.3 复制控制和继承 494 15.4.4 虚析构函数 495 15.4.5 构造函数和析构函数中的虚函数 497 15.5 继承情况下的类作用域 497 15.5.1 名字查找在编译时发生 498 15.5.2 名字冲突与继承 498 15.5.3 作用域与成员函数 499 15.5.4 虚函数与作用域 500 15.6 纯虚函数 502 15.7 容器与继承 503 15.8 句柄类与继承 504 15.8.1 指针型句柄 505 15.8.2 复制未知类型 507 15.8.3 句柄的使用 508 15.9 再谈文本查询示例 511 15.9.1 面向对象的解决方案 513 15.9.2 值型句柄 514 15.9.3 Query_base类 515 15.9.4 Query句柄类 516 15.9.5 派生类 518 15.9.6 eval函数 520 小结 522 术语 523 第16章 模板与泛型编程 525 16.1 模板定义 526 16.1.1 定义函数模板 526 16.1.2 定义类模板 528 16.1.3 模板形参 529 16.1.4 模板类型形参 531 16.1.5 非类型模板形参 533 16.1.6 编写泛型程序 534 16.2 实例化 535 16.2.1 模板实参推断 537 16.2.2 函数模板的显式实参 540 16.3 模板编译模型 542 16.4 类模板成员 545 16.4.1 类模板成员函数 548 16.4.2 非类型形参的模板实参 551 16.4.3 类模板中的友元声明 552 16.4.4 Queue和QueueItem的友元 声明 554 16.4.5 成员模板 556 16.4.6 完整的Queue类 558 16.4.7 类模板的static成员 559 16.5 一个泛型句柄类 560 16.5.1 定义句柄类 561 16.5.2 使用句柄 562 16.6 模板特化 564 16.6.1 函数模板的特化 565 16.6.2 类模板的特化 567 16.6.3 特化成员而不特化类 569 16.6.4 类模板的部分特化 570 16.7 重载与函数模板 570 小结 573 术语 574 第五部分 高级主题 第17章 用于大型程序的工具 579 17.1 异常处理 580 17.1.1 抛出类类型的异常 581 17.1.2 栈展开 582 17.1.3 捕获异常 583 17.1.4 重新抛出 585 17.1.5 捕获所有异常的处理代码 586 17.1.6 函数测试块与构造函数 586 17.1.7 异常类层次 587 17.1.8 自动资源释放 589 17.1.9 auto_ptr类 591 17.1.10 异常说明 595 17.1.11 函数指针的异常说明 598 17.2 命名空间 599 17.2.1 命名空间的定义 599 17.2.2 嵌套命名空间 603 17.2.3 未命名的命名空间 604 17.2.4 命名空间成员的使用 606 17.2.5 类、命名空间和作用域 609 17.2.6 重载与命名空间 612 17.2.7 命名空间与模板 614 17.3 多重继承与虚继承 614 17.3.1 多重继承 615 17.3.2 转换与多个基类 617 17.3.3 多重继承派生类的复制控制 619 17.3.4 多重继承下的类作用域 620 17.3.5 虚继承 622 17.3.6 虚基类的声明 624 17.3.7 特殊的初始化语义 625 小结 628 术语 628 第18章 特殊工具与技术 631 18.1 优化内存分配 632 18.1.1 C++中的内存分配 632 18.1.2 allocator类 633 18.1.3 operator new函数和 operator delete函数 636 18.1.4 定位new表达式 638 18.1.5 显式析构函数的调用 639 18.1.6 类特定的new和delete 639 18.1.7 一个内存分配器基类 641 18.2 运行时类型识别 646 18.2.1 dynamic_cast操作符 647 18.2.2 typeid操作符 649 18.2.3 RTTI的使用 650 18.2.4 type_info类 652 18.3 类成员的指针 653 18.3.1 声明成员指针 653 18.3.2 使用类成员的指针 655 18.4 嵌套类 658 18.4.1 嵌套类的实现 658 18.4.2 嵌套类作用域中的名字查找 661 18.5 联合:节省空间的类 662 18.6 局部类 665 18.7 固有的不可移植的特征 666 18.7.1 位域 666 18.7.2 volatile限定符 668 18.7.3 链接指示:extern "C" 669 小结 672 术语 673 附录 标准库 675 索引 703

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值