-
每个C++程序都包含一个或多个函数(function),其中一个必须命名为main。操作系统通过调用main来运行C++程序。下面是一个非常简单的main函数,它什么也不干,只是返回给操作系统一个值:
-
int main() {return 0; }
-
-
一个函数的定义包含四部分:返回类型(return type)、函数名(function name)、一个括号包围的形参列表(parameter list,允许为空)以及函数体(function body)。虽然main函数在某种程度上比较特殊,但其定义与其他函数是一样的。
-
main函数的返回类型必须为int,即整数类型(虽然在一些编译器中,void main() 可以通过编译,但并非所有编译器都支持void main() ,因为标准中从来没有定义过void main())。int类型是一种内置类型(built-intype),即语言自身定义的类型。函数定义的最后一部分是函数体,它是一个以左花括号(curly brace)开始,以右花括号结束的语句块(block of statements).
-
当return语句包括一个值时,此返回值的类型必须与函数的返回类型相容。在本例中,main的返回类型是int,而返回值0的确是一个int类型的值。请注意,return语句末尾的分号。在C++中,大多数C++语句以分号表示结束。它们很容易被忽略,但如果忘记了写分号,就会导致莫名其妙的编译错误。
-
编译、运行程序
-
很多PC机上的编译器都具备集成开发环境(Integrated Developed Environment,IDE),将编译器与其他程序创建和分析工具包装在一起。在开发大型程序时,这类集成环境可能是非常有用的工具,但需要一些时间来学习如何高效地使用它们。
-
程序源文件命名约定
- 无论你使用命令行界面或者IDE,大多数编译器都要求程序源码存储在一个或多个文件中。程序文件通常被称为源文件( source file)。在大多数系统中,源文件的名字以一个后缀为结尾,后缀是由一个句点后接一个或多个字符组成的。后缀告诉系统这个文件是一个C++程序。不同编译器使用不同的后缀命名约定,最常见的包括.cc、.cxx、.cpp、.cp及.c。
-
-
C++语言并未定义任何输入输出(IO)语句,取而代之,包含了一个全面的标准库( standard library)来提供IO机制(以及很多其他设施)。iostream库包含两个基础类型istream和 ostream,分别表示输入流和输出流。一个流就是一个字符序列,是从IO设备读出或写入IO设备的。术语“流”( stream)想要表达的是,随着时间的推移,字符是顺序生成或消耗的。
-
标准库定义了4个IO对象。为了处理输入,我们使用一个名为cin(发音为see-in)的istream类型的对象。这个对象也被称为标准输入(standard input)。对于输出,我们使用一个名为cout(发音为see-out)的ostream类型的对象。此对象也被称为标准输出(standard output)。标准库还定义了其他两个ostream对象,名为cerr和 clog(发音分别为see-err和 see-log)。我们通常用cerr来输出警告和错误消息,因此它也被称为标准错误(standard error)。而clog用来输出程序运行时的一般性信息。系统通常将程序所运行的窗口与这些对象关联起来。因此,当我们读取cin,数据将从程序正在运行的窗口读入,当我们向cout、cerr和clog写入数据时,将会写到同一个窗口。
-
#include <iostream> int main() {std::cout << "Hello World!\n";std::cout << "输入两个数:" << std::endl;int v1 = 0, v2 = 0; // 变量初始化std::cin >> v1 >> v2;std::cout << "两数之积:" << v1 * v2 << std::endl;return 0; }
-
<<运算符接受两个运算对象:左侧的运算对象必须是一个ostream对象(std::cout),右侧的运算对象是要打印的值。此运算符将给定的值写到给定的ostream对象中。输出运算符的计算结果就是其左侧运算对象。即,计算结果就是我们写入给定值的那个ostream对象。
-
运算符打印endl,这是一个被称为操纵符( manipulator)的特殊值。写入end的效果是结束当前行,并将与设备关联的缓冲区 (buffer)中的内容刷到设备中。缓冲刷新操作可以保证到目前为止程序所产生的所有输出都真正写入输出流中,而不是仅停留在内存中等待写入流。程序员常常在调试时添加打印语句。这类语句应该保证“一直”刷新流。否则,如果程序崩溃,输出可能还留在缓冲区中,从而导致关于程序崩溃位置的错误推断。
-
可能会注意到这个程序使用了std: :cout和 std::endl,而不是直接的cout和 endl。前缀std::指出名字cout和 endl是定义在名为std 的命名空间(namespace)中的。命名空间可以帮助我们避免不经意的名字定义冲突,以及使用库中相同名字导致的冲突。标准库定义的所有名字都在命名空间std中。
-
在提示用户输入数据之后,接下来我们希望读入用户的输入。首先定义两个名为vl和v2的变量(variable)来保存输入,我们将这两个变量定义为int类型,int是一种内置类型,用来表示整数。还将它们初始化( initialize)为0。初始化一个变量,就是在变量创建的同时为它赋予一个值。
-
它读入输入数据。输入运算符(>>)与输出运算符类似,它接受一个istream作为其左侧运算对象,接受一个对象作为其右侧运算对象。它从给定的istream读入数据,并存入给定对象中。与输出运算符类似,输入运算符返回其左侧运算对象作为其计算结果。
-
注释简介
-
注释通常用于概述算法,确定变量的用途,或者解释晦涩难懂的代码段。编译器会忽略注释,因此注释对程序的行为或性能不会有任何影响。虽然编译器会忽略注释,但读者并不会。即使系统文档注释比完全其它部分已经过时,也倾向于相信注释的内容是正确可信的。因此,错误的注释比完全没有注释更糟糕,因为它会误导读者。因此,当你修改代码时,不要忘记同时更新注释!
-
C++中有两种注释:单行注释和界定符对注释。单行注释以双斜线(//)开始,以换行符结束。当前行双斜线右侧的所有内容都会被编译器忽略,这种注释可以包含任何文本,包括额外的双斜线。另一种注释使用继承自C语言的两个界定符(/*和*/)。这种注释以/*开始,以*/结束,可以包含除* /外的任意内容,包括换行符。编译器将落在/*和*/之间的所有内容都当作注释。程序中通常同时包含两种形式的注释。注释界定符对通常用于多行解释,而双斜线注释常用于半行和单行附注。
-
-
控制流
- 语句一般是顺序执行的:语句块的第一条语句首先执行,然后是第二条语句,依此类推。但程序设计语言提供了多种不同的控制流语句,允许我们写出更为复杂的执行路径。
-
while语句反复执行一段代码,直至给定条件为假为止。我们可以用while语句编写一段程序,求1到10这10个数之和:
-
int sum = 0, val = 0;while (val <= 10){sum += val++;}std::cout << "1-10之和:" << sum << std::endl;return 0;
-
-
while 语句的执行过程是交替地检测condition条件和执行关联的语句statement,直至condition为假时停止。所谓条件(condition)就是一个产生真假的结果表达式。只要condition为真,statement 就会被执行。当执行完statement,会再次检测condition,如果condition仍为真,statement再次被执行。while 语句持续地交替检测condition和执行statement,直至condition为假为止。
-
for语句:在我们的while循环例子中,使用了变量val来控制循环执行次数。我们在循环条件中检测val的值,在while循环体中将val递增。这种在循环条件中检测变量、在循环体中递增变量的模式使用非常频繁,以至于C++语言专门定义了第二种循环语句——for语句,来简化符合这种模式的语句。可以用for语句来重写从1加到10的程序:
-
int sum = 0;for (int val = 0; val <= 10; val++){sum += val;//这里注意一下,val不用自己做运算了}std::cout << "1-10之和:" << sum << std::endl;return 0;
-
每个for语句都包含两部分:循环头和循环体。循环头控制循环体的执行次数,它由部分组成:一个初始化语句(init-statement)、一个循环条件(condition)以及一个表达式( expression)。简要重述一下for循环的总体执行流程:
-
1.创建变量val,将其初始化为1。
-
2.检测val是否小于等于10。若检测成功,执行for循环体。若失败,退出循环,继续执行for循环体之后的第一条语句。
-
3.将val的值增加1。
-
4.重复第2步中的条件检测,只要条件为真就继续执行剩余步骤。
-
-
读取数量不定的输入数据
-
上文中,我们编写程序实现了1到10这10个整数求和。扩展此程序一个很自然的方向是实现对用户输入的一组数求和。在这种情况下,我们预先不知道要对多少个数求和,这就需要不断读取数据直至没有新的输入为止:
-
int sum = 0, val = 0;while (std::cin>>val){sum += val;}std::cout << "自定义输入之和:" << sum << std::endl;return 0;
-
当我们使用一个istream对象作为条件时,其效果是检测流的状态。如果流是有效的,即流未遇到错误,那么检测成功。当遇到文件结束符(end-of-file),或遇到一个无效输入时(例如读入的值不是一个整数),istream对象的状态会变为无效。处于无效状态的istream对象会使条件变为假。因此,我们的 while循环会一直执行直至遇到文件结束符(或输入错误)。while循环体使用复合赋值运算符将当前值加到sum上。一旦条件失败,while循环将会结束。我们将执行下一条语句,打印sum的值和一个endl。
-
当从键盘向程序输入数据时,对于如何指出文件结束,不同操作系统有不同的约定。在Windows系统中,输入文件结束符的方法是敲 Ctrl+Z(按住Ctrl键的同时按Z键),然后按 Enter或 Return键。在 UNIX系统中,包括Mac OS X系统中,文件结束符输入是用 Ctrl+D。
-
-
if语句
-
C++也提供了if语句来支持条件执行。我们可以用if语句写个程序,来统计在有序输入中每个值连续出现了多少次:
-
int val = 0, currval = 0;if (std::cin>>currval){int count = 1;while (std::cin >> val){if (val == currval){++count;}else{std::cout << currval << "出现的次数为:" << count << " 次" << std::endl;currval = val;count = 1;}}std::cout << currval << "出现的次数为:" << count << " 次" << std::endl;}return 0;
-
C++用=进行赋值,==作为相等运算符。两个运算符都可以出现在条件中。一个常见的错误是想在条件中使==(相等判断),却误用了=。
-
-
C++程序很大程度上是格式自由的,也就是说,我们在哪里放置花括号、缩进、注释以及换行符通常不会影响程序的语义。例如,花括号表示main函数体的开始,它可以放在main的同一行中;也可以像我们所做的那样,放在下一行的起始位置;还可以放在我们喜欢的其他任何位置。唯一的要求是左花括号必须是main的形参列表后第一个非空、非注释的字符。
-
类简介
-
在C++中,我们通过定义一个类(class)来定义自己的数据结构。一个类定义了一个类型,以及与其关联的一组操作。类机制是C++最重要的特性之一。实际上,C++最初的一个设计焦点就是能定义使用上像内置类型一样自然的类类型(class type)。为了使用类,我们需要了解三件事情:类名是什么?它是在哪里定义的?它支持什么操作?
-
如前所见,为了使用标准库设施,我们必须包含相关的头文件。类似的,我们也需要使用头文件来访问为自己的应用程序所定义的类。习惯上,头文件根据其中定义的类的名字来命名。我们通常使用.h作为头文件的后缀,但也有一些程序员习惯.H、.hpp或.hxx。标准库头文件通常不带后缀。编译器一般不关心头文件名的形式,但有的IDE对此有特定要求。
-
-
定义一个自己的类 sales_item类
-
Sales_item类的作用是表示一本书的总销售额、售出册数和平均售价。我们现在不关心这些数据如何存储、如何计算。为了使用一个类,我们不必关心它是如何实现的,只需知道类对象可以执行什么操作。每个类实际上都定义了一个新的类型,其类型名就是类名。因此,我们的sales_item类定义了一个名为sales_item 的类型。与内置类型一样,我们可以定义类类型的变量。当我们写下如下语句
sales_item item;
,是想表达 item是一个sales_item类型的对象。我们通常将“一个sales_item类型的对象”简单说成“一个sales_item对象”,或更简单的“一个sales_item”。 -
#ifndef SALESITEM_H #define SALESITEM_H #include <iostream> #include <string> class Sales_item { public:Sales_item(const std::string& book) :isbn(book), units_sold(0), revenue(0.0) {}Sales_item(std::istream& is) { is >> *this; }friend std::istream& operator>>(std::istream&, Sales_item&);friend std::ostream& operator<<(std::ostream&, const Sales_item&); public:Sales_item& operator+=(const Sales_item&); public:double avg_price() const;bool same_isbn(const Sales_item& rhs)const {return isbn == rhs.isbn;}Sales_item() :units_sold(0), revenue(0.0) {} public:std::string isbn;unsigned units_sold;double revenue; }; using std::istream; using std::ostream; Sales_item operator+(const Sales_item&, const Sales_item&); inline bool operator==(const Sales_item& lhs, const Sales_item& rhs) {return lhs.units_sold == rhs.units_sold && lhs.revenue == rhs.revenue && lhs.same_isbn(rhs); } inline bool operator!=(const Sales_item& lhs, const Sales_item& rhs) {return !(lhs == rhs); }inline Sales_item& Sales_item::operator +=(const Sales_item& rhs) {units_sold += rhs.units_sold;revenue += rhs.revenue;return *this; } inline Sales_item operator+(const Sales_item& lhs, const Sales_item& rhs) {Sales_item ret(lhs);ret += rhs;return ret; } inline istream& operator>>(istream& in, Sales_item& s) {double price;in >> s.isbn >> s.units_sold >> price;if (in)s.revenue = s.units_sold * price;elses = Sales_item();return in; } inline ostream& operator<<(ostream& out, const Sales_item& s) {out << s.isbn << "\t" << s.units_sold << "\t" << s.revenue << "\t" << s.avg_price();return out; } inline double Sales_item::avg_price() const {if (units_sold)return revenue / units_sold;elsereturn 0; } #endif
-
-
读写Sales_item
-
既然已经知道可以对 sales_item对象执行哪些操作,我们现在就可以编写使用类的程序了。例如,下面的程序从标准输入读入数据,存入一个sales_item对象中,然后将Sales_item 的内容写回到标准输出:
-
Sales_item book;std::cin >> book;std::cout << book << std::endl;
-
输入表示我们以每本99.99元的价格售出了10册书,而输出告诉我们总售出册数为10,总销售额为999.9元,而每册书的平均销售价格为99.99美元。
-
此程序以两个#include指令开始,其中一个使用了新的形式。包含来自标准库的头文件时,也应该用尖括号(<>)包围头文件名。对于不属于标准库的头文件,则用双引号(“”)包围。
-
-
Sales_item对象的加法
-
这里的“和”的概念与算数中的和是完全不一样的。对于 int,我们计算传统意义上的和——两个数值的算术加法结果。对于sales_item对象,我们用了一个全新的“和”的概念——两个sales_item对象的成员对应相加的结果。
-
初识成员函数
-
将两个sales_item对象相加的程序首先应该检查两个对象是否具有相同的工SBN。方法如下:
-
Sales_item book1, book2;std::cin >> book1 >> book2;if ( book1.isbn== book2.isbn){std::cout << "两书的ISBN相同可做加和计算,结果为:" << book1 + book2 << std::endl;return 0;}else{std::cerr << "输入错误,两书ISBN号需要相同" << std::endl;return -1;}
-
此程序与上一版本的差别是if语句及其else分支。即使不了解这个if 语句的检测条件,我们也很容易理解这个程序在干什么。如果条件成立,如上一版本一样,程序打印计算结果,并返回0,表明成功。如果条件失败,我们执行跟在else之后的语句块,打印一条错误信息,并返回一个错误标识。使用点运算符(.)来表达我们需要“名为item1的对象的isbn成员”。点运算符只能用于类类型的对象。其左侧运算对象必须是一个类类型的对象,右侧运算对象必须是该类型的一个成员名,运算结果为右侧运算对象指定的成员。当用点运算符访问一个成员函数时,通常我们是想(效果也确实是)调用该函数。我们使用调用运算符(())来调用一个函数。调用运算符是一对圆括号,里面放置实参argument)列表(可能为空)。
-
-
以上的C++语言的知识,以使你能够编译、运行简单的C++程序。我们看到了如何定义一个main函数,它是操作系统执行你的程序的调用入口。我们还看到了如何定义变量,如何进行输入输出,以及如何编写if、for和 while语句。我们看到了,对于其他人定义的一-个类,我们应该如何创建、使用其对象。