C++ 练气期之函数探幽
作者:互联网
1. 函数基础
一个C++
程序中,往往需要包含若干个函数
,可以说函数
是C++
程序的基础组成元件,是程序中的头等公民。
如果要理解程序中使用函数
的具体意义,则需要了解语言发展过程中致力要解决的 2
问题:
-
一是完善语言的内置功能库(
API
),让开发者不为通用功能所干扰。 -
另就是通过特定的代码组织方案提升程序的可伸缩性、可维护性、可复用性以及安全性。
随着项目规模的增大,分离代码,重构整体结构尤为重要。
函数的出现,从某种意义上讲,其首要任务便是分离主函数中的代码,通过构建有层次性的代码,从而提升程序的健壮性。当然,通过函数分离代码是有准则的,其准则便是以重用逻辑为核心。
分离是一个大前提,有了这个大前提,便是分离的方案。
如函数设计理念、类设计理念、微服务设计理念……都是分离的思路,只是各自面对的是不同规模的项目。
1.1 使用函数
C++
中使用函数分 2
步:
- 定义函数:定义过程强调函数功能的实现。定义函数时,
C++
底层运行时系统并不会为函数中的局部变量分配空间。 - 调用函数:调用函数也就是使用函数提供的功能。此期间运行时系统才会为函数中的局部变量分配空间。
C++
对定义
和调用
这 2
个过程有顺序要求,也就是必须先义再调用。
#include <iostream>
using namespace std;
/*
* 定义函数:
* 侧重设计理念:此函数的功能是什么?或者说,通过使用此函数能获取到什么样的帮助
* 如下设计一个显示个体信息的函数
* 当然在设计过程时,需遵循函数的语法要求
*/
void showInfo(char names[10]){
cout<<"你好:"<<names<<endl;
}
int main(int argc, char** argv) {
char myNames[10]="果壳";
//调用时,函数中的代码方被激活
showInfo(myNames);
return 0;
}
如上代码,当在main
函数中调用showInfo
函数时,showInfo
需要在主函数之前定义,否则编译器会抛出错误。
如果非要把函数的定义放在调用语法之后,也不是不可以。可通过把函数的设计过程再分拆成 2
个步骤实施:
- 声明函数原型:函数原型只包含函数的基础说明信息,并不包含函数功能体。通过原型声明,提前告诉编译器,此函数是存在的。
- 函数功能定义:功能实现。
如下所示:
#include <iostream>
using namespace std;
//声明函数原型
void showInfo(char names[10]);
int main(int argc, char** argv) {
char myNames[10]="果壳";
//调用函数
showInfo(myNames);
return 0;
}
//函数定义可以放在函数调用之后
void showInfo(char names[10]){
cout<<"你好:"<<names<<endl;
}
原型声明语句只要是在调用之前就可以。
1.2 函数的作用域
函数和变量的区别:
- 变量中存储的是数据。变量的存储位置可能是在栈中(
stack area
)、堆中(heap area
)或全局数据区域(data area
)。 - 函数存储的是逻辑代码。函数的存储位置是在代码区(
code area
)。
函数的作用域与变量的作用域不同,变量因声明位置和存储位置不同,其作用域则会有多种情况。而函数只可能存储存在代码区,C++
不允许函数嵌套定义,且只能在文件中定义。从某种意义上讲,函数的定义只有全局概念,而无局部概念。
如上文所述,如果函数是定义在调用之前,不存在调用不到问题,但如果定义是在调用之后,则需要声明原型后才能调用到,声明位置不同时,此函数的可见性也不一样。如下述代码
#include <iostream>
using namespace std;
int main(int argc, char** argv) {
char myNames[10]="果壳";
//调用不到
showInfo(myNames );
//声明函数原型
void showInfo(char names[10]);
//可调用到函数
showInfo(myNames);
return 0;
}
//函数定义在调用之后,调用时,则需要先声明
void showInfo(char names[10]){
cout<<"你好:"<<names<<endl;
}
通过这种机制,可以限制函数的使用位置。
本文是从广义角度讨论函数,并不涉及类中函数的作用域问题。因类可以对函数进一步封装,可以限制函数的使用范围。