-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathsearch.xml
63 lines (63 loc) · 64.6 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title><![CDATA[public和private访问修饰符]]></title>
<url>%2Fcpp%2F9783892c%2F</url>
<content type="text"><![CDATA[公有私有成员查看如下结构体: 12345678910111213141516struct DateStruct // 结构体成员默认是公有的(public){ int month; // 默认公有, 可被任何人访问 int day; // 默认公有, 可被任何人访问 int year; // 默认公有, 可被任何人访问};int main(){ DateStruct date; date.month = 10; date.day = 14; date.year= 2020; return 0;} 在这段程序里,我们声明了一个DateStruct并直接访问它的成员来进行初始化。之所有可以这样是因为一个结构体的成员默认是公有的。公有成员是指结构体或者类中可以被外部访问的成员。因此,main函数位于DateStruct外,但我们仍可以直接访问它的成员年、月、日,因为它们是公有的。 另一方面,我们瞧一瞧下面这个类,它和DateStruct几乎相同。 12345678910111213141516class DateClass // 类成员默认是私有的{ int m_month; // 默认私有, 只能被其他成员访问 int m_day; // 默认私有, 只能被其他成员访问 int m_year; // 默认私有, 只能被其他成员访问};int main(){ DateClass date; date.m_month = 10; // 出错 date.m_day = 14; // 出错 date.m_year = 2020; // 出错 return 0;} 如果你编译这段程序,会报错。这是因为默认情况下,一个类的所有成员都是私有的。私有成员是指结构体或者类中只能被该结构体或类的内部成员访问的成员。因为main函数不是DateClass的内部成员,所以它不能够访问DateClass的内部成员。 访问修饰符尽管类的成员默认是私有的,但我们可以通过public关键字让它变成公有的。 1234567891011121314151617class DateClass{public: // note use of public keyword here, and the colon int m_month; // public, can be accessed by anyone int m_day; // public, can be accessed by anyone int m_year; // public, can be accessed by anyone};int main(){ DateClass date; date.m_month = 10; // okay because m_month is public date.m_day = 14; // okay because m_day is public date.m_year = 2020; // okay because m_year is public return 0;} 因为DateClass的成员现在是公有的,所以我们可以直接在main函数里访问了。 public关键字及随后的冒号就是一个访问修饰符。访问修饰符决定了谁可以访问修饰符后边的成员。每一个成员都会活得前面所指定的访问修饰符的访问级别(如果没指定的话,就是用默认访问修饰符)。 C++提供三种不同的访问修饰符关键字:public,private,和protected。public让被修饰的成员变得公有,private让被修饰的成员变得私有。第三个修饰符,即protected,功能跟private类似。在我们之后的章节开始学习继承的时候,我们会讨论一下private和protected修饰符到底有什么区别。 混合访问修饰符类通常使用多种访问修饰符来设置其内部成员的访问级别。在类中使用访问修饰符并没有数量上的限制。 通常情况下,成员变量一般设置为私有,成员函数则设置为公有。我们会在下一节告诉你为什么。 规则:除非你有什么特殊的理由,不然就让成员变量私有,让成员方法公有。 观察下面的例子,它是一个同时使用了private和public访问修饰符的类。 12345678910111213141516171819202122232425262728293031#include <iostream>class DateClass // members are private by default{ int m_month; // private by default, can only be accessed by other members int m_day; // private by default, can only be accessed by other members int m_year; // private by default, can only be accessed by other memberspublic: void setDate(int month, int day, int year) // public, can be accessed by anyone { // setDate() can access the private members of the class because it is a member of the class itself m_month = month; m_day = day; m_year = year; } void print() // public, can be accessed by anyone { std::cout << m_month << "/" << m_day << "/" << m_year; }};int main(){ DateClass date; date.setDate(10, 14, 2020); // okay, because setDate() is public date.print(); // okay, because print() is public return 0;} 这段程序输出: 10/14/2020 尽管我们不能在main函数里访问m_month、m_day、m_year(因为它们是私有的),但我们可以通过它的公有成员函数setDate()和print()对这些私有变量进行间接访问。 一个类的公有成员通常又被成为公共接口(public interface)。因为只有公公成员可以在类的外部被访问,公共接口定义了使用这个类的程序如何与这个类进行交互。注意上面的main函数,被严格限制只能设置日期和输出日期,DateClass保护它的成员变量不会被直接访问和编辑。 有些程序员喜欢把私有成员写在前面,因为公有成员一般都会使用私有成员,所以理所当然地把私有成员写在前面。然而,类的使用者并不关心私有成员,所以公有成员应该写在前面。无论哪种方式,都是可取的。 访问控制按类进行观察下面的程序: 123456789101112131415161718192021222324252627282930313233343536373839404142#include <iostream>class DateClass // members are private by default{ int m_month; // private by default, can only be accessed by other members int m_day; // private by default, can only be accessed by other members int m_year; // private by default, can only be accessed by other memberspublic: void setDate(int month, int day, int year) { m_month = month; m_day = day; m_year = year; } void print() { std::cout << m_month << "/" << m_day << "/" << m_year; } // 看这里看这里 void copyFrom(const DateClass &d) { // 注意我们可以直接访问参数d的私有成员 m_month = d.m_month; m_day = d.m_day; m_year = d.m_year; }};int main(){ DateClass date; date.setDate(10, 14, 2020); // okay, because setDate() is public DateClass copy; copy.copyFrom(date); // okay, because copyFrom() is public copy.print(); return 0;} C++一个容易被忽视且误解的特性就是,访问控制作用于每个类,而不是每个对象(One nuance of C++ that is often missed or misunderstood is that access control works on a per-class basis, not a per-object basis.)。如果一个函数可以访问一个类的私有成员,那么这个函数就可以访问该类类型的任何对象的私有成员。 在上面的例子,copyFrom()是DateClass的一个成员,对DateClass的私有成员拥有访问权限。这意味着,copyFrom()不仅可以访问自身实例的私有成员,还可以访问参数d的私有成员!如果参数d是其他类型,那就另当别论了。 在需要从一个类的对象复制数据到同一个类的另外一个对象时,这个特性会变得非常有用。就在下一章讨论重载操作符<<来打印一个类的成员时,这个知识点我们会再次遇到。 结构体vs类复习现在我们已经学习了访问修饰符,我们也讨论了c++当中一个类和结构体的不同之处。一个类默认它的成员都是私有的,一个结构体默认它的成员都是公有的。 那就完了! (可是,我还想再啰嗦一下,这里还有一个细微的不同之处–结构体会公有地继承其他类,类则会私有地继承其他类。我们会在之后的章节解释它的意思,然而这一点实际上是无关紧要的,因为一般人不会使用默认继承。)]]></content>
</entry>
<entry>
<title><![CDATA[欢迎来到面向对象编程]]></title>
<url>%2Fcpp%2F1ef7169f%2F</url>
<content type="text"><![CDATA[欢迎来到面向对象编程在1.3章节-介绍变量中,我们知道了C++中的一个对象就是:“一块可以用来存储值的内存区域”,一个有名字的对象被称为变量。 在传统的编程中(我们在此之前一直在做的),程序基本上是计算机的指令列表,它们通过对象定义了数据,然后通过语句和函数使用该数据。数据和处理这个数据的函数是单独的实体,它们组合在一起以产生所需的结果。由于这种分离,导致传统编程在表达上不够直观。程序员可以通过适当的方式管理属性(变量)并将其连接到行为(函数)。用代码表示看起来像这样: 1driveTo(you, work); 那么什么是面向对象编程?我们来打个比喻吧。看看你周围,你所看到的一切都是一个个对象:书、建筑物、食物,甚至你自己。对象有两个主要组成部分:1)相关的属性列表(例如,重量、颜色、大小、坚固性、形状等);2)一些行为(例如,门可以打开、火能让其他东西变热等)。这些属性和行为是不可分割的。 面向对象编程(OOP)为我们提供了创建对象的能力,这些对象将属性和行为绑定到一个独立的、可重用的包中。用代码表示看起来更像这样: 1you.driveTo(work); //你(是个对象)开车去上班(是个行为) 这不仅读得更清楚,而且使对象(你)和被调用的行为(开车到某个地方)更清晰明了。我们关注的不是编写函数,而是定义这些具备各种行为的对象。这就是为什么这种范式被称为“面向对象”。 以这种更模块化的方式编写代码,会让程序更容易编写和理解,并且提供了更高程度的代码重用性。我们可以定义如何与这些对象交互以及它们如何与其他对象交互,从而以更直观的方式来处理我们的数据。 注意,OOP不能取代传统的编程方法。相反,它在编程工具带中为您提供了额外的工具,以便在需要时管理复杂性。 面向对象编程还带来了其他几个有用的概念:继承、封装、抽象和多态性。在接下来的几章中,我们将介绍所有这些概念。这些概念看起来挺多,但是一旦你已经熟悉了OOP,你可能再也不想回到传统的编程方式了。 注意,“对象”这个词可以表达的事情太多了,容易造成混淆。在传统编程中,对象是存储值的一块内存,仅此而已。在面向对象编程中,“对象”意味着它既是传统编程意义上的对象,同时又是属性和行为的结合。所以从现在开始,当我们使用术语“对象”时,我们指的是面向对象编程里的“对象”。]]></content>
</entry>
<entry>
<title><![CDATA[内联函数]]></title>
<url>%2Fcpp%2Ff10c6aa3%2F</url>
<content type="text"><![CDATA[内联函数函数的使用提供了许多好处,包括: 函数内部的代码可以重用。 更改或更新函数中的代码(只需改一次)要比在多处更改重复的代码容易。重复代码是导致效率低下和程序错误的一个因素之一。 它使您的代码更易于阅读和理解,因为您不需要查看它的实现来理解它的作用(前提是有合理的命名和注释)。 函数提供类型检查以确保函数调用参数与函数参数匹配(类似函数的宏[function-like macros]不执行此操作,这可能导致错误)。 函数使您的程序更容易调试。 但是,函数的一个主要缺点是每次调用函数时,都会产生一定的性能开销。这是因为CPU必须存储它正在执行的当前指令的地址(这样它才知道之后该从哪里返回)以及其他寄存器,所有函数参数必须被创建并赋值,并且程序必须跳转到新的位置执行。因此就地(in-place)编写的代码要快得多。 对于执行复杂任务的函数,与函数运行所花费的时间相比,函数调用的开销通常是微不足道的。但是,对于常用的短函数(不超过几行),进行函数调用所需的时间通常比实际执行函数代码所需的时间多得多。这可能导致严重的性能损失。 C++提供了一种将函数的优点与就地编写的代码速度相结合的方法:内联函数(inline function)。inline 关键字用于请求编译器把你的函数作为内联函数。当编译器编译你的代码时,所有内联函数都会就地展开 – 也就是说,函数调用被替换为函数本身内容的副本,这会删除函数调用开销!缺点是因为内联函数在每次函数调用时就地扩展,这可能会使编译的代码变得更大,特别是如果内联函数很长或对内联函数有很多调用。 比如下面的代码段: 1234567891011int min(int x, int y){ return x > y ? y : x;}int main(){ std::cout << min(5, 6) << '\n'; std::cout << min(3, 2) << '\n'; return 0;} 该程序调用了min()函数两次,产生了两次函数调用的开销。然而min()函数是一个很短的函数,把它作为内联函数是最好的选择。 1234inline int min(int x, int y){ return x > y ? y : x;} 现在,当程序编译main()时,两次min()函数调用被就地展开,就好像main()已经像这样编写: 123456int main(){ std::cout << (5 > 6 ? 6 : 5) << '\n'; std::cout << (3 > 2 ? 2 : 3) << '\n'; return 0;} 这将使程序执行得更快,代价是编译代码略大。 由于代码膨胀的可能性,一般把那些经常在循环内部被调用且内部没有分支跳转的短函数(不超过几行)作为内联函数。另外请注意,inline关键字只是一个建议,用于告知编译器你希望每遇到此函数的调用时,都将该函数内容就地展开 – 但如果你试图内联一个冗长的函数,编译器很可能会忽略你的请求。 如今的编译器现在非常擅长自动内联函数 – 在大多数情况下比人类做得更好。即使您没有将函数标记为内联,编译器也会自动内联它认为可以提升性能的函数。因此,在大多数情况下,没有特意使用inline关键字的必要。让编译器为您处理内联函数。 规则:了解有inline函数这么一个东西,但现代编译器会适当地为您自动内联,所以没必要使用inline关键字。 内联函数是“每个程序只能有一个定义”的例外。 在前面的章节中,我们已经注意到您不应该在头文件中实现函数(带有外部链接),因为当这些头文件包含在多个.cpp文件中时,函数定义将被复制到多个.cpp文件中。然后将编译这些文件,并且链接器将抛出错误,因为它会注意到您已经多次定义了相同的函数。 但是,内联函数不受“每个程序只能有一个定义”的规则的限制,因为内联函数实际上并不会被当成一个函数来编译 - 因此,当链接器链接到多个文件在一起时不会产生冲突。 这一点在现在看起来是无聊琐碎,但下一章我们会介绍一种新的函数(成员函数),它充分利用了这一点。 即便是使用内联函数,你也不应该在头文件中定义全局函数。]]></content>
</entry>
<entry>
<title><![CDATA[注释]]></title>
<url>%2Fcpp%2F71fb958f%2F</url>
<content type="text"><![CDATA[注释注释是直接插入到程序源代码中的程序员可读笔记,注释会被编辑器忽略,且仅供程序使用。 在C++中,有两种不同的注释样式,它们都有相同的用途:帮助程序员以某种方式记录代码。 单行注释一个C++单行注释以//符号开头,它告诉编译器忽略从//符号到行尾的所有内容。例如: 1std::cout << "Hello world!"; // 从这里开始到行尾的内容都被忽略 通常,单行注释用于快速注释单行代码。 123std::cout << "Hello world!\n"; // std::cout 位于 iostream 库std::cout << "It is very nice to meet you!\n"; // 这些注释让代码可读性变差std::cout << "Yeah!\n"; // 尤其是每一行代码的长度不同 对行的右侧进行注释可能会使代码和注释难以阅读,尤其是在内容比较长的情况下。如果行很短,则可以简单地对齐注释(通过制表符),如下所示: 123std::cout << "Hello world!\n"; // std::cout lives in the iostream librarystd::cout << "It is very nice to meet you!\n"; // this is much easier to readstd::cout << "Yeah!\n"; // don't you think so? 但是,如果行内容较长,则向右侧放置注释可能会使内容更长。在这种情况下,单行注释通常放在它要注释的那一行的上方: 12345678// std::cout lives in the iostream librarystd::cout << "Hello world!\n";// this is much easier to readstd::cout << "It is very nice to meet you!\n";// don't you think so?std::cout << "Yeah!\n"; 作者的说明 上面的陈述代表了我们第一次遇到代码片段。因为片段不是完整的程序,所以它们不能自己编译。相反,它们的存在是为了以简洁的方式展示特定的概念。 如果您想编译代码片段,则需要将其转换为完整程序才能进行编译。通常,该程序看起来像这样: 1234567#include <iostream>int main(){ // Replace this line with the snippet of code you'd like to compile return 0;} 多行注释一对/和/符号表示一个C语言风格的多行注释,所有在这两个符号之间的内容都会被忽略。 123/* 这是一个多行注释。 这一行会被忽略 这一行也是。 */ 正因为符号之间的所有内容都会被忽略,你有时候会看到程序员对多行注释进行了一定的“美化”: 1234/* 这是一个多行注释。 * 左对齐的星号 * 可以让注释更易读。 */ 多行注释不能嵌套。否则会出现不可预知的结果: 12/* 这是一个多行 /* 注释 */ 这并没有在注释内 */// 上面的注释在第一个 */ 处已经结束, 而不是第二个 */]]></content>
</entry>
<entry>
<title><![CDATA[介绍编译器,连接器和库]]></title>
<url>%2Fcpp%2F9b6d5a68%2F</url>
<content type="text"><![CDATA[介绍编译器,连接器和库继续我们从上一课0.4C++开发简介中对该图的讨论: 我们来讨论步骤4-7。 第4步:编译源代码为了编译C++程序,我们使用C++编译器。C++编译器按顺序遍历程序中的每个源代码(.cpp)文件,并执行两项重要任务: 首先,它检查您的代码以确保它遵循C++语言的规则。如果没有,编译器会给你一个错误(和相应的行号),以帮助确定需要修复的内容。编译过程也将中止,直到错误得到修复。 其次,它将您的C++源代码转换为称为目标文件的机器语言文件。目标文件通常名为name.o或name.obj,其中name与生成它的.cpp文件的名称相同。 如果您的程序有3个.cpp文件,编译器将生成3个目标文件: C++编译器可用于许多不同的操作系统。我们将讨论很快安装编译器,因此现在不需要这样做。 第5步:链接目标文件和库在编译器创建一个或多个目标文件之后,另一个称为链接器的程序 启动。链接器的工作有三个: 首先,获取编译器生成的所有目标文件,并将它们组合成一个可执行程序。 其次,除了能够链接目标文件之外,链接器还能够链接库文件。一个库文件是预编译代码的集合,它已经“打包”在其他程序中重用。 C++核心语言实际上相当小而简洁(您将在这些教程中学到很多东西)。但是,C++还附带了一个名为C++标准库(通常缩写为标准库)的扩展库,它提供了可在程序中使用的其他功能。C++标准库中最常用的部分之一是iostream库,包含在显示器上打印文本和从用户获取键盘输入的功能。几乎所有编写的C++程序都以某种形式使用标准库,因此将标准库链接到程序中非常常见。一旦你使用它的任何部分,大多数链接器将自动链接到标准库中,所以这通常不是你需要担心的事情。 您也可以选择在其他库中链接。例如,如果您要编写一个播放声音的程序,您可能不希望编写自己的代码来读取磁盘中的声音文件,检查以确保它们有效,或者弄清楚如何路由声音数据通过扬声器播放操作系统或硬件 - 这将是很多工作!相反,你可能会下载一个已经知道如何做这些事情的库,并使用它。我们将在附录中讨论如何在库中链接(并创建自己的!)。 第三,链接器确保正确解析所有跨文件依赖关系。例如,如果您在一个.cpp文件中定义某个内容,然后在另一个.cpp文件中使用它,则链接器会将两者连接在一起。如果链接器无法使用该事物的定义连接对事物的引用,则会出现链接器错误,并且链接过程将中止。 一旦链接器完成链接所有目标文件和库(假设一切顺利),您将拥有一个可执行文件,然后您可以运行! 对于高级读者 对于复杂项目,某些开发环境使用makefile,该文件描述了如何构建程序(例如,要编译和链接的文件,或以其他方式处理)。已经写了关于如何编写和维护makefile的全书,它们可以成为一个非常强大的工具。但是,因为makefile不是C++核心语言的一部分,也不需要使用它们来继续,所以我们不会将它们作为本教程系列的一部分进行讨论。 步骤6和7:测试和调试这是有趣的部分(希望如此)!您可以运行可执行文件,看看它是否产生您期望的输出! 如果您的程序运行但无法正常工作,那么现在是时候进行一些调试以找出问题所在。我们将讨论如何测试您的程序以及如何更快地调试它们。 集成开发环境(IDE)请注意,步骤3,4,5和7都涉及软件(编辑器,编译器,链接器,调试器)。虽然您可以为每个功能使用单独的程序,但称为集成开发环境(IDE)的软件包将所有这些功能捆绑在一起并集成在一起。我们将在下一节讨论IDE,并安装一个IDE。]]></content>
</entry>
<entry>
<title><![CDATA[语句和程序结构]]></title>
<url>%2Fcpp%2F198adc04%2F</url>
<content type="text"><![CDATA[语句和程序结构章节介绍欢迎来到这些C++教程的第一个主要章节! 在本章中,我们将首先介绍一些对每个C++程序都至关重要的主题。因为有很多主题要涵盖,所以我们将涵盖相当浅层的大部分内容。本章的目标是帮助您了解基本C++程序的构建方式。到本章结束时,您将能够编写自己的简单程序。 在以后的章节中,我们将重新审视大多数这些主题并更详细地探讨它们。我们还将介绍基于这些概念的新概念。 为了保持课程长度可管理,主题可能会分成几个后续课程。如果您觉得课程中没有涵盖某些重要概念,则可能会在下一课中介绍它。 语句计算机程序是一系列指令,告诉计算机该做什么。一个语句是一种类型的指令,导致该程序执行某些操作。 语句是目前C++程序中最常见的指令类型。这是因为它们是C++语言中最小的独立计算单位。在这方面,它们的行为很像自然语言中的句子。当我们想要将想法传达给另一个人时,我们通常用句子(而不是随机词或音节)来写或说。在C++中,当我们想让程序执行某些操作时,我们通常会编写语句。 C++中的大多数(但不是全部)语句以分号结尾。如果你看到一个以分号结尾的行,那么它可能就是一个语句。 在诸如C++的高级语言中,单个语句可以编译成许多机器语言指令。 对于高级读者 C++中有许多不同类型的语句: 1.声明语句2.跳转声明3.表达式陈述4.复合语句5.选择陈述(条件)6.迭代语句(循环)7.Try语句块 当您完成本系列教程时,您将了解所有这些内容! 功能和主要功能在C++中,语句通常被分组为称为函数的单元。一个功能是语句的集合,依次执行。当您学习编写自己的程序时,您将能够以任何方式创建自己的函数并混合和匹配语句(我们将在未来的课程中展示如何)。 规则:每个C++程序都必须有一个名为main的特殊函数(全小写字母)。程序运行时,执行从函数main中的第一个语句开始,然后按顺序继续。 程序通常在执行函数main中的最后一个语句时终止(完成运行)(尽管它们可能在某些情况下提前中止)。 通常编写函数来执行特定的工作。例如,名为“max”的函数可能包含指出两个数字中哪一个更大的语句。名为“calculateGrade”的函数可以从一组测试分数中计算学生的成绩。我们将很快讨论有关函数的内容,因为它们是程序中最常用的组织工具。 作者的说明:在讨论函数时,将一对括号附加到函数名称的末尾是相当常见的简写。例如,如果您看到术语main()或doSomething(),则这是分别名为main或doSomething的函数的简写。这有助于将函数与其他类型的对象(例如变量)区分开来,而无需每次都写入“函数”一词。 解剖Hello World!现在您已经简要了解了哪些语句和函数,让我们回到我们的“Hello world”程序,并更详细地了解每行的内容。 1234567#include <iostream>int main(){ std::cout << "Hello world!"; return 0;} 第1行是一种特殊类型的行,称为预处理程序指令。这个预处理器指令表明我们想要使用iostream库的内容,它是C++标准库的一部分,允许我们从/向控制台读取和写入文本。我们需要这一行来在第5行使用std :: cout。排除这一行会导致第5行出现编译错误,因为编译器不会知道std :: cout是什么。 第2行是空白的,编译器会忽略它。该行仅用于帮助使程序对人类更具可读性(通过分离#include预处理程序指令和程序的后续部分)。 第3行告诉编译器我们将编写(定义)一个名为main的函数。如上所述,每个C++程序都必须具有main函数,否则将无法编译。 第4行和第7行告诉编译器哪些行是主函数的一部分。第4行的开口花括号和第7行的结束花括号之间的所有内容都被视为主要功能的一部分。这称为函数体。 第5行是函数main中的第一个语句,是我们运行程序时将执行的第一个语句。 std :: cout(代表“console output”)和operator <<允许我们向控制台发送字母或数字以便输出。在这种情况下,我们发送文本“Hello world!”,它将输出到控制台。此语句创建程序的可见输出。 第6行是一个返回语句。当可执行程序完成运行时,程序会将值发送回操作系统,以指示它是否成功运行。这个特殊的return语句将值0返回给操作系统,这意味着“一切正常!”。这是程序中执行的最后一个语句。 我们编写的所有程序都将遵循此通用模板或其变体。 作者的说明:如果上述解释的部分(或全部)令人困惑,那么此时就会出现这种情况。这只是为了提供快速概述。随后的课程将深入研究上述所有主题,并提供大量额外的解释和示例。 您可以自己编译并运行该程序,您将看到它将以下内容输出到控制台: Hello world! 如果您遇到编译或执行此程序的问题,请查看第0.8课- 一些常见的C++问题。 语法和语法错误在英语中,句子是根据你在学校英语课上学到的特定语法规则构建的。例如,普通句子在一段时间内结束。管理语句如何在语言中构造的规则称为语法。如果您忘记了句号并同时运行两个句子,则这违反了英语语法。 C++也有一个语法:关于如何构造程序以便被认为有效的规则。编译程序时,编译器负责确保程序遵循C++语言的基本语法。如果违反规则,编译器会在您尝试编译程序时发出抱怨,并向您发出语法错误。 让我们看看如果我们在“Hello world”程序的第5行省略分号会发生什么,如下所示: 1234567#include <iostream>int main(){ std::cout << "Hello world!" return 0;} 随意自己编译这个不正确的程序。 Visual Studio产生以下错误(您的编译器可能会生成具有不同措辞的错误消息): 1c:\vcprojects\test1.cpp(6): error C2143: syntax error : missing ';' before 'return' 这告诉你在第6行有一个语法错误:编译器在return语句之前期望分号,但它没有找到一个分号。虽然编译器会在遇到语法错误时告诉你编译哪行代码,但遗漏实际上可能在前一行。在这种情况下,错误实际上在第5行的末尾(编译器直到第6行才发现问题)。 编写程序时,语法错误很常见。幸运的是,它们通常很容易找到并修复,因为编译器通常会指向您。只有解决了所有语法错误后,才能完成程序的编译。 您可以尝试从“Hello world”程序中删除字符甚至整行,以查看生成的各种错误。尝试在第5行的末尾恢复丢失的分号,然后删除第1,3或4行,看看会发生什么。]]></content>
</entry>
<entry>
<title><![CDATA[集成开发环境(IDE)安装]]></title>
<url>%2Fcpp%2Ffd9ffcf1%2F</url>
<content type="text"><![CDATA[一个集成开发环境(IDE)是一个软件包含了所有你需要开发,编译,链接和调试程序的事情。 使用典型的C++ IDE,您将获得一个代码编辑器,用于执行行编号和语法突出显示。许多(但不是全部)IDE包括C++编译器和链接器,IDE将知道如何与源代码进行交互以将源代码转换为可执行文件。当您需要调试程序时,可以使用集成调试器。 此外,IDE通常捆绑了许多其他有用的编辑功能,例如集成帮助,名称完成,自动格式化,有时还有版本控制系统。因此,虽然您可以单独执行所有这些操作,但安装IDE并使它们都可以从单个界面访问它们要容易得多。 所以让我们安装一个!明显的下一个问题是,“哪一个?”。许多IDE都是免费的(价格合理),如果您愿意,可以安装多个IDE,因此这里没有“错误的决定”。我们将在下面推荐一些我们的最爱。 如果您还有其他IDE,那也没关系。我们在这些教程中向您展示的概念通常适用于任何体面的现代IDE。但是,各种IDE使用不同的名称,布局,键映射等…因此您可能需要在IDE中进行一些搜索才能找到相同的功能。 Visual Studio(适用于Windows)如果您在Windows机器上进行开发(大多数人都是如此)并且磁盘空间和下载大小不是约束,那么我们强烈建议您使用Visual Studio Community 2017。当您运行安装程序时,您最终会进入一个屏幕,询问您要安装的工作负载。选择使用C++进行桌面开发。如果不这样做,那么C++功能将无法使用。 在屏幕右侧选择的默认选项应该没问题,但请确保选择了Windows 10 SDK。Windows 10 SDK可以在旧版本的Windows上使用,因此如果您仍在运行Windows 7或8,请不要担心。 如果磁盘空间和/或下载大小是一个挑战,那么我们建议使用Microsoft免费的Windows桌面Visual Studio Express 2017,您可以在页面底部找到它。 Code :: Blocks(适用于Linux或Windows)如果您正在使用Linux进行开发(或者您正在开发Windows但希望编写可以轻松移植到Linux的程序),我们建议使用Code :: Blocks。Code :: Blocks是一个免费的开源跨平台IDE,可以在Linux和Windows上运行。 对于Windows用户 确保获得捆绑了MinGW的Code :: Blocks的版本(它应该是其文件名以mingw-setup.exe结尾的版本)。这将安装MinGW,其中包括GCC C++编译器的Windows端口: 当您第一次启动Code :: Blocks时,您可能会得到一个编译器自动检测对话框。如果这样做,请确保将GNU GCC Compiler设置为默认编译器,然后选择确定按钮。 使用Code :: Blocks,默认情况下可以禁用C++ 11 / C++ 14 / C++ 17功能。你肯定想检查并打开它。首先,转到“设置”菜单>“编译器”: 然后找到标有Have g ++的方框符合C++ XX ISO C++语言标准[-std = C++ XX] : ,其中XX为11,14或其他更高的数字(参见红框内的项目)下面的例子): 检查具有最高编号的那个(在上面的例子中,这是红色框内的C++ 14选项)。 您的Code :: Blocks版本也可能支持C++的实验版或刚刚发布的版本。如果是这样,这将被标记为Have g ++遵循即将推出的C++ 11YY(又名C++ XX)ISO C++语言标准[-std = C++ ZZ](参见上面的蓝框)。如果要在该版本中启用功能,可以选择检查这些功能,但请注意支持可能不完整(例如某些功能可能缺失)。 问:我想在Code :: Blocks中启用C++ 17功能,但我没有看到-std = C++ 17选项 如果你看到-std = C++ 1z的一个选项,那就相当了(C++ 17之前被称为C++ 1z,然后才知道它将在什么年份完成)。 或者,您可以转到“其他编译器选项”选项卡并键入-std = C++ 17。 如果您的编译器支持C++ 17,这将有效。如果您使用旧版本的Code :: Blocks和C++ 17功能似乎不起作用,请升级您的编译器。 问:我收到“在GNU GCC编译器的已配置搜索路径中找不到编译器可执行文件”错误 请尝试以下方法: 在Windows上,请确保已下载Code :: Blocks WITH MinGW的版本。这是名字中有“mingw”的人。 尝试进入设置,编译器,然后选择“重置为默认值”。 尝试转到设置,编译器,工具链可执行文件选项卡,并确保将“编译器的安装目录”设置为MinGW目录(例如C:\ Program Files(x86)\ CodeBlocks \ MinGW)。 尝试执行完全卸载,然后重新安装。 尝试不同的编译器。 Mac OSX IDE流行的Mac选择包括Xcode(如果它可用)或Eclipse。Eclipse默认情况下未设置为使用C++,您需要安装可选的C++组件。 虽然Visual Studio for Mac已经发布,但截至2018年8月它不支持C++,所以目前我们不推荐它。 我可以使用基于Web的编译器吗?是的,对某些事情。当您的IDE正在下载时(或者如果您不确定是否要提交安装IDE),可以使用基于Web的编译器继续本教程,例如TutorialsPoint中的编译器。 基于Web的编译器适用于简单的练习和简单的练习。但是,它们的功能通常非常有限 - 许多不允许您保存项目,创建可执行文件或有效调试程序。您可以尽可能迁移到完整的IDE。 我可以使用命令行编译器(例如Linux上的g ++)吗?是的,但您需要找到自己的编辑器并查找如何在其他地方使用它。 当事情出错时(又名IDE代表“我甚至不……”)IDE安装似乎导致其公平的问题。安装可能会彻底失败(或者安装可能会起作用,但是当您尝试使用它时,由于配置问题,IDE会出现问题)。如果遇到此类问题,请尝试卸载IDE(如果它首先安装),重新启动计算机,暂时禁用防病毒或防恶意软件,然后再次尝试安装。 如果此时仍遇到问题,您有两种选择。更简单的选择是尝试不同的IDE。另一种选择是解决问题。遗憾的是,安装和配置错误的原因各不相同,并且特定于IDE软件本身,我们无法有效地就如何解决此类问题提出建议。在这种情况下,我们建议将您遇到的错误消息或问题复制到Google搜索中,并尝试在其他地方找到一个不可避免地遇到同样问题的可怜的灵魂的论坛帖子。通常会有关于您可以尝试解决问题的建议。 继续一旦安装了IDE(如果事情没有按预期进行,这可能是最困难的步骤之一),或者如果您暂时继续使用基于Web的编译器,那么您就可以编写第一个程序了!]]></content>
</entry>
<entry>
<title><![CDATA[教程简介]]></title>
<url>%2Fcpp%2F1ed2d910%2F</url>
<content type="text"><![CDATA[欢迎欢迎来到C++教程,这些教程旨在让学习C++更轻松容易。 我们不像许多其他网站和书籍那样假设你有任何以往的编程经验。任何你需要知道的东西,我们都会在学习过程中传授给你,并带有大量的示例。 无论你是C++爱好者或者专业开发者,你都来到了对的地方。 教程结构本章节属于介绍性质教程,它将告诉你C++是什么,它的由来,程序是如何执行的以及您需要安装什么软件来编写自己的程序。你甚至可以编写自己的第一个程序。 更多章节将探讨C++语言的不同部分。在第一章(第1章)中,您将对许多基本的C++概念有一个广泛而浅薄的了解,因此我们可以开始编写一些简单的程序。更多章节将深入探讨这些概念,或介绍新概念。 每一章都有一个主题,其下面的所有部分通常都与该主题相关。每节课或章节都没有建议的时间; 请以适合您的速度来学习这些材料。 目标在我们开始之前,让我们来看看这些教程的几个重要目标: 涵盖编程主题以及C++。传统教科书在教授某一门编程语言的基础知识方面做得非常好,但它们通常不涉及和这门语言相关的其他话题。打个比方,教科书一般会省略有关编程风格,常见错误,调试,好/坏编程实践和测试的部分。因此,当你学完这些书后,即便你明白如何用这门语言编程了,但你养成的许多编程坏习惯会在今后成为你的阻碍!本教程的目标之一就是,在学习的过程中自然而然地引出相关话题并加以讨论,确保所有相关话题都包含在教程中。完成后,你不仅知道如何正确使用C++编程,你还知道不该怎么用C++编程,两者是同等重要的。 提供了很多示例。大多数人从示例中学到的东西和从文字阅读中学到的一样多。本教程将努力提供大量清晰,简洁的示例,以展示如何应用您正在学习的概念。我们也会尽量避免在介绍某一概念时,忽略其他相关的必要概念或是为了节省文章空间而忽略某些例子。 这些都会让人产生困惑。 提供练习课程。许多课程结尾包含一些练习(带有答案),你可以先自己尝试独立解决这些问题。完成后再与我们给出的答案进行对比,看看有什么不同,如果你不理解我们是如何写出这些答案的,就请回顾课程并在你还不理解的部分多下功夫。 最重要的是:玩得开心。编程可以带来很多乐趣,如果你没有乐趣,那么你就没有以正确的思维方式来编程。疲惫或不快乐的程序员会犯错误,调试代码往往比一开始写出正确的代码要花费更长的时间!这时候我建议你睡一个好觉,第二天早上再来尝试解决问题。 充分利用这些教程在阅读这些教程时,我们建议您采用一些实践来最大化您的学习体验: 尝试手动输入示例程序并自行编译。不要复制和粘贴它们!这将帮助您了解自己在什么情况下容易出错,以及熟悉编译器的警告和错误。当您输入示例程序时,请思考你输入的这些语句都有什么有意。 当您在程序中出错或发现错误时,请修复它们。在向别人寻求帮助之前,尝试解决自己的问题。学习如何查找和修复错误是成功编程的关键技能。不要忽视学习如何使用调试器(我们将在未来的课程中解释) –它是排查程序错误的关键工具。 试验这些示例。更改数字和文字以查看会发生什么。修改程序以执行其他操作(例如,如果程序添加两个数字,则添加三个数字)。尝试找到打破程序的不同方法(如果程序要求用户输入,请尝试各种不同的输入)。您将通过遵循它们来修改示例。 计划花一些时间参加测验。如果您是编程新手,您可能会发现这些具有挑战性(由于你正在迫使你的大脑适应编程思维,所以这是再正常不过不过的事情)。如果您第一次没有得到正确的答案,请不要气馁。在找到有效的方法之前,您可能需要尝试几种不同的方法。如果你真的被困住,可以看看答案。在继续之前,请确保您了解答案的工作原理。 使用您学到的概念编写自己的短程序。没有什么比练习更有效。 常见的相关问题问:这些教程是在2007年编写的。它们是否仍然相关? 是的,一点没错。 C++不会经常更改,这些教程已经更新,以适应新的内容和语言更改。 问:如果我遇到一个概念,该怎么办? 如果您不理解某些内容,请仔细阅读评论。其他读者可能遇到过类似的问题。其次,尝试浏览系列中的下一课 – 您的问题可以在那里得到解答。第三,使用搜索引擎查看您的问题(或错误消息)是否已在其他地方解决。第四,去编程问答平台上询问您的问题,例如Stack Overflow。 如果所有其他方法都尝试了且没有得到结果,请跳过您不理解的部分,稍后再回过头来。您可能会发现,有了其他文章提供的其他知识,原来比较难以理解的部分可能就变得容易理解一些了。 问:如果我对某些知识遗忘了,我该怎么办? 前往教程的目录页。查找您想要了解更多信息的任何主题,您将找到讨论该主题的课程的链接。 好吧,让我们继续吧!]]></content>
</entry>
<entry>
<title><![CDATA[介绍C++开发]]></title>
<url>%2Fcpp%2F46108864%2F</url>
<content type="text"><![CDATA[介绍C++开发在我们编写和执行第一个C++程序之前,我们需要更详细地了解一个C++程序是怎么被开发出来的。看下图: 第1步:定义您要解决的问题。这是“做什么”的阶段,在这个阶段你需要找出你要解决的问题。定义你想要编写什么样的程序或许是最简单的一步,但也可能是最难的一步。但从概念上讲,它是最简单的。您只需要有一个深思熟虑的想法,你就可以进行下一步了。 这里有一些例子: “我想编写一个程序,允许我输入许多数字,然后计算平均值。”“我想写一个生成2d迷宫的程序,让用户浏览它。如果用户到达目的地,用户将获胜。““我想写一个程序,读取股票价格文件并预测股票是涨还是跌。” 第2步:确定如何解决问题。这是“怎么做”的阶段,你要在这个阶段决定用什么样的方式来解决第一阶段所提出的问题。这也是软件开发中最容易忽略的步骤。问题的关键在于有很多方法可以解决问题 – 但是,其中一些方法很好,其中一些方法却很烂。通常,程序员会一下子就想出一个解决方案,然后屁股一坐,就开始写代码。这种情况下通常会产出比较烂的解决方案。 通常,良好的解决方案具有以下特征: 它们很简单(不会过于复杂或令人困惑)。 它们有很好说明(特别是在提出任何假设或限制时)。 它们是模块化构建的,因此可以在以后重复使用或更改,且不会影响程序的其他部分。 它们非常稳健,可以在出现意外情况时容易修复或提供有用的错误消息。 当你脑袋一热,屁股一坐,然后立即开始写代码时,你通常思考的是“我想做这个”,因此你使用最快的实现方式来达成你想要的效果,然而这可能导致程序的健壮性非常脆弱,以后难以更改或扩展,或者存在大量Bug(技术缺陷)。 作为旁白... 术语Bug最早是由托马斯·爱迪生早在19世纪70年代提出!然而,该术语在20世纪40年代普及,当时工程师发现一只飞蛾卡在早期计算机的硬件中,导致短路。当时的错误报告和“飞蛾”实体现在都还在美国Smithsonian历史博物馆存放着。 研究表明,程序员只有20%的时间用于编写初始程序。另外80%用于维护,包括调试(删除错误),针对新需求进行更改(例如,在新的操作系统版本上运行),增强功能(用于改进可用性或功能的微小更改),或者内部改进(提高可靠性或可维护性)。 因此,你有必要在开始写代码前,花更多的时间去思考解决问题的最佳方法,提出更多的假设,以及未日后的维护做好计划,这样可以一路上节约你很多的时间,记住,思考两次,编码一次! 我们会在今后的课程更多地讨论如何有效地设计问题的解决方案。 第3步:编写程序为了编写程序,我们需要两件事:首先我们需要编程语言的知识 – 这就是这些教程的用途!其次,我们需要一个代码编辑器。可以使用您想要的任何代码编辑器编写程序,甚至用windows系统的记事本或者Unix的vi都行。但是,我们强烈建议您使用专为写代码而设计的编辑器。如果你还没有,请不要担心。我们将简要介绍如何安装代码编辑器。 专为写代码而设计的编辑器具有一些使编程更容易的功能,包括: 1)行号。当编译器给我们一个错误时,行号很有用,因为一般的编译器报错会像这样:错误代码/错误消息,第64行。如果没有显示行号的编辑器,你要找第64行可能只有一行一行慢慢数了。 2)语法高亮和着色。语法高亮和着色会更改程序各个部分的颜色,以便更容易识别程序的不同组件。这是一个包含行号和语法高亮的C++程序示例(来自译者:我还不知道怎么通过markdown显示行号…): 1234567#include <iostream>int main(){ std::cout << "Colored text!"; return 0;} 我们在本教程中展示的示例将始终具有行编号和语法突出显示,好让它更容易看懂。 3)明确的字体。非编程字体通常使得难以区分数字0和字母O,或数字1,字母l(小写字母L)和字母I(大写字母i)。一个好的编程字体将区分这些符号,以确保不会意外地使用一个符号代替另一个符号。 在C++中,您的程序通常称为name.cpp,其中name替换为您为程序选择的名称(例如计算器,hello等等)。.cpp扩展则告诉您这是一个包含C++指令的C++源代码文件。请注意,有些人使用扩展名.cc而不是.cpp,但我们建议您使用.cpp。 最佳实践 将您的代码文件命名为name.cpp,其中name是您选择的名称,.cpp是指示该文件是C++源文件的扩展名。 另请注意,许多复杂的C++程序都有多个.cpp文件。在学习初期您一般用到一个.cpp文件就够了,但你需要知道的是,一个程序很有可能会有成百上千的.cpp文件(来自译者:比如虚幻引擎源代码,WTF!) 一旦我们编写了程序,接下来的步骤就是将它转换成我们可以运行的东西,然后看它是否有效!我们将在下一节中讨论这些(4到7)步骤。]]></content>
</entry>
<entry>
<title><![CDATA[介绍C和C++语言]]></title>
<url>%2Fcpp%2Fa5c6b875%2F</url>
<content type="text"><![CDATA[在C++之前是C语言C语言由贝尔电话实验室的Dennis Ritchie于1972年开发,主要用作系统编程语言(用于编写操作系统的语言)。Ritchie的主要目标是生成一种易于编译的简约语言,允许有效访问内存,生成高效代码,并且是独立的(不依赖于其他程序)。对于高级语言,它旨在为程序员提供大量控制,同时仍然鼓励平台(硬件和操作系统)独立(即,不必为每个平台重写代码)。 C最终变得如此高效和灵活,以至于1973年,Ritchie和Ken Thompson使用C重写了大部分UNIX操作系统。许多以前的操作系统都是用汇编语言编写的。与仅生成只能在特定CPU上运行的程序的程序集不同,C具有出色的可移植性,允许在许多不同类型的计算机上轻松地重新编译UNIX并加速其采用。C和Unix的命运联系在一起,而C的受欢迎程度部分与UNIX作为操作系统的成功有关。 1978年,Brian Kernighan和Dennis Ritchie出版了一本名为“The C Programming Language”的书。这本书通常被称为K&R(在作者的姓氏之后),提供了该语言的非正式规范,并成为事实上的标准。当需要最大的可移植性时,程序员会坚持K&R中的建议,因为当时大多数编译器都是按照K&R标准实现的。 1983年,美国国家标准协会(ANSI)成立了一个委员会来建立C的正式标准。在1989年(委员会啥都做呀~),他们完成并发布了C89标准,通常称为ANSI C. 1990年,国际标准化组织(ISO)采用ANSI C(稍作修改的版本)。这个版本的C被称为C90。编译器最终符合ANSI C / C90标准,并且希望最大可移植性的程序被编码为此标准。 1999年,ANSI委员会发布了一个名为C99的新版C语言。C99采用了许多功能,这些功能已经作为扩展进入编译器,或者已经在C++中实现。 C++C++(发音为see plus plus)由Bjarne Stroustrup在贝尔实验室开发,作为C的扩展,从1979年开始。C++为C语言添加了许多新功能,也许最好被认为是C的超集,尽管这是并非完全正确(因为C99引入了一些C++中不存在的功能)。C++声名鹊起的主要原因在于它是一种面向对象的语言。至于对象是什么以及它与传统编程方法的区别,我们将在第8章(面向对象编程基础)中介绍它。 C++于1998年由ISO委员会批准,并于2003年再次批准(称为C++ 03)。自那时起,C++语言(C++ 11,C++ 14和C++ 17,在2011年,2014年和2017年得到批准)的三个主要更新已经完成,为该语言添加了额外的功能。特别是C++ 11为该语言添加了大量新功能。这些更新中的一些相关功能将在这些教程中讨论。该语言的未来更新正在积极考虑之中。 C和C++的哲学C和C++的基本设计理念可以概括为“信任程序员” - 既美妙又危险。C++旨在让程序员可以高度自由地完成他们想要的任务。然而,这也意味着语言通常不会阻止你做一些没有意义的事情,因为它会假设你因为某些原因而无法理解。如果没有意识到,新程序员可能会陷入相当多的陷阱。这是“知道如何正确使用C++和不该怎么用C++编程两者同等重要”的原因之一。 问:C++擅长什么? C++在需要高性能和精确控制内存和其他资源的情况下表现出色。以下是一些常见的应用程序类型,最有可能用C++编写: 视频游戏 实时系统(例如运输,制造等……) 高性能金融应用(例如高频交易) 图形应用程序和模拟 生产力/办公应用 嵌入式软件 音视频处理 问:在进行这些教程之前,我是否需要了解C? 不需要!从C++开始是完美的,我们会教你一路上需要知道的一切(包括要避免的坑)。 一旦你了解了C++,如果你有需要,学习标准C应该很容易。目前,C主要用于小众用例:在嵌入式设备上运行代码,以及与只支持C的代码打交道的时候……大多数情况下,建议使用C++。]]></content>
</entry>
<entry>
<title><![CDATA[编程语言介绍]]></title>
<url>%2Fcpp%2F2258fc9a%2F</url>
<content type="text"><![CDATA[编程语言介绍如今的计算机速度极快,而且速度越来越快。然而,即便有如此快的速度,它依然存在一些重要的制约因素:计算机本身只能理解一组非常有限的命令,你必须准确地告诉它做什么,它才会做什么。 计算机程序(通常也被称为应用程序)是一组可以让计算机执行一些任务的指令。创建程序的过程称为编程。程序员通常通过书写源代码(通常缩写为代码)来创建程序,源代码是键入一个或多个文本文件内的命令列表。 组成计算机和执行程序的物理计算机部件的集合称为硬件。计算机程序被加载到内存中,硬件按顺序执行每个指令,这就称为运行或执行程序。 机器语言计算机的CPU无法理解C++。CPU可以直接理解的有限指令集称为机器代码(或机器语言或指令集)。 这是一个机器语言指令的例子: 10110000 01100001 当计算机最初发明时,程序员必须直接用机器语言编写程序,这是一件非常困难和耗时的事情。 如何组织这些指令超出了本介绍的范围,但有两点需要注意。首先,每条指令由1和0的序列组成。每个单独的0或1称为二进制数字,或简称为位。组成单个命令的位数会有所不同 – 例如,某些CPU只会处理32位长的指令,而某些其他CPU(例如x86系列)具有长度可变的指令。 其次,每组二进制数字由CPU解释为执行特定工作的命令,例如这两个数字的比较,或将此数字放在该内存位置。但是,由于不同的CPU具有不同的指令集,因此不能在不共享相同指令集的CPU上使用为一种CPU类型编写的指令。这意味着程序通常不可移植(如果没有进行大返工的前提下)用于不同类型的系统,并且必须重新编写。 汇编语言因为机器语言对人类来说很难阅读和理解,所以发明了汇编语言。在汇编语言中,每个指令由短缩写(而不是一组位)标识,并且可以使用名称和其他数字。 这是一个与上述指令相同但用汇编语言描述的例子: mov al, 061h 这使得汇编比机器语言更容易读取和写入。但是,CPU无法直接理解汇编语言。相反,必须先将汇编程序翻译成机器语言,然后才能由计算机执行。这是通过使用称为汇编器(assembler)的程序完成的。用汇编语言编写的程序往往非常快,而如今,在速度至关重要的情况下,还是会有人使用汇编语言。 但是,汇编语言仍有一些缺点。首先,汇编语言仍需要大量指令来完成简单的任务。虽然单个指令本身在某种程度上是人类可读的,但了解整个程序正在做什么就比较难了(这有点像试图通过单独查看每个字母来理解句子)。其次,汇编语言的可移植性仍然不够 – 使用汇编语言为一种CPU类型编写的程序不能在其他使用不同指令集的硬件上运行。并且必须重写或进行大量修改。 高级语言为了解决可读性和可移植性问题,一些新的编程语言,如C,C++,Pascal(以及后来的Java,Javascript和Perl等语言)出现了。这些语言被称为高级语言,因为它们旨在允许程序员编写程序而无需关心程序将运行在何种类型的计算机上。 这儿同样是与上述相同的指令但用高级语言描述的例子: a = 97; 与汇编程序非常相似,用高级语言编写的程序必须翻译成计算机可以运行的格式才能运行。这有两种主要方式:编译和解释。 编译器是一个程序,可以读取源代码,并生成一个独立的可执行程序。将代码转换为可执行文件后,您无需编译器即可运行该程序。最初,编译器不够强大,生成的都是缓慢且未经优化过的代码。然而,这么多年过来了,编译器已经非常擅长生成快速、经过优化的代码,并且在某些情况下可以比人类在汇编语言方面做得更好! 以下是编译过程的简化表示: 由于C++程序通常是需要编译的,因此我们将在稍后详细介绍编译器。 解释器是直接执行在源代码中的指令,而不需要他们首先被编译成可执行的程序。解释器往往比编译器更灵活,但在运行程序时效率较低,因为每次运行程序时都需要完成解释过程。这意味着每次运行程序时都需要解释器。 以下是解释过程的简化表示: 可以在此处查看对编译器与解释器的优缺点的详细比较(可选阅读) 大多数语言都可以被编译或解释,但是,传统语言如C,C++和Pascal是需要编译的,而像Perl和Javascript这样的“脚本”语言往往需要被解释。有些语言,比如Java,混合使用了两种方法。 高级语言有许多可取的特性 首先,高级语言更容易读写,因为命令更接近我们每天使用的自然语言。 其次,高级语言需要较少的指令来执行与低级语言相同的任务,使程序更简洁,更容易理解。在C++中,您可以a = b * 2 + 5;在一行中执行某些操作。在汇编语言中,这将需要5或6个不同的指令。 第三,高级语言写的程序可以在很多不同的平台被编译/解释,你不需要通过修改程序来让它运行在不同的PUC(你只需要为那个Cpu重新编译)。举个例子: 可移植性有两个常见的例外。首先,许多操作系统(如Microsoft Windows)提供很多平台特有代码(platform-specific functions)供你在代码中使用,这些平台特有代码可以使编写特定操作系统的程序变得更加容易,但代价是可移植性。在这些教程中,我们将避免使用任何平台特有代码 某些编译器还支持特定于编译器的扩展 - 如果您使用这些扩展,您的程序将无法由其他不支持相同扩展的编译器编译而无需修改。一旦安装了编译器,我们稍后会详细讨论这些内容。 有些编译器支持特定编译器拓展 – 如果你使用了它,你的程序就不能被其他编译器编译,除非其他编译器支持同样的编辑器拓展,我们会在之后教你安装编译器的时候再来讨论这一点。]]></content>
</entry>
<entry>
<title><![CDATA[右值引用]]></title>
<url>%2Fcpp%2F96d9fb0d%2F</url>
<content type="text"><![CDATA[R-Value在第一章我们提到了左值和右值,然后告诉你不要太担心它们。在C++ 11出现之前这么说没什么问题。但是要理解C++ 11中的Move语义则需要重新审视该主题。这就是本节的内容。 左值和右值尽管左值和右值名称中都包含“值”一词,但左值和右值实际上不是值的属性,而是表达式的属性。 C++中的每个表达式都有两个属性:一个类型(用于类型检查)和一个值类别(Value Category)(用于某些类型的语法检查,例如是否可以将表达式的结果用于赋值)。在C++ 03及更早版本中,左值和右值是唯一可用的两个值类别。 定义哪些表达式是左值哪些是右值是非常复杂的,因此我们将用比较简单的形式来讲解,这对我们的学习目的是足够了的。 定义左值(也称为定位器值)最简单的方法是将左值视为函数或对象(或一个计算为函数或对象的表达式)。所有左值都分配了内存地址。 左值的最初定义是“在赋值表达式的左侧的值都叫做左值”。然而,在const关键字被添加到了C++语言之后,这一定义就不准确了,并且左值被分成两个子类:可修改的左值和不可修改的左值(const)。 定义右值最简单的方法是“只要不是左值,那它就是右值”。这包括字面值(例如5),临时的值(例如x+1)和匿名对象(例如 Fraction(5, 2))。右值通常根据它们的值进行分辨,它具有表达式范围,且不能被赋值。 This non-assignment rule makes sense, because assigning a value applies a side-effect to the object. Since r-values have expression scope, if we were to assign a value to an r-value, then the r-value would either go out of scope before we had a chance to use the assigned value in the next expression (which makes the assignment useless) or we’d have to use a variable with a side effect applied more than once in an expression (which by now you should know causes undefined behavior!). 为了支持Move语义,C++ 11引入了3个新的值类别:pr-values, x-values, and gl-values。我们将在很大程度上忽略这些,因为理解它们对于有效地学习或使用移动语义是没有必要的。如果您有兴趣,cppreference.com有一个广泛的表达式列表,这些表达式符合各种值类别的要求,以及有关它们的更多详细信息。 左值引用在C++ 11之前,C++中只存在一种类型的引用,因此它被称为“引用”。但是,在C++ 11中,它有时被称为左值引用。左值引用只能用可修改的左值初始化。 左值引用 可初始化 可修改 可修改的左值 Yes Yes 不可修改的左值 No No 右值 No No 可以使用左值和右值来初始化对const对象的左值引用。但是,这些值无法修改。 左值const引用 可初始化 可修改 可修改的左值 Yes No 不可修改的左值 Yes No 右值 Yes No 对const对象的左值引用特别有用,因为它们允许我们将任何类型的参数(左值或右值)传递给函数,而无需复制参数。 右值引用C++ 11添加了一种称为右值引用的新类型引用。右值引用是一个只能用右值初始化的引用。使用单个&符号创建左值引用,但使用双&符号创建右值引用: 123int x = 5;int &lref = x; // 使用左值x初始化左值引用int &&rref = 5; // 使用右值5初始化右值引用 无法使用左值初始化右值引用。 右值引用 可初始化 可修改 可修改的左值 No No 不可修改的左值 No No 右值 Yes Yes 右值Const引用 可初始化 可修改 可修改的左值 No No 不可修改的左值 No No 右值 Yes Yes 右值引用有两个有用的属性。首先,右值引用将它们初始化的对象的生命周期延长到右值引用的生命周期(对const对象的左值引用也可以这样做)。其次,非常量右值引用允许您修改右值! 我们来看看一些例子: 12345678910111213141516171819202122232425262728#include <iostream> class Fraction{private: int m_numerator; int m_denominator; public: Fraction(int numerator = 0, int denominator = 1) : m_numerator(numerator), m_denominator(denominator) { } friend std::ostream& operator<<(std::ostream& out, const Fraction &f1) { out << f1.m_numerator << "/" << f1.m_denominator; return out; }}; int main(){ Fraction &&rref = Fraction(3, 5); // r-value reference to temporary Fraction std::cout << rref << '\n'; return 0;} // rref (and the temporary Fraction) goes out of scope here 该程序输出: 3/5 作为一个匿名对象,Fraction(3,5)通常会在定义它的表达式的末尾超出范围。但是,由于我们用它初始化一个右值引用,它的持续时间会延长到块的结尾。然后我们可以使用该右值引用来输出Fraction的值。 现在让我们来看一个不太直观的例子: 12345678910#include <iostream> int main(){ int &&rref = 5; // because we're initializing an r-value reference with a literal, a temporary with value 5 is created here rref = 10; std::cout << rref; return 0;} 该程序输出: 10 虽然使用文字值初始化右值引用然后能够更改该值可能看起来很奇怪,但是当使用文字初始化右值时,从文字构造临时值以使引用引用临时值对象,而不是文字值。 右值引用不经常以上述任何一种方式使用。 右值引用作为函数参数右值引用更常用作函数参数。当您希望对左值和右值参数有不同的行为时,这对函数重载最有用。 123456789101112131415161718void fun(const int &lref) // l-value arguments will select this function{ std::cout << "l-value reference to const\n";} void fun(int &&rref) // r-value arguments will select this function{ std::cout << "r-value reference\n";} int main(){ int x = 5; fun(x); // l-value argument calls l-value version of function fun(5); // r-value argument calls r-value version of function return 0;} 这输出: 左值引用const右值引用 如您所见,当传递左值时,重载函数已解析为具有左值引用的版本。当传递右值时,重载函数解析为具有右值引用的版本(这被认为是比对const的左值引用更好的匹配)。 你为什么要这样做?我们将在下一课中更详细地讨论这个问题。不用说,它是移动语义的重要组成部分。 一个有趣的说明:12int &&ref = 5;fun(ref); 实际上调用函数的左值版本!虽然变量ref具有对整数的类型右值引用,但它本身实际上是左值(与所有命名变量一样)。混淆源于在两种不同背景下使用术语右值。可以这样想:命名对象是左值。匿名对象是右值。命名对象或匿名对象的类型与左值还是右值无关。或者,换句话说,如果已经调用了右值引用,则不会存在这种混淆。 返回右值引用你永远都不应该在函数中返回一个右值引用,因为当引用的对象超出函数末尾的范围时你得到的就是一个无效的引用。]]></content>
</entry>
</search>