-
内置函数(inline function)(内嵌函数,内联函数):嵌入到主调函数中的函数,是一种提高效率的方法。即在编译时将所调用函数的代码直接嵌入到主调函数中,而不是将流程转出去。
-
使用内置函数可以节省运行时间,但却增加了目标程序的长度。
-
并非一经指定为inline,编译系统就必须这样做。编译系统会根据具体情况决定是否这样做。
-
因此一般只将规模很小(一般为5个语句以下)而使用频繁的函数(如定时采集数据的函数)声明为 inline 函数。
inline int max(int a,int b,int c);
-
-
函数的重载(function overloading):C++允许用同一函数名定义多个函数
- 要实现的是同一类的功能,只是有些细节不同
- 不能只有函数的类型不同
- 重载函数的参数个数、参数类型或参数顺序3者中必须至少有一种不同,函数返回值类型可以相同也可以不同。
int max(int a,int b,int c); int max(int a); double max(double a,double b,double c);
//error case int f(int); int f(double); void f(int);
-
函数模板(function template):建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。
- 实参的类型取代函数模板中的虚拟类型T。
- 用函数模板比函数重载更方便,程序更简洁。但应注意它只适用于函数的参数个数相同而类型不同,且函数体相同的情况。(参数决定类型)
- 类型参数可以不只一个,可以根据需要确定个数。
template < typename T> 或 template <class T> T max(T a,T b); template< typename T1,typename T2 ,...>
-
有默认参数的函数:
-
实参与形参的结合是从左至右顺序进行的。因此指定默认值的参数必须放在形参表列中的最右端,否则出错。
-
一个函数不能既作为重载函数,又作为有默认参数的函数。因为当调用函数时如果少写一个参数,系统无法判定是利用重载函数还是利用默认参数的函数,出现二义性,系统无法执行。
float area( float r = 9.1 ); area(); //实际调用的是area(6.5); void f1(float a,int b=0,int c,char d=′a′); //不正确 void f2(float a,int c,int b=0, char d=′a′); //正确
-
-
函数的嵌套调用:C++不允许对函数作嵌套定义,也就是说在一个函数中不能完整地包含另一个函数。在一个程序中每一个函数的定义都是互相平行和独立的。
- 虽然C++不能嵌套定义函数,但可以嵌套调用函数
-
变量的作用域(scope):变量的有效范围,是从空间的角度来分析的,分为全局变量和局部变量。归纳起来,变量有4种不同的作用域,文件作用域是全局的,其他三者是局部的。除了变量之外,任何以标识符代表的实体都有作用域,概念与变量的作用域相似。
- 文件作用域(file scope)
- 函数作用域(function scope)
- 块作用域(block scope)
- 函数原型作用域(function prototype scope)。
-
**变量的存储期:**指变量在内存中的存在期间。这是从变量值存在的时间角度来分析的。存储期可以分为静态存储期(static storage duration)和动态存储期(dynamic storage duration)。这是由变量的静态存储方式和动态存储方式决定的。
- 静态存储方式是指在程序运行期间,系统对变量分配固定的存储空间。
- 动态存储方式则是在程序运行期间,系统对变量动态地分配存储空间。
-
内存中的供用户使用的存储空间
- 程序区
- 静态存储区
- 全局变量:程序开始执行时给全局变量分配存储单元,程序执行完毕就释放这些空间
- 动态存储区:在函数调用开始时分配动态存储空间,函数结束时释放这些空间。在程序执行过程中,这种分配和释放是动态的
- 函数形式参数。在调用函数时给形参分配存储空间。
- 函数中的自动变量(未加static声明的局部变量)
- 函数调用时的现场保护和返回地址等
-
变量的存储类别属性(storage class)(变量除了数据类型外的属性):指的是数据在内存中存储的方法。存储方法分为静态存储和动态存储两大类。根据变量的存储类别,可以知道变量的作用域和存储期。
-
自动的(
auto
):属于动态存储方式,变量没有写存储类别的时候默认是auto。- 为自动变量赋初值,不是在编译时进行的,而是在函数调用时进行,每调用一次函数重新给一次初值,相当于执行一次赋值语句。
- 如果不赋初值,则它的值是一个不确定的值。
-
静态的(
static
):在静态存储区内分配存储单元。有时希望函数中的局部变量的值在函数调用结束后不消失而保留原值,即其占用的存储单元不释放,在下一次该函数调用时,该变量保留上一次函数调用结束时的值。- 为静态局部变量赋初值是在编译时进行值的,即只赋初值一次,在程序运行时它已有初值。
- 当没有赋初值时,编译时自动赋初值0(对数值型变量)或空字符(对字符型变量)
- 其他函数是不能引用它的,也就是说,在其他函数中它是“不可见”的。【毕竟还是局部的,全局的就不一样了】
- 但是要多占内存,而且降低了程序的可读性,当调用次数多时往往弄不清静态局部变量的当前值是什么。因此,如不必要,不要多用静态局部变量。【相对于全局变量,这个方法更好】
例4.13 输出1~5的阶乘值(即1!,2!,3!,4!,5!)。 #include <iostream> using namespace std; int fac(int); //函数声明 int main( ) {int i; for(i=1;i<=5;i++) cout<<i<<″!=″<<fac(i)<<endl; return 0; } int fac(int n) {static int f=1; //f为静态局部变量,函数结束时f的值不释放 f=f*n; //在f原值基础上乘以n return f; }
-
寄存器的(
register
):为提高执行效率,C++
允许将局部变量的值放在CPU中的寄存器中,需要用时直接从寄存器取出参加运算,不必再到内存中去存取。- 在程序中定义寄存器变量对编译系统只是建议性(而不是强制性)的。当今的优化编译系统能够识别使用频繁的变量,自动地将这些变量放在寄存器中。
-
外部的(全局变量)(
extern
):作用域为从变量的定义处开始,到本程序文件的末尾。编译时将全局变量分配在静态存储区。- 提前引用声明:如果在定义点之前的函数想引用全局变量,则应该在引用之前用关键字extern对该变量作外部变量声明,表示该变量是一个将在下面定义的全局变量。
T function() { extern int a,b; f(a,b); //引用定义在后面的全局变量,要用上一行做声明 ... } int a=2,b=7;
- 在多文件的程序中声明外部变量:如果一个程序包含两个文件,在两个文件中都要用到同一个外部变量
num
,不能分别在两个文件中各自定义一个外部变量num
。正确的做法是:在任一个文件中定义外部变量num
,而在另一文件中用extern
对num
作外部变量声明。【总的来说,extern
就是在声明的时候来用的】
file1.cpp extern int a , b; int main() { int c = a + b; ... } file2.cpp int a = 2, b = 3; ...
- 用
static
声明静态外部变量:希望某些外部变量只限于被本文件引用,而不能被其他文件引用。
file1.cpp static int a=3; int main() {...} file2.cpp extern int a; int fun(int n) { a*=n; }
auto
,static
和register
3种存储类别只能用于变量的定义语句中,extern只能用来声明已定义的外部变量,而不能用于变量的定义。
auto char c; //字符型自动变量,在函数内定义 static int a; //静态局部整型变量或静态外部整型变量 register int d; //整型寄存器变量,在函数内定义 extern int b; //声明一个已定义的外部整型变量
-
-
内部函数(静态函数):一个函数只能被本文件中其他函数所调用。如果在不同的文件中有同名的内部函数,互不干扰。
- 通常把只能由同一文件使用的函数和外部变量放在一个文件中,在它们前面都冠以
static
使之局部化,其他文件不能引用。static 类型标识符 函数名(形参表) static int fun(int a , int b);
- 通常把只能由同一文件使用的函数和外部变量放在一个文件中,在它们前面都冠以
-
外部函数:可供其他文件调用。如果在定义函数时省略
extern
,则默认为外部函数file1.cpp extern int max(int a ,int b);(函数原型) //不加extern也可以,因为函数默认就是extern的 int main() { int c = max(3,4); } file2.cpp int max(int a,int b){}
-
函数原型:能够把函数的作用域扩展到定义该函数的文件之外(不必使用
extern
)。函数原型通知编译系统:该函数在本文件中稍后定义,或在另一文件中定义。- 利用函数原型扩展函数作用域最常见的例子是
#include
命令的应用。在#include
命令所指定的头文件中包含有调用库函数时所需的信息。 - 比如
sin
,并不是由用户在本文件中定义的,而是存放在数学函数库中的。sin
函数的原型是double sin(double x)
,本应该在程序中一一写出来,但这显然是麻烦而困难的,因此在头文件cmath
中包括了所有数学函数的原型和其他有关信息, - 使用
#include <cmath>
即可在该文件中合法地调用各数学库函数了。
- 利用函数原型扩展函数作用域最常见的例子是
-
预处理命令:可以改进程序设计环境,提高编程效率。但它不是
C++
语言本身的组成部分,不能直接对它们进行编译。为了与一般C++
语句相区别,这些命令以符号“#”
开头,而且末尾不包含分号。- 宏定义:一般是用一个短的名字代表一个长的字符串
#define 标识符 字符串 #define pi 3.1415926 #define 宏名(参数表) 字符串 #define area(a,b) a*b
- 文件包含:指一个源文件可以将另外一个源文件的全部内容包含进来,即将另外的文件包含到本文件之中。
#include
- 宏定义:一般是用一个短的名字代表一个长的字符串
#include<文件名> VS #include" 文件名"
+ 用尖括号时,系统到系统目录中寻找要包含的文件,如果找不到,编译系统就给出出错信息。
+ 有时被包含的文件不一定在系统目录中,这时应该用双撇号形式,在双撇号中指出文件路径和文件名。用户自己写的头文件很适用。
+ 如果在双撇号中没有给出绝对路径,如#include ″file2.c″
则默认指用户当前目录中的文件。若找不到,再按标准方式查找。
- 条件编译:一般情况下,进行编译时对源程序中的每一行都要编译。但是有时希望程序中某一部分内容只在满足一定条件时才进行编译。
#ifdef 标识符 或者 #ifndef 标识符
//标识符需要在头文件中定义:#define 标识符,后面可以没有字符串,此时起定义的作用
程序段1
#else //可省略
程序段2
#endif
#if 表达式
程序段1
#else
程序段2
#endif
- 头文件(标题文件) :常用在文件头部的被包含的文件
- 对类型的声明。
- 函数声明。
- 内置(inline)函数的定义。
- 宏定义
- 全局变量定义。外部变量声明。如entern int a;
- 还可以根据需要包含其他头文件