根据你在学习编程语言(特别是C++)的阶段,LearnCpp.com可能是你唯一用来学习C++或查找相关内容的资源。LearnCpp.com旨在以适合初学者的方式解释概念,但它无法涵盖语言的每一个方面。随着你开始探索超出这些教程所涵盖的主题,你不可避免地会遇到这些教程无法解答的问题。在这种情况下,你需要利用外部资源。
其中一个资源是Stack Overflow,你可以在那里提问(或者更好的是,阅读之前有人问过并已回答的相同问题)。但有时,更好的第一步是查阅参考手册。与倾向于关注最重要主题并使用非正式/常见语言以便于学习的教程不同,参考手册使用正式术语精确描述C++。正因为如此,参考材料往往是全面的、准确的……但也难以理解。
在本课中,我们将通过研究三个示例,展示如何使用cppreference,这是一个我们贯穿课程中经常引用的流行标准参考手册。
概览
Cppreference首先为你提供了一个关于核心语言和库的概览:
cppreference概览
从这里,你可以访问cppreference提供的所有内容,但使用搜索功能或搜索引擎会更方便。在完成LearnCpp.com上的教程后,概览是一个很好的去处,可以让你深入了解库,并看看语言还提供了哪些你可能不知道的功能。
表格的上半部分展示了当前语言中的特性,而下半部分则展示了技术规范,这些特性可能在未来版本中被添加到C++中,或者已经部分被接受到语言中。如果你想知道即将推出的新功能,这会很有用。
从C++11开始,cppreference在每个特性旁边都标注了它们被添加到语言标准的版本号。标准版本就是你在上面图片中某些链接旁边看到的小绿数字。没有版本号的特性自C++98/03以来就已可用。版本号不仅出现在概览中,而且在cppreference的每个地方都有,让你清楚地知道在特定的C++版本中你可以或不可以使用什么。
警告
如果你使用搜索引擎,而某个技术规范刚刚被标准接受,你可能会被链接到技术规范而不是官方参考,这两者可能有所不同。
提示
Cppreference是C++和C的参考手册。由于C++与C共享一些函数名,因此在搜索某些内容后,你可能会发现自己进入了C的参考部分。Cppreference的网址和顶部的导航栏始终会显示你正在浏览的是C还是C++的参考部分。
std::string::length
我们先来研究一个你在之前课程中已经熟悉的函数:std::string::length,它返回字符串的长度。
在cppreference的右上角搜索“string”。这样做会显示一个长长的类型和函数列表,目前只有顶部的内容是相关的。
字符串搜索
我们本可以直接搜索“string length”,但为了在本课程中展示尽可能多的内容,我们选择走长路。点击“Strings library”会带你进入一个关于C++支持的各种字符串类型的页面。
字符串库页面
如果我们查看“std::basic_string”部分,可以看到一个typedef列表,其中包含std::string。
点击“std::string”会带你进入std::basic_string的页面。没有专门的std::string页面,因为std::string是std::basic_string
typedef
<char>
表示字符串中的每个字符都是char类型。你会注意到C++还提供了其他使用不同字符类型的字符串。在使用Unicode而不是ASCII时,这些会很有用。
在同一个页面的下方,有一个成员函数列表(类型的行为)。如果你想了解某种类型可以做什么,这个列表非常方便。在这个列表中,你会找到一个关于length(和size)的条目。
点击链接会带你进入length和size的详细函数描述页面,这两个函数的作用相同。
每个页面的顶部都以该特性的简要概述、语法、重载或声明开始:
字符串长度重载
页面标题显示了类和函数的名称以及所有模板参数。我们可以忽略这部分内容。在标题下方,我们可以看到所有不同的函数重载(共享相同名称的不同版本的函数)以及它们适用于哪种语言标准。
在那之下,我们可以看到函数接受的参数以及返回值的含义。
由于std::string::length是一个简单的函数,所以这个页面的内容并不多。许多页面会展示它们所记录的特性的示例用法,这个页面也是如此:
字符串长度示例
当你还在学习C++时,示例中会有一些你尚未见过的特性。如果有足够的示例,你可能能够理解足够多的内容,从而大致了解函数的用法和作用。如果示例过于复杂,你可以在其他地方搜索示例,或者查阅你不理解的部分的参考内容(你可以点击示例中的函数和类型,查看它们的作用)。
现在我们知道了std::string::length的作用,但我们之前就知道了。让我们来看看一些新的内容!
std::cin.ignore
在第9.5课——std::cin和处理无效输入中,我们提到了std::cin.ignore,它用于忽略直到换行符的所有内容。这个函数的一个参数是一个冗长的值。那是什么来着?难道不能直接用一个大数字吗?这个参数到底有什么作用?让我们来搞清楚!
在cppreference搜索“std::cin.ignore”会得到以下结果:
搜索引擎结果
- std::cin, std::wcin — 我们想要的是.ignore,而不是普通的std::cin。
- std::basic_istream<CharT,Traits>::ignore — 哎呀,这是什么?我们先跳过这个。
- std::ignore — 不,这不是我们要找的。
- std::basic_istream — 这个也不是。
没有找到,那怎么办?我们去std::cin的页面,从那里开始查找。在那一页上没有明显的内容。在页面顶部,我们可以看到std::cin和std::wcin的声明,它告诉我们需要包含哪个头文件才能使用std::cin:
声明
我们可以看到,std::cin是一个std::istream类型的对象。我们点击链接进入std::istream的页面:
basic_istream
等一下!我们在搜索“std::cin.ignore”时之前见过std::basic_istream。原来istream是basic_istream的typedef名称,所以我们的搜索并没有完全错误。
在该页面向下滚动,我们会看到熟悉的函数:
成员函数
我们已经使用过其中许多函数:operator»、get、getline、ignore。在该页面上浏览一下,了解一下std::cin中还有哪些其他内容。然后点击ignore,因为这是我们感兴趣的。
ignore
在页面顶部有函数签名和对函数及其两个参数的描述。参数后面的“=”符号表示默认参数(我们在第11.5课——默认参数中会讲到)。如果我们没有为具有默认值的参数提供参数,就会使用默认值。
第一个要点回答了我们所有的问题。我们可以看到,std::numeric_limitsstd::streamsize::max()对std::cin.ignore有特殊含义,它会禁用字符计数检查。这意味着std::cin.ignore会一直忽略字符,直到找到分隔符,或者直到没有更多的字符可供查看。
很多时候,如果你已经知道某个函数的作用,但忘记了参数或返回值的含义,你不需要阅读整个函数描述。在这种情况下,阅读参数或返回值的描述就足够了。
参数和返回值
参数描述非常简洁。它没有包含std::numeric_limitsstd::streamsize::max()的特殊处理或其他停止条件,但作为一个提醒很有用。
语言语法示例
除了标准库之外,cppreference还记录了语言语法。这里有一个有效的程序:
#include <iostream>
int getUserInput()
{
int i{};
std::cin >> i;
return i;
}
int main()
{
std::cout << "How many bananas did you eat today? \n";
if (int iBananasEaten{ getUserInput() }; iBananasEaten <= 2)
{
std::cout << "Yummy\n";
}
else
{
std::cout << iBananasEaten << " is a lot!\n";
}
return 0;
}
为什么在if语句的条件中有一个变量定义?我们通过在最喜欢的搜索引擎中搜索“cppreference if statement”来使用cppreference找出它的作用。这样会带你进入if语句的页面。在页面顶部,有一个语法参考。
查看if语句的语法。如果你去掉所有的可选部分,你会得到一个你已经熟悉的if语句。在条件之前,有一个可选的初始化语句(init-statement),这看起来就像上面代码中发生的情况。
if (init-statement condition) statement-true
if (init-statement condition) statement-true else statement-false
在语法参考下方,是对语法的每个部分的解释,包括初始化语句。它提到初始化语句通常是一个带有初始化器的变量声明。
在语法之后是对if语句的解释和简单示例:
解释与示例
我们已经知道if语句是如何工作的,示例中没有包含初始化语句,所以我们向下滚动一点,找到一个专门讨论带有初始化器的if语句的部分:
带有初始化器的If语句
首先,展示了如何在不实际使用初始化语句的情况下编写初始化语句。现在我们知道上面的代码在做什么了。它是一个普通的变量声明,只是合并到了if语句中。
接下来的句子很