C++初探 2(初涉C++)

目录

注:

进入C++

main()函数

C++注释

C++预处理器和iostream文件

头文件名

名称空间

使用cout进行C++输出

C++源代码的格式化

C++语句

声明语句和变量

赋值语句

cout的新用法

其他C++语句

类简介

函数

使用有返回值的函数

函数变体

用户定义的函数

用户定义的有返回值的函数

在多函数程序中使用using编译指令

添加内容


注:

        本笔记参考:《C++ PRIMER PLUS》(第6版)


进入C++

注:编译器是大小写敏感并且拼写敏感的。

例子:一份程序清单。

#include<iostream>
int main()
{
	using namespace std;
	cout << "Come up and C++ me some time.";    //虽然也可以使用printf函数,但此处使用C++的输入函数。
	cout << endl;
	cout << "You won't regret it!" << endl;
	return 0;
}

顺便一提,如果程序在打开后的瞬间直接关闭,为了解决这种情况,可以在return语句前使用:

cin.get();

程序的输出结果:

分析:

        上述的C++程序中存在这些元素:

代码解释
前缀 //注释
#include预处理器编译指令
int main()函数头
using namespace

                       编译指令

( namespace 对应的就是标识符的各种指示范围,用来控制标识符的生效范围)

{ }被花括号括起来的部分即为函数体
coutC++中显示消息的语句
return用来解释main()函数的语句

        接下来将较为详细地解释这些元素。


main()函数

        去掉修饰后,上述程序的基本程序是:

int main()
{
    //各种修饰

    return 0;
}

语句的概念:每条完整的指令都被称为语句

        首先,先了解函数定义的组成:

        函数头:即第一行的 int main()

        函数体:即花括号中包括的部分。(其中 return 0; 被称为结束函数,对应main()的最后一条语句——返回语句)

        接下来再看看函数头和函数体的解释:

  • 函数头:对函数与程序其他部分之间进行了总结,描述了函数与调用它的函数之间的接口。
  • 函数体:指出函数应做什么的计算机指令

作为接口的函数头

        在C++中,要求main()函数的定义以int main()开始。

        通常,一个函数头的组成形如:

  1. 函数返回类型:描述从函数返回给调用它的函数的信息。
  2. 形参列表:描述从调用函数传递给被调用函数的信息。

但这样的格式放到main()中时就会有点奇怪,因为通常不会存在从程序的其它部分调用main()。

        这是因为:通常,main()被启动代码调用,而启动代码是由编译器添加进程序中的,是程序与操作系统之间的“桥梁”。其实,main()的函数头就是在描述main()和操作系统之间的接口。

        简而言之,函数头:

int main()

表示给调用它的函数返回一个整数,且不从调用它的函数那里获得任何信息。

        这个函数头还存在变体:

void main()

冷知识:在C语言中,如果省略返回类型,相当于函数的类型是 int 。不过这种写法逐渐被C++淘汰了。

