第二章 进入C++
printf与cout有什么区别?
iostream文件是什么?
int main()也是一个函数,但它的返回值呢?
main函数的返回值能不能不是int,而是其他的呢?
为什么main()不能使用其他名称?
我们常常说的“实现”,到底是什么意思?
为什么变量必须声明?
2.1 进入C++
1、C++对大小写敏感,也就是说区分大写字符和小写字符。
2、.cpp是最常用的后缀名,也可以使用其他的
// myfirst.cpp -- displays a message
#include <iostream> // a PREPROCESSOR directive
int main() // function header
{ // start of function body
using namespace std; // make definitions visible
cout << "Come up and C++ me some time."; // message
cout << endl; // start a new line
cout << "You won’t regret it!" << endl; // more output
return 0; // terminate main()
}
有些窗口环境在独立的窗口中运行程序,并在程序运行完毕后自动关闭该窗口,就是说我们可能根本看不出来有没有运行,解决方法是手动添加:
cin.get();
用来阻塞程序
运行结果:
Come up and C++ me some time.
You won’t regret it!
C语言输入和输出
C++能够使用printf()、scanf()和其他所有标准C输入和输出函数,只需要包含常规C语言的stdio.h文件。
您使用函数来创建C++程序。通常,设计独立的函数来处理这些任务。示例中只包含一个名为main()的函数。myfirst.cpp示例包含下述元素。
- 注释,由前缀//标识。
- 预处理器编译指令#include。
- 函数头:int main()。
- 编译指令using namespace。
- 函数体,用{和}括起。
- 使用C++的cout工具显示消息的语句。
- 结束main()函数的return语句。
2.1.1 main() 函数
去掉修饰后,示例中的代码如下:
int main()
{
statements
return 0;
}
这几行代码构成了函数定义(function definition)。
第一行int main()叫函数头(function heading),函数头对函数与程序其他部分之间的接口进行了总结。
花括号({和})中包括的部分叫函数体。
函数体是指出函数应做什么的计算机指令。
在C++中,每条完整的指令都称为语句,所有的语句都以分号结束。
main()中最后一条语句叫作返回语句(return statement),它结束该函数。
语句和分号
语句是要执行的操作。为理解源代码,编译器需要知道一条语句何时结束,另一条语句何时开始。有些语言使用语句分隔符。例如,FORTRAN通过行尾将语句分隔开来,Pascal使用分号分隔语句。在Pascal中,有些情况下可以省略分号,例如END前的语句后面,这种情况下,实际上并没有将两条语句分开。不过C++与C一样,也使用终止符(terminator),而不是分隔符。终止符是一个分号,它是语句的结束标记,是语句的组成部分,而不是语句之间的标记。结论是:在C++中,不能省略分号。
作为接口的函数头
C++句法要求main()函数的定义以函数头int main()开始。
C++中函数可被其他函数激活或调用,函数头描述了函数与调用它的函数之间的接口。main()被启动代码调用,而启动代码是由编译器添加到程序中的,是程序和操作系统之间的桥梁。事实上,该函数头描述的是main()和操作系统之间的接口。
下面的函数头表明main()函数可以给调用它的函数返回一个整数值,且不从调用它的函数那里获得任何信息:
int main()
很多现有的程序都使用经典C函数头:
main() // original C style
在C语言中,省略返回类型相当于说函数的类型为int。C++淘汰了这种用法。
也可以使用下面的变体:
int main(void) // very explicit style
在括号中使用关键字void明确地指出,函数不接受任何参数。在C++(不是C)中,让括号空着与在括号中使用void等效(在C中,让括号空着意味着对是否接受参数保持沉默)。
有些程序员使用下面的函数头,并省略返回语句:
void main()
这在逻辑上是一致的,因为void返回类型意味着函数不返回任何值。该变体适用于很多系统,但由于它不是当前标准强制的一个选项,因此在有些系统上不能工作。
最后,如果main函数末尾没有返回语句,则默认return 0;
但仅在main函数中适用。而不适用于其他函数。
2.1.2 C++注释
C++注释以双斜杠(//)打头。注释是程序员为读者提供的说明,通常标识程序的一部分或解释代码的某个方面。编译器将忽略注释。
注释可以位于单独的一行上,也可以和代码位于同一行。
// myfirst.cpp -- displays a message
提示:应使用注释来说明程序。程序越复杂,注释的价值越大。注释不仅有助于他人理解这些代码,也有助于程序员自己理解代码,特别是隔了一段时间没有接触该程序的情况下。
作者最讨厌的四件事:
写注释,写文档,别人不写注释,别人不写文档!!
C风格注释
C++也能够识别C注释,C注释包括在符号/和/之间:
#include <iostream> /* a C-style comment */
由于C风格注释以*/结束,而不是到行尾结束,因此可以跨越多行。
但应尽量使用C++注释,因为这不涉及到结尾符号与起始符号的正确配对,所以它产生问题的可能性很小。事实上,C++标准也在C语言中添加了//注释。
2.1.3 C++预处理器和iostream文件
如果程序要使用C++输入或输出工具,请提供这样两行代码:
#include <iostream>
using namespace std;
C++和C一样,也使用一个预处理器,该程序在进行主编译之前对源文件进行处理。(有些C++实现使用翻译器程序将C++程序转换为C程序。虽然翻译器也是一种预处理器,但这里不讨论这种预处理器,而只讨论这样的预处理器,即它处理名称以#开头的编译指令)不必执行任何特殊的操作来调用该预处理器,它会在编译程序时自动运行。
#include <iostream> // a PREPROCESSOR directive
该编译指令导致预处理器将iostream文件的内容添加到程序中。这是一种典型的预处理器操作:在源代码被编译之前,替换或添加文本。
为什么要将iostream文件的内容添加到程序中呢?
答案涉及程序与外部世界之间的通信,iostream中的io指的是输入(进入程序的信息)和输出(从程序中发送出去的信息)。C++的输入/输出,涉及iostream文件中的多个函数的定义。为了使用cout来显示消息,第一个程序需要这些定义。#include编译指令导致iostream文件的内容随源代码文件的内容一起被发送给编译器。实际上,iostream文件的内容将取代程序中的代码行#include 。原始文件没有被修改,而是将源代码文件和iostream组合成一个复合文件,编译的下一阶段将使用该文件。
我尝试过将iostream文件直接复制到.cpp的文件中相应的部分,替代原来的#include <iostream>,也可以运行
2.1.4 头文件名
像iostream这样的文件叫作包含文件(include file)——由于它们被包含在其他文件中;也叫头文件(header file)——由于它们被包含在文件起始处。
C++编译器自带了很多头文件,每个头文件都支持一组特定的工具。C语言的传统是,头文件使用扩展名h,C++程序仍可以使用这种.h文件。有些C头文件被转换为C++头文件,这些文件被重新命名,去掉了扩展名h(使之成为C++风格的名称),并在文件名称前面加上前缀c,而C++头文件则没有扩展名。
头文件命名约定:
头文件类型 | 约定 | 示例 | 说明 |
---|---|---|---|
C++旧式风格 | 以.h结尾 | iostream.h | C++程序可以使用 |
C旧式风格 | 以.h结尾 | math.h | C、C++程序可以使用 |
C++新式风格 | 没有扩展名 | iostream | C++程序可以使用,使用namespace std |
转换后的C | 加上前缀c,没有扩展名 | cmath | C++程序可以使用,可以使用不是C的特性,如namespace std |
由于C使用不同的文件扩展名来表示不同文件类型,因此用一些特殊的扩展名(如.hpp或.hxx)表示C++头文件是有道理的
2.1.5 名称空间
如果使用iostream,而不是iostream.h,则应使用下面的名称空间编译指令来使iostream中的定义对程序可用:
using namespace std;
这叫作using编译指令。名称空间支持是一项C++特性,旨在让您编写大型程序以及将多个厂商现有的代码组合起来的程序时更容易,它还有助于组织程序。一个潜在的问题是,可能使用两个已封装好的产品,而它们都包含一个名为wanda()的函数。这样,使用wanda()函数时,编译器将不知道指的是哪个版本。名称空间让厂商能够将其产品封装在一个叫作名称空间的单元中,这样就可以用名称空间的名称来指出想使用哪个厂商的产品。
例如,两个函数名都是wanda的函数,但是由于身处在不同的名称空间中。可以区分调用不同的函数
Microflop::wanda("go dancing?"); // use Microflop namespace version
Piscine::wanda("a fish named Desire"); // use Piscine namespace version
意味着在iostream中定义的用于输出的cout变量实际上是std::cout,而endl实际上是std::endl。
std::cout << "Come up and C++ me some time.";
std::cout << std::endl;
然而,很多人不喜欢使用std::cout
这种写法,觉得麻烦,using编译指令应运而生。
using namespace std;
这个using编译指令使得std名称空间中的所有名称都可用。这是一种偷懒的做法,但是我喜欢。
在大型项目中还是一个潜在的问题。更好的方法是,只使所需的名称可用,这可以通过使用using声明来实现:
using std::cout; // make cout available
using std::endl; // make endl available
using std::cin; // make cin available
用这些编译指令替换下述代码后,便可以使用cin和cout,而不必加上std::前缀,然而,要使用iostream中的其他名称,必须将它们分别加到using列表中。
2.1.6 使用 cout 进行 C++输出
现在来看一看如何显示消息。
cout << "Come up and C++ me some time.";
双引号括起的部分是要打印的消息。
在C++中,用双引号括起的一系列字符叫作字符串
<<符号表示该语句将把这个字符串发送给cout;该符号指出了信息流动的路径。
从概念上看,输出是一个流,即从程序流出的一系列字符。cout对象表示这种流,其属性是在iostream文件中定义的。cout的对象属性包括一个插入运算符(<<),它可以将其右侧的信息插入到流中。请看下面的语句(注意结尾的分号):
cout << "Come up and C++ me some time.";
它将字符串“Come up and C++ me some time.”插入到输出流中。因此,与其说程序显示了一条消息,不如说它将一个字符串插入到了输出流中。(后者好理解一点)
初识运算符重载
大家可能注意到了,插入运算符(<<)看上去就像按位左移运算符(<<),这是一个运算符重载的例子,通过重载,同一个运算符将有不同的含义。编译器通过上下文来确定运算符的含义。C本身也有一些运算符重载的情况。例如,&符号既表示地址运算符,又表示按位AND运算符;* 既表示乘法,又表示对指针解除引用。这里重要的不是这些运算符的具体功能,而是同一个符号可以有多种含义,而编译器可以根据上下文来确定其含义。C++扩展了运算符重载的概念,允许为用户定义的类型(类)重新定义运算符的含义。
控制符endl
cout << endl;
endl是一个特殊的C++符号,表示一个重要的概念:重起一行。
在输出流中插入endl将导致屏幕光标移到下一行开头。打印字符串时,cout不会自动移到下一行。
诸如endl等对于cout来说有特殊含义的特殊符号被称为控制符(manipulator)。
换行符
C++还提供了另一种在输出中指示换行的旧式方法:C语言符号\n:
cout << "What’s next?\n"; // \n means start a new line
\n被视为一个字符,名为换行符。
显示字符串时,在字符串中包含换行符,而不是在末尾加上endl,可减少输入量:
cout << "Pluto is a dwarf planet.\n"; // show text, go to next line
cout << "Pluto is a dwarf planet." << endl; // show text, go to next line
另一方面,如果要生成一个空行,则两种方法的输入量相同,但对大多数人而言,输入endl更为方便(因为全是英文字母,输起来顺手):
cout << "\n"; // start a new line
cout << endl; // start a new line
显示用引号括起的字符串时,通常使用换行符\n,在其他情况下则使用控制符endl。一个差别是,endl确保程序继续运行前刷新输出(将其立即显示在屏幕上);而使用“\n”不能提供这样的保证,这意味着在有些系统中,有时可能在您输入信息后才会出现提示。
2.1.7 C++源代码的格式化
有些语言(如Python)是面向行的,即每条语句占一行。对于这些语言来说,回车的作用是将语句分开。然而,在C++中,分号标示了语句的结尾。因此,在C++中,回车的作用就和空格或制表符相同。这说明既可以把一条语句放在几行上,也可以把几条语句放在同一行上。
#include <iostream>
int
main
() { using
namespace
std; cout
<<
"Come up and C++ me some time."
; cout <<
endl; cout <<
"You won’t regret it!" <<
endl;return 0; }
这样虽然不太好看,但仍然是合法的代码。必须遵守一些规则,具体地说,在C和C++中,不能把空格、制表符或回车放在元素(比如名称)中间,也不能把回车放在字符串中间。
源代码中的标记和空白
一行代码中不可分割的元素叫作标记,通常,必须用空格、制表符或回车将两个标记分开,空格、制表符和回车统称为空白。
C++源代码风格
虽然C++在格式方面赋予了您很大的自由,但如果遵循合理的风格,程序将更便于阅读。有效但难看的代码不会令人满意。它遵循了下述规则。
- 每条语句占一行。
- 每个函数都有一个开始花括号和一个结束花括号,这两个花括号各占一行。
- 函数中的语句都相对于花括号进行缩进。
- 与函数名称相关的圆括号周围没有空白。
前三条规则旨在确保代码清晰易读;第四条规则帮助区分函数和一些也使用圆括号的C++内置结构
2.2 C++语句
C++程序是一组函数,而每个函数又是一组语句。
2.2.1 声明语句和变量
计算机是一种精确的、有条理的机器。要将信息项存储在计算机中,必须指出信息的存储位置和所需的内存空间。在C++中,完成这种任务的一种相对简便的方法,是使用声明语句来指出存储类型并提供位置标签。
int carrots;
这条语句提供了两项信息:需要的内存以及该内存单元的名称
这条语句指出程序需要足够的存储空间来存储一个整数,在C++中用int表示整数。编译器负责分配和标记内存的细节。
完成的第二项任务是给存储单元指定名称。在这里,该声明语句指出,此后程序将使用名称carrots来标识存储在该内存单元中的值。carrots被称为变量,因为它的值可以修改。
程序中的声明语句叫作定义声明(defining declaration)语句,简称为定义(definition)。这意味着它将导致编译器为变量分配内存空间。
提示:对于声明变量,C++的做法是尽可能在首次使用变量前声明它。
2.2.2 赋值语句
赋值语句将值赋给存储单元。
carrots = 25;
符号=叫作赋值运算符。C++(和C)有一项不寻常的特性——可以连续使用赋值运算符。
int steinway;
int baldwin;
int yamaha;
yamaha = baldwin = steinway = 88;
赋值将从右向左进行。
可以对变量的值进行修改:
carrots = carrots - 1; // modify the variable
2.2.3 cout的新花样
int carrots =25;
cout << carrots;
首先,cout将carrots替换为其当前值25;然后,把值转换为合适的输出字符。
如上所示,cout可用于数字和字符串。但别忘了,整数25与字符串“25”有天壤之别。该字符串存储的是书写该数字时使用的字符,即字符2和5。程序在内部存储的是字符2和字符5的编码。要打印字符串,cout只需打印字符串中各个字符即可。但整数25被存储为数值,计算机不是单独存储每个数字,而是将25存储为二进制数。cout必须将整数形式的数字转换为字符串形式。另外,cout很聪明,知道carrots是一个需要转换的整数。
与老式C语言的区别在于cout的聪明程度。在C语言中,要打印字符串“25”和整数25,可以使用C语言的多功能输出函数printf():
printf("Printing a string: %s\n", "25");
printf("Printing an integer: %d\n", 25);
撇开printf()的复杂性不说,必须用特殊代码(%s和%d)来指出是要打印字符串还是整数。如果让printf()打印字符串,但又错误地提供了一个整数,由于printf()不够精密,因此根本发现不了错误。它将继续处理,显示一堆乱码。
cout的智能行为源自C++的面向对象特性。实际上,C++插入运算符(<<)将根据其后的数据类型相应地调整其行为,这是一个运算符重载的例子。
2.3 其他 C++语句
再来看几个C++语句的例子
// getinfo.cpp -- input and output
#include <iostream>
int main()
{
using namespace std;
int carrots;
cout << "How many carrots do you have?" << endl;
cin >> carrots; // C++ input
cout << "Here are two more. ";
carrots = carrots + 2;
// the next line concatenates output
cout << "Now you have " << carrots << " carrots." << endl;
return 0;
}
如果您发现在以前的程序清单中需要添加cin.get(),则在这个程序清单中,需要添加两条cin.get()语句,这样才能在屏幕上看到输出。第一条cin.get()语句在您输入数字并按Enter键时读取输入,而第二条cin.get()语句让程序暂停,直到您按Enter键。
下面是该程序的运行情况:
How many carrots do you have?
12
Here are two more. Now you have 14 carrots.
该程序包含两项新特性:用cin来读取键盘输入以及将四条输出语句组合成一条。
2.3.1 使用 cin
cin >> carrots;
从这条语句可知,信息从cin流向carrots。像C++将输出看作是流出程序的字符流一样,它也将输入看作是流入程序的字符流。iostream文件将cin定义为一个表示这种流的对象。输出时,<<运算符将字符串插入到输出流中;输入时,cin使用>>运算符从输入流中抽取字符。通常,需要在运算符右侧提供一个变量,以接收抽取的信息(符号<<和>>被选择用来指示信息流的方向)。
与cout一样,cin也是一个智能对象。它可以将通过键盘输入的一系列字符(即输入)转换为接收信息的变量能够接受的形式。
2.3.2 使用cout 进行拼接
getinfo.cpp中的另一项新特性是将4条输出语句合并为一条。iostream文件定义了<<运算符,以便可以像下面这样合并(拼接)输出:
cout << "Now you have " << carrots << " carrots." << endl;
这样能够将字符串输出和整数输出合并为一条语句。得到的输出与下述代码生成的相似:
cout << "Now you have ";
cout << carrots;
cout << " carrots.";
cout << endl;
根据有关cout的建议,也可以按照这样的方式重写拼接版本,即将一条语句放在4行上:
cout << "Now you have "
<< carrots
<< " carrots."
<< endl;
这是由于C++的自由格式规则将标记间的换行符和空格看作是可相互替换的。
需要注意的另一点是:
Now you have 14 carrots.
和
Here are two more.
在同一行中。
这是因为前面指出过的,cout语句的输出紧跟在前一条cout语句的输出后面。
2.3.3 类简介
类是用户定义的一种数据类型。要定义类,需要描述它能够表示什么信息(属性)和可对数据执行哪些操作(行为)。也就是说,类定义描述的是数据格式及其用法,而对象则是根据数据格式规范创建的实体。
现在来看cout。它是一个ostream类对象。ostream类定义(iostream文件的另一个成员)描述了ostream对象表示的数据以及可以对它执行的操作,如将数字或字符串插入到输出流中。同样,cin是一个istream类对象,也是在iostream中定义的。
注意:
类描述了一种数据类型的全部属性(包括可使用它执行的操作),对象是根据这些描述创建的实体。
知道类是用户定义的类型,但作为用户,并没有设计ostream和istream类。就像函数可以来自函数库一样,类也可以来自类库。ostream和istream类就属于这种情况。从技术上说,它们没有被内置到C++语言中,而是语言标准指定的类。这些类定义位于iostream文件中,没有被内置到编译器中。如果愿意,程序员甚至可以修改这些类定义(不建议这样乱搞),iostream系列类和相关的fstream(或文件I/O)系列类是早期所有的实现都自带的唯一两组类定义。
类描述指定了可对类对象执行的所有操作。要对特定对象执行这些允许的操作,需要给该对象发送一条消息。
C++提供了两种发送消息的方式:一种方式是使用类方法,另一种方式是重新定义运算符,cin和cout采用的就是这种方式。
cout << "I am not a crook."
在这个例子中,消息带一个参数——要显示的字符串
2.4 函数
由于函数用于创建C++程序的模块,对C++的OOP定义至关重要,C++函数分两种:有返回值的和没有返回值的。
2.4.1 使用有返回值的函数
有返回值的函数将生成一个值,而这个值可赋给变量或在其他表达式中使用。
x = sqrt(6.25); // returns the value 2.5 and assigns it to x
表达式sqrt(6.25)将调用sqrt()函数。表达式sqrt(6.25)被称为函数调用,被调用的函数叫作被调用函数(called function),包含函数调用的函数叫作调用函数。
参数是发送给函数的信息,返回值是从函数中发送回去的值。
情况基本上就是这样,只是在使用函数之前,C++编译器必须知道函数的参数类型和返回值类型。
注意:
C++程序应当为程序中使用的每个函数提供原型。
函数原型之于函数就像变量声明之于变量——指出涉及的类型。
sqrt()的函数原型像这样:
double sqrt(double); // function prototype
第一个double意味着sqrt()将返回一个double值。括号中的double意味着sqrt()需要一个double参数。因此该原型对sqrt()的描述和下面代码中使用的函数相同:
double x; // declare x as a type double variable
x = sqrt(6.25);
原型结尾的分号表明它是一条语句,这使得它是一个原型,而不是函数头。如果省略分号,编译器将把这行代码解释为一个函数头,并要求接着提供定义该函数的函数体。
在程序中使用sqrt()时,也必须提供原型。可以用两种方法来实现:
- 在源代码文件中输入函数原型;
- 包含头文件cmath(老系统为- math.h),其中定义了原型。
第二种方法更好,因为头文件更有可能使原型正确。
不要混淆函数原型和函数定义
可以看出,原型只描述函数接口。也就是说,它描述的是发送给函数的信息和返回的信息。而定义中包含了函数的代码,如计算平方根的代码。
应在首次使用函数之前提供其原型
// sqrt.cpp -- using the sqrt() function
#include <iostream>
#include <cmath> // or math.h
int main()
{
using namespace std;
double area;
cout << "Enter the floor area, in square feet, of your home: ";
cin >> area;
double side;
side = sqrt(area);
cout << "That’s the equivalent of a square " << side
<< " feet to the side." << endl;
cout << "How fascinating!" << endl;
return 0;
}
2.4.2 函数变体
有些函数需要多项信息。这些函数使用多个参数,参数间用逗号分开。
double pow(double, double);
另外一些函数不接受任何参数。
int rand(void);
关键字void明确指出,该函数不接受任何参数。如果省略void,让括号为空,则C++将其解释为一个不接受任何参数的隐式声明。
还有一些函数没有返回值。
void bucks(double);
由于它不返回值,因此不能将该函数调用放在赋值语句或其他表达式中。
在有些语言中,有返回值的函数被称为函数(function);没有返回值的函数被称为过程(procedure)或子程序(subroutine)。但C++与C一样,这两种变体都被称为函数。
2.4.3 用户定义的函数
用户经常需要编写自己的函数,尤其是在设计类的时候。
函数格式
type functionname(argumentlist)
{
statements
}
函数头
void simon(int n)
开头的void表明simon()没有返回值,括号中的int n表明,使用simon()时,应提供一个int参数。
关键字
关键字是计算机语言中的词汇。本章使用了int、void、return、double等C++关键字。由于这些关键字都是C++专用的,因此不能用作他用。也就是说,不能将return用作变量名,也不能把double用作函数名。不过可以把它们用作名称的一部分,如painter(其中包含int)或return_aces。
2.4.4 用户定义的有返回值的函数
我们再深入一步,编写一个使用返回语句的函数。main()函数已经揭示了有返回值的函数的格式:在函数头中指出返回类型,在函数体结尾处使用return。
函数原型描述了函数接口,即函数如何与程序的其他部分交互。参数列表指出了何种信息将被传递给函数,函数类型指出了返回值的类型。程序员有时将函数比作一个由出入它们的信息所指定的黑盒子(black boxes)(电工用语)。函数原型将这种观点诠释得淋漓尽致
函数stonetolb()短小、简单,但包含了全部的函数特性:
- 有函数头和函数体;
- 接受一个参数;
- 返回一个值;
- 需要一个原型。
可以把stonetolb()看作函数设计的标准格式。
2.4.5 在多函数程序中使用 using编译指令
using namespace std;
如果多个函数使用了cout,因此需要能够访问位于名称空间std中的cout定义。但只让需要访问名称空间std的函数访问它是更好的选择。
总之,让程序能够访问名称空间std的方法有多种,下面是其中的4种。
- 将using namespace std;放在函数定义之前,让文件中所有的函数都能够使用名称空间std中所有的元素。
- 将using namespace std;放在特定的函数定义中,让该函数能够使用名称空间std中的所有元素。
- 在特定的函数中使用类似using std::cout;这样的编译指令,而不是using namespace std;,让该函数能够使用指定的元素,如cout。
- 完全不使用编译指令using,而在需要使用名称空间std中的元素时,使用前缀std::,如下所示:
std::cout << "I’m using cout and endl from the std namespace" << std::endl;
命名约定
C++程序员给函数、类和变量命名时,可以有很多种选择。程序员对风格的观点五花八门,这些看法有时就像公共论坛上的圣战。就函数名称而言,程序员有以下选择:
Myfunction()
myfunction()
myFunction()
my_function()
my_funct()
选择取决于开发团体、使用的技术或库以及程序员个人的品位和喜好。
个人的命名风格也是值得注意的——它有助于保持一致性和精确性。精确、让人一目了然的个人命名约定是良好的软件工程的标志,所以尽量让你的代码写的像诗一样!!
小思考🤔️
printf与cout有什么区别?
如果已经习惯了C语言和printf(),可能觉得cout看起来很奇怪。程序员甚至可能固执地坚持使用printf()。但与使用所有转换说明的printf()相比,cout的外观一点也不奇怪。更重要的是,cout还有明显的优点。它能够识别类型的功能表明,其设计更灵活、更好用。另外,它是可扩展的(extensible)。也就是说,可以重新定义<<运算符,使cout能够识别和显示所开发的新数据类型。如果喜欢printf()提供的细致的控制功能,可以使用更高级的cout来获得相同的效果。
总的来说:printf功能单一,cout使用便捷,且可对<<进行重载,实现更多种数据类型的输出
iostream文件是什么?
iostream 是C++标准库中的头文件,用于输入和输出流操作。它包含了许多类和函数,用于处理输入和输出数据。以下是一些主要的内容:
cin 和 cout: iostream 提供了 cin 和 cout
这两个标准输入输出流对象,分别用于从键盘读取输入和向屏幕输出数据。例如,cin 可用于接受用户的输入,而 cout
可用于将数据输出到控制台。
输入和输出操作符 (<< 和 >>): iostream 中定义了用于输入和输出的操作符 << 和 >>。您可以使用这些操作符将数据发送到输出流或从输入流中读取数据。
其他流对象: 除了 cin 和 cout,iostream 还提供了其他流对象,如 cerr(标准错误流)和 clog(标准日志流),用于错误信息和日志记录。
文件流 (ifstream 和 ofstream): iostream 还包含了用于文件输入和输出的类,如 ifstream(文件输入流)和
ofstream(文件输出流),它们使您能够读取和写入文件。
iostream 是C++标准库的一部分,它简化了输入和输出操作,并提供了灵活的方式来处理不同类型的数据流。通过包含 iostream
头文件,您可以在C++程序中使用这些流对象和相关函数,以进行输入和输出操作。
int main()也是一个函数,但它的返回值呢?
下面复习一下main()的函数头:
int main()
开头的int表明,main()返回一个整数值;空括号(其中可以包含void)表明,main()没有参数。对于有返回值的函数,应使用关键字return来提供返回值,并结束函数。这就是要在main()结尾使用下述语句的原因:
return 0;
这在逻辑上是一致的:main()返回一个int值,而程序员要求它返回整数0。但可能会产生疑问,将这个值返回到哪里了呢?毕竟,程序中没有哪个地方可以看出对main()的调用:
squeeze = main(); // absent from our programs
答案是,可以将计算机操作系统(如UNIX或Windows)看作调用程序。因此,main()的返回值并不是返回给程序的其他部分,而是返回给操作系统。很多操作系统都可以使用程序的返回值。例如,UNIX外壳脚本和Windows命令行批处理文件都被设计成运行程序,并测试它们的返回值(通常叫作退出值)。通常的约定是,退出值为0则意味着程序运行成功,为非零则意味着存在问题。因此,如果C++程序无法打开文件,可以将它设计为返回一个非零值。然后,便可以设计一个外壳脚本或批处理文件来运行该程序,如果该程序发出指示失败的消息,则采取其他措施。
main函数的返回值能不能不是int,而是其他的呢?
标准C++规定 main 函数的返回值类型必须是 int,这是因为 main 函数的返回值通常用于指示程序的退出状态。一般情况下,返回 0
表示程序正常退出,非零值则表示程序异常退出,这个非零值通常用于指示错误码或异常状态。例如:
int main() {
// 主程序逻辑
return 0; // 表示程序正常退出
}
然而,根据C++标准,C++11之后的版本允许 main 函数的返回值类型是 void,但这种情况下程序的退出状态将默认为0。例如:
void main() {
// 主程序逻辑
// 程序默认正常退出
}
虽然允许返回 void,但这并不是一个通用的做法,通常还是建议使用 int
类型的返回值来表示程序的退出状态。如果需要返回其他类型的值,可以通过全局变量或其他方式来传递额外的信息。
为什么main()不能使用其他名称?
通常,C++程序必须包含一个名为main()的函数(不是Main()、MAIN()或mane()。记住,大小写和拼写都要正确)。由于myfirst.cpp程序只有一个函数,因此该函数必须担负起main()的责任。在运行C++程序时,通常从main()函数开始执行。因此,如果没有main(),程序将不完整,编译器将指出未定义main()函数。
也存在一些例外情况。例如,在Windows编程中,可以编写一个动态链接库(DLL)模块,这是其他Windows程序可以使用的代码。由于DLL模块不是独立的程序,因此不需要main()。用于专用环境的程序——如机器人中的控制器芯片——可能不需要main()。有些编程环境提供一个框架程序,该程序调用一些非标准函数,如_tmain()。在这种情况下,有一个隐藏的main(),它调用_tmain()。但常规的独立程序都需要main(),本书讨论的都是这种程序。
我们常常说的“实现”,到底是什么意思?
在C++中,“实现”
通常指的是将类或函数的定义具体实现为可执行的代码。这包括编写函数体、方法的具体实现、成员变量的初始化和操作、类的构造函数和析构函数的定义等等。实现是代码的具体部分,它使类、函数或模块能够执行其设计的功能。
举例来说,当你定义一个类(例如一个名为 Person的类),你可以在类的声明中指定其成员函数的原型和成员变量,但实际的函数体和操作必须在实现中编写。这个实现通常包含在一个独立的源代码文件中,例如一个 .cpp 文件,而不是在类的声明中。
在C++中,通常将类的声明放在头文件(.h 或 .hpp)中,而将类的实现放在源文件(.cpp)中。这种分离允许编译器将类的声明和实现分开处理,同时也使代码更易于维护和重用。
总之,“实现” 在C++中指的是将代码的抽象描述转化为可执行的具体代码部分,以实现类、函数、方法等的功能。
为什么变量必须声明?
有些语言(最典型的是BASIC)在使用新名称时创建新的变量,而不用显式地进行声明。这看上去对用户比较友好,事实上从短期上说确实如此。问题是,如果错误地拼写了变量名,将在不知情的情况下创建一个新的变量。在BASIC中,ss程序员可能编写如下语句:
CastleDark = 34
...
CastleDank = CastleDark + MoreGhosts
...
PRINT CastleDark
由于CastleDank是拼写错误(将r拼成了n),因此所作的修改实际上并没有修改CastleDark。这种错误很难发现,因为它没有违反BASIC中的任何规则。然而,在C++中,将声明CastleDark,但不会声明被错误拼写的CastleDank,因此对应的C++代码将违反“使用变量前必须声明它”的规则,因此编译器将捕获这种错误,发现潜在的问题。
因此,声明通常指出了要存储的数据类型和程序对存储在这里的数据使用的名称。