第4章 组织程序和数据

新概念:划分模块、函数(形参、实参、按值传参、引用传参、重载)、错误提示机制(异常)、结构体、类、独立编译(头文件、源文件、声明)、预编译处理

 

之前我们所见到的教材示例都的代码已经变得有一些庞大了。C++和其他语言一样,对于处理庞大的代码提供了分模块机制。所谓的划分模块就是将我们的程序中相对独立的功能和数据划分开,每个单独的模块尽量只完成相对单一的功能,然后将这些相对独立的模块组合起来形成我们完整的程序。

 

之前我们已经见过,而且是我们见过的唯一函数:int main();我们可以定义更多的函数,取不同的名字,这些函数可以具有各种各样的参数类型。在我们定义函数的时候,我们可以规定形参的类型(我们在定义函数形参的时候并不会创建这些参数,只有在函数调用的时候才会创建,所以称为“形参”,而调用的时候所创建的参数就被称为“实参”)。我们调用函数的时候会将一些值用于创建我们的实参,这些值可以是字面量、变量,也可以是表达式等,但是类型必须是函数定义的形参类型,而且必须按照参数列表的顺序进行传递。

 

当我们的形参类型为非引用类型的时候,调用时触发的将是值传递。这样的值类型参数会将我们调用时所传值复制给参数,我们在使用参数的时候,实际就等于在使用一个函数内部的局部对象。

 

当我们的形参类型为引用类型的时候,调用时触发的将是引用传递。这样的引用类型参数会创建一个我们所传递的值的引用,我们在使用参数的时候,实际就等于在直接操作我们所传递的那个值(对象)。对于内置类型变量,由于其本身体积就小,我们没有必要使用引用类型传参,直接使用值类型也不会有什么效率损失,只有我们的程序确实要用到引用传参才能完成我们对内置类型参数的处理时才使用。对于自定义类型,尽量使用引用传参,避免不必要的数据拷贝导致效率低下。

 

C++提供了函数重载机制,也就是说我们可以定义很多个函数,这些函数可以具有相同的名字,但是他们不能够具有相同的参数列表。我们在调用函数的时候都会对函数列表中的参数进行相应的参数传递,所以C++可以通过我们所传递的参数个数、类型、顺序等来查找到相对应的函数重载。

 

一个程序应该具备相应的错误提示,当程序中检测到错误的时候,以某中机制提示给用户是很有必要的。C++提供异常机制,对于程序中产生的异常或者错误都可以通过异常机制来进行提示。抛出一个异常使用关键字:throw捕获异常使用try{}catch(){}结构。抛出的异常都是一个异常对象,我们捕获的也是一个对象,这个异常对象往往包含了异常信息以便我们捕获处理。

 

我们可以通过函数将程序的功能进行划分,我们也可以通过数据结构将程序的数据进行归类。关键字:struct将帮助我们建立我们自己的数据结构,这样我们的数据也可以根据其关联性进行划分组织了。其定义形式为:struct T{...};其中省略号就是我们的要放入这个结构的数据了,这些数据被称为结构成员,这个结构被命名为T

 

C++还提供了一个更加强大的抽象概念:类,关键字为class。类可以将我们的函数和数据结构组合起来,形成我们的自定义类型。这个概念是C++中最为强大的概念,它具有非常强的抽象能力,也是我们对程序进行组织划分的强大工具。其实C++已经摒弃了结构体的概念,之所以保留struct关键字是为了给由C语言转型而来的程序员提供便利,也是为了能够兼容古老的代码。在C++中,structclass的唯一区别就是默认的访问权限而已。像我们之前使用的标准库设施(带有std::前缀的名字)大多数都是类或者类对象。

 

所谓独立编译,就是我们可以将我们划分好的模块放入到不同的程序源文件中进行单独的编译,再通过链接器将它们链接成最终的程序。为了支持独立编译,C++提供了头文件、源文件两种概念。头文件主要是模块中的部件声明(如函数、类等),源文件则是这些函数、类等的实现代码。

 

编译器在对我们的代码进行编译之前会有一个预编译处理过程,我们可以通过这个过程进行一些有用的编译控制。

 

新设施:std::domain_errorconst、自定义比较函数的std::sortstd::setwinlinetry{}catch(){}

 

教材示例中使用了一个标准库异常对象std::domain_error,其实标准库还提供了其他的一些异常对象,我们将这些标准库提供的异常对象称为标准异常对象。这些异常对象都可以通过字符串进行创建,捕获到这些异常便通过what()成员函数来获取其携带的字符串信息。

 

const关键字是广为讨论的C++关键字。它是一个修饰性关键字,被其所修饰便具有只读属性。其可以修饰对象本身,也可以修饰间接对象(引用、指针)所关联的对象,还可以修饰类成员函数等。我们试图对const修饰的对象进行写操作(修改等),那么编译器会给我们的严厉的错误提示,合理使用const对于我们控制自己代码的正确性、描述抽象概念的语义等都具有很好的作用。

 

上一章我们已经使用过std::sort了,当时使用的是其两个参数的重载。而这一章教材中示例使用了其三个参数的重载。其中前两个参数和前一章的一样,表示一个区间,而第三个参数则是指定我们自己的比较函数。那么std::sort就会根据我们的比较函数进行排序,这个比较函数必须符合其规定的形式:接受两个比较的值作为参数,并返回比较结果(能够作为条件判断)。

 

本章中对于格式化输出不仅沿用了上一章的精度控制std::setprecision,还使用了一个新的控制工具std::setw。这个标准库设施是用于对输出数据进行宽度限制的,其作用时效和std::setprecision不一样,是临时性的,所以我们要记住若要再次控制输出数据宽度(哪怕和上次控制的相同)也必须要再次使用std::setw

 

inline关键字也是一个修饰性关键字,用来修饰函数的。被其修饰的函数编译器会考虑将其内联(即省略函数调用过程,直接将函数体代码拷贝到调用处),可以减少函数调用开销,但是会增大代码体积(因为每个调用都会被拷贝一份函数体代码)。其带来的效率上的优化也不是我们想当然的,所以在我以后进一步解析前,大家先暂时不要使用,仅作为了解。

 

try{}catch(){}结构是我们用于捕获异常的结构,对于可能产生异常的代码我们放到try块当中,当有异常抛出时,程序将会忽略后面的代码,直接转向catch块,并将异常对象作为参数传递给catch块。异常机制不是免费的,以后的课程会有对其使用的深入讨论。

 

新技术:头文件防多次包含

 

对于我们的头文件,我们可能在一个程序中会有多个模块进行包含,为了避免其被重复的包含,我们使用#ifndef #define #endif这三个预编译控制,例如我们有个头文件test.h,那么我们就在这个头文件的最顶部写上:

#ifndef TEST_H

#define TEST_H

在最底部写上:

#endif // TEST_H

这样就能够防止这个头文件被重复包含了。

 

下一课:C++课堂第5章 使用顺序容器并分析字符串 希望我的课堂对大家学习C++有所帮助

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值