使用这个函数头可以省略返回语句。但由于该变体不是标准强制的,所以在一些系统上是无法工作的。(ps:ANSI/ISO C++最终还是做出了让步。如果编译器检测到main()函数末尾未出现返回语句,则自动认为存在一个 return 0;

        通常,C++的程序中必须包含一个名为main()的函数。当然,存在一些特殊情况,如:在Windows中,可以编写一个动态链接库(DDL),这是其他Windows程序可以使用的代码。由于DLL不是独立的程序,因此不需要main()。


C++注释

        C++的注释以双斜杠(//)打头,到行尾结束。注释的存在是为读者提供说明。

实际上,预编译器在预处理阶段就会清除这些注释。

        应使用注释说明程序,程序越复杂,注释就越重要。因为这不仅是帮助他人理解代码,也有助于程序员自己理解代码。


C++预处理器和iostream文件

        在需要使用C++输入或者输出时,可以使用:

#include<iostream>    //iostream这个文件内涉及的内容就是程序与外部之间的通信
using namespace std;

        C++也存在预处理器,在编译程序时,预处理器会自行启动。

        #include<iostream>  ,这条编译指令会让预处理器将iostream文件的内容添加到程序内。学过C语言后,对这些应该都有稍微涉猎。


头文件名

        像 iostream 这样的文件被称为包含文件(include file),原因是:它们被包含在其他文件中。也被称为头文件(header file),原因是:它们被包含在文件起始处。

        在C语言,同样存在着名为头文件的文件,它们大多都有一致的 扩展名h  。诞生C++中不再使用这种用法,尽管C语言仍然保留有 扩展名h ,但是C++的头文件是没有扩展名的

        这些原本来自C语言的库在移植到C++的过程中去掉了 扩展名h ,取而代之的是 前缀c (表明这个库来自C语言),例如:C语言版本的 math.h 变成了 cmath 。

        对于纯粹来自C++的头文件(如iostream)来说,去掉h不只是形式上的改变,更重要的是:没有h的头文件也可以包含名称空间

        总结

头文件风格约定示例说明
C++(旧式)以.h结尾iostram.hC++程序可以使用
C(旧式)以.h结尾math.hC、C++程序可以使用
头文件风格约定示例说明
C++(新式)没有扩展名iostramC++程序可以使用,使用namespace std
转换后的C加上前缀c,没有扩展名cmath

C++程序可以使用,可以使用不是C的特性,如:namespace std。


名称空间

        如果使用iostream,而不是iostream.h,那么要使iostream中的定义对程序有用,就需要这样的名称空间编译指令:

using namespace std;

        这叫做using编译指令。

        名称空间支持是一项C++特性,这个特性便于:①编写大型程序;②编写组合多个厂商的代码的程序;③组织程序。

        之所以会存在这样的特性,是由于C++的广泛使用和模块化的使用方式:有时候,我们会发现自己现在组织的程序要调用来自不同厂商的产品。此时,这两个产品中存在用同一个函数名命名的函数,如果就这么使用这个函数,那么到底应该调用那个函数呢?

        所以在C++中,会存在名称空间,不同的名称空间单元内会被封装进不同厂商的产品,这样就可以用名称空间的名称来指定想要使用的产品了。举个例子,现在存在一个被不同产品定义的wanda()函数:

        Microflop Industries 将产品定义放到应该名为Microflop的名称空间内。这样,其wanda()函数的全称就是Microflop::wanda()。

        Piscine公司的wanda()版本就是Pscine::wanda()。

        接下来是使用:

Microflop::wanda("go dancing");
Piscine::wanda("123123");

        按照这种方式,类、函数、变量都被放在了名称空间std内。而在之前说明过的输出变量cout实际上就是 std::cout ,endl实际上就是 std::endl 。所以如果不想使用编译指令using,可以这样:

std::cout << "Come up and C++ me some time."
std::cout <<std::endl;

        所以,类似于 using namespace std; 这种定义形式,实际上是为了方便输入而存在的。但是在大型项目中,这种直接使用整个std空间进行定义的方式存在隐患,此时定义所需名称才是更好的选择:

using std::cout;
using std::endl;

使用cout进行C++输出

cout << "Come up and C++ me some time.";
  • 双引号 括起来的部分是要打印的信息。在C++中,和C语言类似地,用双引号括起来的部分被称为字符串。
  • <<符号 指出了信息流动的路径,在上述语句中,表示将字符串发送给cout。
  • cout 是一个预定义的对象,可以显示字符串、数字和单个字符等等。(对象是类的特定实例,而类定义了数据的存储和使用方式)

        上述演示告诉了我们对象的长处之一:不了解对象的内部情况也可以使用它。我们需要知道的只有对象的接口即可。

在C++中,理解上述代码的过程:

  1. 从概念上看,输出是一个流,即从程序中流出的一系列字符。
  2. cout对象表示这种流,其属性是在iostream中定义的。
  3. cout的对象属性包括一个插入运算符(<<)(这个运算符的作用是将其右侧的信息插入到输出流中)

初识运算符重载

        如果有学习C的经验,会发现插入运算符(<<)看起来就像按位左移运算符(<<),这就是一个运算符重载的例子。重载能使同一个运算符拥有不同的定义。编译器通过上下文来确定运算符的定义。

        在C中也有类似的例子,例如:&即表示地址运算符,也表示AND运算符。

        C++扩展了运算符重载的概念,允许用户定义的类型(类)重新定义运算符的含义。

1. 控制符endl

cout << endl

        endl是一个特殊的C++符号,表示一个重要的概念:重启一行。在输出流中插入endl将导致屏幕光标移到下一行开头。诸如endl等对于cout来说有特殊含义的特殊符号被称为控制符。endl也在头文件iostream中被定义,且位于名称空间std内。

使用例:

int main()
{
	using namespace std;
	cout << "Hello";
	cout << "World,";

	cout << endl;

	cout << "Hello ";
	cout << "C++.";
	return 0;
}

代码的执行结果:

2. 换行符

        C++中也可以使用C语言的换行方式:符号\n :

cout << "Hello\n";
cout <<"World.";

才是 \n 被视为一个字符,即换行符。

        一般而言,如果要显示字符串,那么换行符与endl相比,前这可以减少输入量。但如果要生成一个空行,对大多数人而言,还是endl来得方便。

        注意:endl 和 换行符\n 存放一个差别 —— endl确保重新继续运行前刷新输出(将其立即显示在屏幕上);而 “\n” 不能提供这样的保证,在某些系统中,可能需要在输入信息后,才会出现提示。


C++源代码的格式化

        对于类似于python的语言而言,回车的作用是分开语句。但在C++中,分号已经标示了语句的句尾。因此,在C++中,回车的作用就类似于空格和制表符。

        对C++而言,必须遵守的规则具体来说就是: 不能把空格、制表符或者回车放在元素(比如名称)中间, 也不能把回车放在字符串中间。反面例子:

int ma in()    //在名称中间存在空格

re
turn 0;    //在语句中存在回车

cout << "Behold the Beans
 of Beauty!";    //在字符串中存在回车

ps:不过C++11新增的原始(raw)字符串可包含回车。

源代码中的标记和空白

        一行代码中不可分割的元素叫做标记(token)。通常,要使用空格、制表符或者回车分开两个标记。

        空格、制表符、回车统称为空白(white space)。

C++源代码风格

        大多数程序员在编写C++代码时,会遵循一定的规则:

  • 每行语句占一行。
  • 每个函数都有一个开始花括号和一个结束花括号,这两个花括号各占一行。
  • 函数中的语句都相对于花括号进行缩进。
  • 与函数名称相关的圆括号周围没有空白。

C++语句

例子:

#include <iostream>

int main()
{
    using namespace std;

    int carrots;

    carrots = 25;
    cout << "I have ";
    cout << carrots;
    cout << " carrots.";
    cout << endl;
    carrots = carrots - 1;
    cout << "Crunch, crunch. Now I have " << carrots << " carrots." << endl;

    return 0;
}

程序执行结果:

分析: 

        在上述语句中,我们可以了解到两种新的语句:

  1. 声明语句——创建变量。
  2. 赋值语句——给该变量提供一个值。

声明语句和变量

        C++通过声明语句来指出存储类型并提供位置标签。例如上述语句中的carrots的声明:

int carrots;

        这条语句提供的信息有:① 需要的内存;② 该内存单元的名称。

        先说第①点:在C++中,int表示整数,它表示没有小数部分的数字,即整数。C++中,int类型可正可负,大小取决于实现。

        再说第②点:该声明语句指出,此后程序将使用名称carrots来标识存储在该内存单元中的值。carrots被称为变量,因为它的值可以被修改。

        有些语言在使用新名称时自动创建新变量,而不用显式地进行声明。在这种情况下,如果发生拼写错误会很难被发现。

        程序中的声明语句叫做定义声明语句,简称定义。它将导致编译器为变量分配内存空间,在较为复杂的情况下,还可能有引用声明。

        不同于C语言的变量声明通常位于函数的开始位置,C++通常的做法是在首次使用变量前声明它,方便查找变量并了解变量的类型。

赋值语句

        赋值语句将值赋给存储单元。例如:

carrots = 25;

        上述的语句将整数25赋给了变量carrots表示的存储单元。符号 = 被称为赋值运算符。和C语言相比,C++有一项不同寻常的特性——可以连续使用赋值运算符。例如,下面的代码是合法的:

int mon;
int eoe;
int yay;
yay = eoe = mon = 88;

        赋值将从右向左进行。首先,88被赋给mon;然后,mon的值(现在是88)被赋给eoe;最后,eoe的值被赋给yay。

        另外还有一条赋值语句表面可以对变量的值进行修改:

carrots = carrots - 1;

cout的新用法

        在上述的代码中,我们得知,cout可以被用来打印变量,该变量的值是一个整数:

cout << carrots;

        实际上,打印carrots的值25是两个操作:① cout将carrots替换成当前值25;② 在把值转换成合适的输出字符。这里要注意的是,在打印前,cout必须将整数形式的数字转换为字符串形式,并且cout知道carrots是一个需要转换的整数。

        相比于C语言中存在的printf函数而言,cout不用使用特殊代码(%s和%d之类的),也不会由于要求的类型与实际变量类型不一致而产生错误。

printf("%d\n", 25);
printf("%s\n", "25");

        cout的智能行为源于C++的面向对象特性。实际上,C++的插入运算符(<<)将根据其后的数据类型相应地调整行为,这是一个运算符重载的例子。

其他C++语句

例子:

cin 是与 cout 相对的用于输入的对象。

#include <iostream>

int main()
{
    using namespace std;

    int carrots;
    
    cout << "你有多少胡萝卜?" << endl;
    cin >> carrots;
    cout << "这里还有两根多的。";
    carrots = carrots + 2;
    
    //打印结果
    cout << "现在你有" << carrots << "根胡萝卜。" << endl;

    return 0;
}

程序执行结果:

分析:

        该程序包含两条新特性:① 用cin来读取键盘输入;② 将四条语句组合成一条。

使用cin

cin >> carrots;

        这条语句表示:从键盘输入的值最终被赋给了carrots。即信息从cin流向了carrots。

        就像C++将输出看作是输出程序的字符流一样,也可以将输入看作是流入程序的输入流。iostream文件将cin定义为一个表示这种流的对象。

        与cout一样,cin也是一个智能对象,它可以将输入转换成接收信息的变量能够接受的形式。

使用cout进行拼接

cout << "现在你有" << carrots << "根胡萝卜。" << endl;

        除此之外,这条语句还可以被写成:

cout << "现在你有";
cout << carrots;
cout << "根胡萝卜。";
cout << endl;

或者

cout << "现在你有"
	 << carrots
	 << "根胡萝卜。"
	 << endl;

        这是由于C++的自由格式规则将标记间的换行符和空格看作是可互相替换的。

类简介

        类是用户定义的一种数据类型。要定义类,需要描述它能够表示声明信息和可对数据执行那些操作。类之于对象 就像 类型之于变量 。也就是说:

  • 类定义:描述的是数据格式及其用法。
  • 对象:是根据数据格式规范创建的实体。

        打个比方,如果类就好比所有著名演员,那么对象就好比某个著名的演员。而如果用OOP术语来表示,那么C++中的类就对应于某些语言中的对象类型,而C++对象对应于对象实例或实例变量。

        拿cout来举例:它是一个ostream类的对象。ostream(iostream文件的另一个成员)描述了ostream对象表示的数据及可以对它执行的操作。

||| 类描述了一种数据类型的全部属性(包括可使用它执行的操作),对象是根据这些描述创建的实体。

        就像函数来自函数库一样,类也可以来自类库。ostream和istream类就属于这种情况。它们没有被内置在C++语言中,而是语言标准指定的类。多数的实现都在软件包内提供了其他类的定义。

        类描述指定了可对类对象执行的所有操作。要对特定对象执行这些操作,需要个对象发送一条信息。发送信息有两种方法:

  1. 使用类的方法。(本质上是函数调用)
  2. 重新定义运算符。cin和cout就是使用的这种方法。比如下面的语句重新定义<<运算符将“显示消息”发送给cout:
    cout << "你好!";

    在这个例子中,消息带有一个参数——要显示的字符串。

函数

        函数用于创建C++程序的模块,对C++的OOP定义至关重要。

        C++函数分为两种,有返回值的和没有返回值的。可以在标准库中找到这两类函数的例子,也可以自行编写。

使用有返回值的函数

        有返回值的函数所生成的返回值可以被赋给变量或在其他表达式中被使用。接下来演示函数sqrt()的使用例子:

x = sqrt(6.25);

        其中,表达式sqrt(6.25)被称为函数调用,被调用的函数被称为调用函数,包含函数调用的函数被称为调用函数

  • 参数:( )内的值 6.25 是被发送给函数的消息,这被称为传递给函数。以这种方式发送给函数的值叫做参数。
  • 返回值:函数sqrt()的返回值是2.5,这个值会被发送给调用函数,发送回去的这个值被称为返回值。

        但是在使用函数前,C++编译器必须知道函数的参数类型和返回值类型。C++提供这种信息的方式是使用函数原型语句。

||| C++程序必须为每一个被使用的函数提供函数原型。

        函数原型之于函数 就像 变量声明之于变量 。sqrt()的函数原型像这样:

double sqrt(double);

        第一个double意味着sqrt()将返回一个double值。括号内的double意味着sqrt()需要一个double类型的参数。所以为了所有该函数,代码应该写成:

double x;        //将x声明成一个 double类型 的参数
x = sqrt(6.25);

        函数原型的分号表明它是一条语句,这使得它是一个原型,而不是函数头。当然,在程序中使用sqrt()时,必须提供原型。

        注意:不要混淆函数原型和函数定义。函数原型描述函数接口,即只描述发送给函数的信息和返回的信息。而定义包含了函数的代码。在C++中,库文件包含函数的编译代码,头文件则包含原型。

完整的函数使用例:

#include<iostream>
#include<cmath>

int main()
{
	using namespace std;

	double area;
	cout << "请输入一个正方形房间的面积: ";
	cin >> area;

	double side;
	side = sqrt(area);
	cout << "这个房间的边长是 " << side
		<< " 米。" << endl;
	cout << "哇!" << endl;

	return 0;
}

程序的执行结果是:

        如果在UNIX中遇到这样一条消息,指出_sqrt是一个没有被定义的外部函数,那么可能需要在命令行结尾使用-ml选项:

CC sqrt.C -lm

如果上述现象发生在Linux系统下,有些版本的Gnu编译器于此类似:

g++ sqrt.C -ml

函数变体

        有些函数需要多项信息,这些函数会使用多个变量,参数之间用逗号隔开。如:

double pow(double, double);

        有些函数不接受任何参数。如:

int rand(void);

        注意:在C++中,函数调用必须包括括号,技术没有产生。

        还有些函数没有返回值。如:

void buck(double);

因为没有返回值,所以不需要使用变量或者函数对返回值进行接收,需要调用时,只要给与参数即可:

buck(12.12);

        在有些语言中,有返回值的被称为函数;没有返回值的被称为过程(procedure)或者子程序(subroutine)。

用户定义的函数

例子:

#include<iostream>
void Sub(int, int);
using namespace std;

int main()
{
	cout << "请输入第一个数字: ";
	int x = 0;
	cin >> x;
	cout << "请输入第二个数字: ";
	int y = 0;
	cin >> y;

	Sub(x, y);
}

void Sub(int x, int y)
{
	cout << "两者相加的结果是: " << x + y;
}

程序执行的结果是:

分析:

1. 函数格式

        在上述程序中,Sub()函数的定义和main()的定义采用的格式相同。有一个函数头,然后是函数体,所以函数的格式可以被统一为:

type functionName(argumentList)

{

        statements

}

        注意:C++不允许函数定义的嵌套。每个函数定义需要是独立的,所有函数的创建是平等的。

2. 函数头

        在上述的例子中,Sub()的函数头是:

void Sub(int, int);

        这个函数是没有返回值的,对于它的调用,需要像这样:

Sub(x, y);

        现在回到之前对main()函数返回值的讨论,main()函数的函数头是 int main() ,开头的int表示main()将返回一个整数值,那么这个值一个有谁接收呢?

squeese = main();

        答案是:可以将计算机操作系统(如Windows)看作调用程序。main()函数的返回值是直接返回操作系统的。很多系统可以使用函数的返回值。一般约定,退出值为0代表程序运行成功,为非零则意味着出现问题。

用户定义的有返回值的函数

例子:

#include<iostream>
int stonetolb(int);

int main()
{
	using namespace std;
	int stone;
	cout << "请输入质量(以英石为单位): ";
	cin >> stone;
	int pounds = stonetolb(stone);
	cout << stone << "英石 = ";
	cout << pounds << " 英镑。" << endl;
	return 0;
}

int stonetolb(int sts)
{
	return 14 * sts;
}

程序的执行结果是:

分析:

  1. 在main()中,程序通过cin给整型变量stone通过一个值。
  2. 这个值被作为参数传递给stonetolb()函数,在该函数中,这个值被赋给变量sts。
  3. 然后,stonetolb()用关键字return将14*sts返回给main()。

        这表明:return后面可以跟较为复杂的表达式

注:通常在可以使用一个简单常量的地方,都可以使用一个返回值类型与该常量相同的函数。

        这表明:函数原型描述了函数接口,即函数如何与程序的其他部分交互。参数列表指出何种信息将被传递给函数,函数类型指出返回值的类型。

        函数stonetolb包含了全部的函数特性:

  • 有函数头和函数体;
  • 接受一个参数;
  • 返回一个值;
  • 需要一个原型。

在多函数程序中使用using编译指令

        在上述的程序中,我们可以发现总是存在这样一条编译命令:

using namespace std;

        这是因为我们使用了 cout ,为了能够使用它,我们需要访问位于名称空间内的cout定义。

        我们可以发现,这条using编译命令不仅仅存在于函数内部,而且也可以存在于函数的外面(前面)

#include<iostream>
using namespace std;
void print(void);

int main()
{
    cout << "Hello ";
    print();
    return 0;
}
void print(void)
{
    cout << "world!";
}

        一般情况下,只让需要访问名称空间std的函数访问它是更好的选择

        当然,让程序访问名称空间std的方法不止一种,这里仅举四种作为例子:

  1. using namespace std; 放在函数定义之前此时文件内的使用函数都可以使用名称空间std中的所有元素。
  2. using namespace std; 放在特定的函数定义中让该函数能够使用名称空间std中的所有元素。
  3. 在特定的函数中使用类似于 using std::cout; 这样的编译指令,让该函数能够使用指定的元素,如cout。
  4. 完全不使用编译指令using,而在需要使用名称空间std中的元素时,使用前缀std::,如下所示:
    std::cout << "Hello!" << std::endl;

添加内容

C++中的语句类型功能
声明语句定义函数中使用的变量的名称和类型。
赋值语句使用赋值运算符(=)给变量赋值。
消息语句将消息发送给对象,激发某种行动。
函数调用执行函数。被调用的函数执行完毕后,程序返回函数调用语句后面的语句。
函数原型声明函数的返回类型、函数接受的参数数量和类型。
返回语句将一个值从被调用的函数那里返回调用函数中。
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值