随笔分类 - 《C++ Primer 4th edition》概览与浅析
摘要:C++ 的标准库定义了 3 种顺序容器类型:vector、list 和 deque(是双端队列"double-ended queue"的简写,发音为"deck")它们的差别在于访问元素的方式,以及添加或删除元素相关操作的运行代价。标准库还提供了 3 种容器适配器(adaptors)。实际上,适配器是根据原始的容器类型所提供的操作,通过定义新的操作接口,来适应基础的容器类型。顺序容器适配器包括 stack、queue 和 priority_queue 类型,见下表——//顺序容器 vector 支持快速随机访问list 支持快速插入/删除deque 双端队
阅读全文
摘要:[1. 条件状态]在展开讨论 fstream 和 sstream 头文件中定义的类型之前,需要了解更多 IO 标准库如何管理其缓冲区及其流状态的相关内容。谨记本节和下一节所介绍的内容同样适用于普通流、文件流以及 string 流。所有 IO 对象都有一组条件状态,用来指示是否可以通过该对象进行 IO 操作。如果出现了错误(例如遇到文件结束符)对象的状态将标志无法再进行输入,直到修正了错误为止。标准库提供了一组函数设置和检查这些状态,用来标记给定的 IO 对象是否处于可用状态,或者碰到了哪种特定的错误。下表 列出了标准库定义的一组函数和标记,提供访问和操纵流状态的手段。strm::iostate
阅读全文
摘要:C++ 的输入/输出(input/output)由标准库提供。标准库定义了一些类型,支持对文件和控制窗口等设备的读写(IO)。另外一些类型,使 string 对象能够像文件一样操作,而无须 IO 就能实现数据与字符之间的转换。这些 IO 类型都定义了如何读写内置数据类型的值。此外,通常类的设计者还可以使用 IO 标准库设施读写自定义类的对象。类类型通常使用 IO 标准库为内置类型定义的操作符和规则来进行读写。getline 函数: 需要分别取 istream 类型和 string 类型的两个引用形参, 其功能是从 istream 对象读取一个单词,然后写入 string 对象中。为了同时支持或
阅读全文
摘要:函数指针是指指向函数而非指向对象的指针。像其他指针一样,函数指针也指向某个特定的类型。函数类型由其返回类型以及形参表确定,而与函数名无关: // pf points to function returning bool that takes two const string references bool (*pf)(const string &, const string &);pf 声明为指向函数的指针,它所指向的函数带有两个 const string& 类型的形参和 bool 类型的返回值。*pf 两侧的圆括号是必需的: // declares a functio
阅读全文
摘要:0. 定义与声明出现在相同作用域中的两个函数,如果具有相同的名字而形参列表不同,则称之为“重载函数”。(任何程序都仅有一个 main 函数的实例。main 函数不能重载。>_<||| 这一点就不用多解释什么了吧。。。)通过省去为函数起名并记住函数名字的麻烦,函数重载简化了程序的实现,使程序更容易理解。函数名只是为了帮助编译器判断调用的是哪个函数而已。例如,一个数据库应用可能需要提供多个 lookup 函数,分别实现基于姓名、电话号码或账号之类的查询功能。函数重载使我们可以定义一系列的函数,它们的名字都是 lookup,不同之处在于用于查询的值不相同。如此可传递几种类型中的任一种值调
阅读全文
摘要:0. 类的成员函数函数原型定义了所有和函数相关的类型信息: 函数返回类型是什么、函数的名字、应该给这个函数传递什么类型的实参。类的成员函数,其原型必须在类中定义。但是,函数体则既可以在类中也可以在类外定义。以下是一个 Sales_item 类的定义。 1 class Sales_item { 2 // operations on Sales_item objects 3 public: 4 double avg_price() const; 5 bool same_isbn(const Sales_item &rhs) const 6 ...
阅读全文
摘要:一、引用形参考虑下面不适宜复制实参的例子,该函数希望交换两个实参的值:1 // incorrect version of swap: The arguments are not changed!2 void swap(int v1, int v2)3 {4 int tmp = v2;5 v2 = v1; // assigns new value to local copy of the argument6 v1 = tmp;7 } // local objects ...
阅读全文
摘要:throw, try, catch C++ 的异常处理中包括:throw 表达式,错误检测部分使用这种表达式来说明遇到了不可处理的错误。可以说,throw 引发了异常条件。try 块,错误处理部分使用它来处理异常。try 语句块以 try 关键字开始,并以一个或多个 catch 子句结束。在 try 块中执行的代码所抛出(throw)的异常,通常会被其中一个 catch 子句处理。由于它们“处理”异常,catch 子句也称为处理代码。由标准库定义的一组异常类,用来在 throw 和相应的 catch 之间传递有关的错误信息。系统通过 throw 表达式抛出异常。throw 表达式由关键字 th
阅读全文
摘要:标准 C++ 为了加强类型转换的可视性,引入命名的强制转换操作符,为程序员在必须使用强制转换时提供了更好的工具。命名的强制类型转换符号的一般形式如下: cast-name<type>(expression);其中 cast-name 为 static_cast、dynamic_cast、const_cast 和 reinterpret_cast 之一,type 为转换的目标类型,而 expression 则是被强制转换的值。强制转换的类型指定了在 expression 上执行某种特定类型的转换。dynamic_cast: 支持运行时识别指针或引用所指向的对象。const_cast:
阅读全文
摘要:毫无疑问,自增( ++ )和自减( -- )操作符为对象加1或减1操作提供了方便简短的实现方式。(编程中的宗旨“简洁即美”!)它们有前置和后置两种使用形式: int i = 0, j; j = ++i; // j = 1, i = 1: prefix yields incremented value j = i++; // j = 1, i = 2: postfix yields unincremented value因为前置操作返回加1后的值,所以返回对象本身,是左值。而后置操作返回的则是右值。( 巧记:“前前后后”—— 前置操作返回修改前的值,后置操作返回修改后的值 )。建议:优先使...
阅读全文
摘要:一、使用数组初始化 vector 对象不能用一个数组直接初始化另一数组,程序员只能创建新数组,然后显式地把源数组的元素逐个复制给新数组。这反映 C++ 允许使用数组初始化 vector 对象,尽管这种初始化形式起初看起来有点陌生。使用数组初始化 vector 对象,必须指出用于初始化式的第一个元素以及数组最后一个元素的下一位置的地址:1 const size_t arr_size = 6;2 int int_arr[arr_size] = {0, 1, 2, 3, 4, 5};3 // ivec has 6 elements: each a copy of the co...
阅读全文
摘要:许多 C++ 程序在有标准类之前就已经存在了,因此既没有使用标准库类型 string 也没有使用 vector。而且,许多 C++ 程序为了兼容现存的 C 程序,也不能使用 C++ 标准库。因此,现代的 C++ 程序经常必须兼容使用数组和/或 C 风格字符串的代码,标准库提供了兼容处理。毫无疑问,当然可以用字符串字面值来初始化 string 类对象: string st3("Hello World"); // st3 holds Hello World通常,由于 C 风格字符串与字符串字面值具有相同的数据类型,而且都是以空字符 null 结束,因此可以把 C 风格字符串用在
阅读全文
摘要:引言数组类型的变量有三个重要的限制: 1)数组长度固定不变; 2)在编译时必须知道其长度; 3)数组只在定义它的块语句内存在。实际的程序往往不能忍受这样的限制——它们需要在运行时动态地分配数组。虽然数组长度是固定的,但动态分配的数组不必在编译时知道其长度,可以(通常也是)在运行时才确定数组长度。与数组变量不同,动态分配的数组将一直存在,直到程序显式释放它为止。每一个程序在执行时都占用一块可用的内存空间,用于存放动态分配的对象,此内存空间称为程序的自由存储区(free store)或堆(heap)。C 语言程序使用一对标准库函数 malloc 和 free 在自由存储区中分配存储空间,而 C++
阅读全文
摘要:总述使用引用(reference)和指针(pointer)都可间接访问另一个值,但它们之间存在两个重要区别:(1)引用总是指向某个确定对象(事实上,引用就是该对象的别名、外号),定义引用时没有进行初始化会出现编译错误;(2)赋值行为上存在差异: 给引用赋值修改的是该引用所关联癿对象的值,而不是使该引用与另一个对象关联。引用一经初始化,就始终指向同一个特定对象(这就是为什么引用必须在定义时初始化的原因)。 给指针赋值修改的是指针对象本身,也就是使该指针指向另一对象,指针在不同时刻可指向不同的对象(叧要保证类型匹配)。简单的举两个程序段作为例子。第一个程序段将一个指针赋给另一指针: 1 #in..
阅读全文
摘要:一、概念引入:除了使用下标来访问容器对象的元素外,标准库还提供了另一种访问元素的方法:使用迭代器(Iterators)。迭代器是一种检查容器内元素并遍历元素的数据类型。所有的标准库容器都定义了相应的迭代器类型,而只有少数的容器支持下标操作。因为迭代器对所有的容器都适用,现代C++程序更倾向于使用迭代器而不是下标操作访问容器元素,即使对支持下标操作的vector类型也是这样。(即:尽量使用迭代器访问容器元素。)二、困惑——迭代器和迭代器类型最开始的时候容易搞不清楚,原因之一是由于同一个术语iterator往往表示两个不同的事物。一般意义上指的是迭代器的概念;而具体而言时指的则是由容器定义的具体的
阅读全文
摘要:一、定义的概述 1. 变量的定义用于为变量分配存储空间,还可以为变量指定初始值。 (在一个程序中,变量有且仅有一个定义。) 2. 声明用于向程序表明变量的类型和名字。(程序中变量可以声明多次。) 3. 定义也是声明 —— 当定义变量的同时,我们也就声明了它的类型和名字。二、extern关键字 1. extern 声明变量而不定义它,也不分配存储空间。(事实上,它只是说明变量定义在程序的其他地方。) 2. 不定义变量的声明包括对象名、对象类型和对象类型前的关键字extern: extern int i; // declares but does not define i ...
阅读全文
摘要:首先看这个就跟没定义一样的定义:像 42 这样的值,在程序中被当作“字面值常量”。>_<|||.... 1. 称之为字面值是因为只能用它的值称呼它,称之为常量是因为它的值不能修改。 2. 每个字面值都有相应的类型,例如:0 是 int 型,3.14159 是 double 型。 (注意:只有内置类型存在字面值,没有类类型的字面值。因此,也没有任何标准库类型的字面值。)一、整型字面值规则 -- Rules for Integer Literals定义字面值整数常量可以使用十进制、八进制和十六进制中的任一种形式来表示,例如,我们能将值 20 定义 20 // decimal 我们通..
阅读全文
摘要:1 #include <iostream>2 int main()3 {4 int sum = 0, value;5 while (std::cin >> value)6 sum += value; // equivalent to sum = sum + value7 std::cout << "Sum is: " << sum << std::endl;8 return 0;9 }while的条件,std::cin >> value ,它具有从标准输入读取下一个数并且将读入的值保存在 value 中
阅读全文