第2章 面向过程的编程风格

2.1 如何编写函数

函数定义:

每一个函数必须定义以下四个部分:

1.返回类型。

2.函数名

3.参数列表

4.函数体

 

函数必须先声明,然后才能被调用。函数声明让编译器能检查函数的使用是否正确。

函数声明:

函数声明需要包含返回类型、函数名、参数列表,也称为函数原型。

 

2.2 调用函数

两种参数传递方式:传地址、传值

当我们调用一个函数时,会在内存中建立一块特殊区域,称为程序堆栈。一旦函数完成,这块内存会被释放,里面的临时对象也会消失。

 

通过传地址,可以将函数参数和实际对象产生关联。

void swap(int &val1.int & val2) 

 

 

作用域和地址:

对象如果在函数以外声明,具有file scope,从声明点到文件末尾都可见,file scope内的对象具有static extent,从main()开始执行前内存就已经分配好了,一直持续到程序结束。

 

动态内存管理

分配动态内存使用new

释放动态内存使用delete

例子:

int *pi = new int;

int *pi  = new int(10);

 

int*pia = new int[24]; //分配数组

delete pi;   //删除pi所指的int

delete [] pia;//删除数组

 

 

2.3 提供默认参数值

C++允许我们为函数参数提供默认值

关于默认参数有两个规则:

1.默认值的解析是从右开始的,如果我们为某个参数提供默认值,那么它右面的参数也要有默认值。

2.默认值只能指定一次,可以在函数声明处,也可以在函数定义处。

通常放在声明处。

 

例子:

//NumericSqe.h

void display(const vector<int>&, ostream&=cout);

 

#include”NumericSeq.h”

void display(const vector<int>& vec, ostream &os)

{

}

 

 

2.4 使用局部静态对象

使用 局部静态对象:

 

const vector<int>*

fibon_seq(int size)

{

 static vector<int> elems;

 

return &elems;

}

 

elems被定义为函数中的局部静态对象。局部静态对象所处的内存空间。即使在不同的函数调用过程中,依然持续存在。

 

 

2.5 声明inline函数

将函数声明为inlien函数,表示要求编译器在函数调用点将函数内容展开。

只要在函数前加上关键字 inline就可以将函数声明为inline:

inline函数的定义一般在头文件中。

 

比较短小的函数适合定义成inline函数。

 

2.6提供重载函数

参数列表不相同(参数类型或参数个数不同)的函数可以拥有相同的函数名称。

如:

void display(char ch);

void display(const string&);

调用时编译器通过参数列表知道该调用哪个函数。

 

2.7 定义并使用模板函数

函数模拟(function template)通过了一种机制,让我们得以将单一函数的内容与各种类型绑定(bind)起来。

function template将参数列表的部分参数的类型抽离出来。

function template以关键字template开场,然后是<>括起来的标识符,里面的标志符是我们希望推迟决定的数据类型。 用户利用这一模板来产生函数。

 

template<typename elemType>

void display(const string &msg, const vector<elemType>&vec)

{

cout<<msg;

for(int ix = 0;ix <vec.size();++ix)

{elemType  t = vec[ix];

 cout<<t<<’’l

}

}

关键字typename表示,elemType在函数中是一个暂时放置类型的占位符。

elemType可以是任意名称。

 

使用function template的方式和普通函数相似:

vector<int> ivec;

string msg;

//…

display(msg,ivec);

编译器会将elemType绑定为int,然后产生一份函数实例,

如果写

vector<string> ivec;

string msg;

//…

display(msg,ivec);

编译器会将elemType绑定为string.

 

一般而言,如果函数具有多种实现方式,我们可以将它重载,

如果我们希望函数主体不变,仅仅改变其中的数据类型,可以使用function template。

 

 

2.8 函数指针带来更大的弹性

函数指针(pointer to function),必须指明函数的返回值类型,参数列表。

例如:

const vector<int>* (*seq_ptr) (int);

 

seq_ptr是一个可以 指向返回值是const vector<int>*,参数是int的函数 的函数指针。

调用方式和函数相同:

const vector<int>*pseq = seq_ptr(pos);

取得函数的地址: 提供函数名即可:

seq_ptr = pell_seq; //将pell_seq()的地址给seq_ptr指针。

 

2.9 设定头文件

函数的定义只有一份,但可以有多份声明。

一个对象只能在程序中定义一次。

inlien函数的定义放在头文件中。

 

在file scope内定义的对象,如果可能被多个文件访问,就应该被声明在头文件中。

在对象前定义前加关键字extern可以使其变成声明:

extern const vector<int>* (*seq_array[seq_cnt])(int);

 

const  object是一次定义规则下的例外,const object的定义只要一出文件之外就不可见。?