1.传值与传址
1.1索引(也叫化身,英文名reference)
声明一个reference,只需要在类型和名称之间加个&号
如: int val=2;
int &rval=val;//定义一个reference,叫rval,用于代表val,即作为val的化身
int *p=&val;//这是个指针变量
注意,索引只要绑定了一个对象后就绑死了,再也不能代表其他对像了.
并且,所有对索引的操作其实就是对其所代表的对像的操作,索引只是一个化身而已.
如:
rval=3;//其实就是将val值变为3,因为rval代表的是val
int *point=&rval;//其实就是将rval代表的对像val的地址赋给point
1.2址传递
void swap(int &val1,int &val2)
{// 这就是址传递,实参的值会得到改变,而值传递并不改变实参的值.
int temp=val1;
val1=val2;
val2=temp;
}
2.生存空间和范围
2.1 定义在函数内部的变量只存活于函数执行之际,如果想将这些局部变量以传址形式返回(即返回地址)
就会报错.但我们可以以传值方式返回其值.
2.2 对于内置数据类型,如int ,char 等,如果定义会全局变量时,即使我们不进行初始化,也会默认初始化为0.
但如果定义局部变量就不具默认初始化的能力.
3.动态内存管理
3.1分配内存
int *p1,*p2.*p3;
p1=new int;//未初始化
p2=new int(10);//初始化为10
p3=new int[10];//分配数组,长度为10,p3指向首元素地址
3.2释放内存
delete p1;
delete [] p3;//如果是释放数组,需在中间加个下标运算符
调用delete 时,编译器会自动帮我们检查地址是否为空.所以无需我们检查
4.函数参数使用默认值
//display定义
void display(vector <int>&vec,ostream *os=&cout)
{//第二个参数使用了默认值,默认将信息输出到cout
int i;
for(i=0;i<vec.size();i++)
(*os)<<vec[i]<<" ";
(*os)<<endl;
}
//调用display,如果只打算输出到cout,可以用单个参数的调用
display(vec);
//改变输出对像
ofstream ofil("data.txt");
display(vec,&ofil);
规则:
4.1 在形参列表中,使用默认值的参数应该放在最右边
如:
void display(vector <int>&vec,ostream *os=&cout)正确
void display(ostream *os=&cout,vector <int>&vec)错误
4.2 可以函数声明或定义中指定默认值,但是只能在一个地方指定,假如在声明中指定,那就在定义中不能
指定,通常提倡在声明中指定
5.使用局部静态变量
通常一个函数里面定义的变量,默认情况下都是非静态性的,局部非静态性变量随着函数被调用而得到内存,
一旦函数执行完毕,内存空间就会被收回,这样使得我们不能够返回变量的地址,只能返回变量值。
但如果在函数内部定义变量时,在前面加个static,就将这个变量声明为局部静态变量,即使函数执行完毕,它的
内存空间依然存大。
6.函数重载(依据参数列表)
函数名称相同,而参数表(类型或参数数目)不同的一组函数就构成重载函数。
但如果仅仅只有返回值类型不同是不能构成重载的,反而编译时会报错。
7.模板函数(Template Functions)
如果一个函数需有多种实现方式,我们可以用函数重载。
但如果一个函数需要是仅仅是参数具有多种类型,到执行时才绑定具体的变量类型,我们可以用模板函数
7.1模板函数定义
template<typename elemType>//template和 typename都是关键词
void display_message(const string &msg,const vector<elemType>&vec)
{
........
........函数主体
}
模板函数的定义以template<>开头,尖括号里面可以放多个型别识别代称,这个例子中只放了一个elemType
typename也是一个关键词,表示其后的elemType代表一个数据类型(型别),但具体代表什么类型,要到函数执行时才绑定,elemType不是关键词,可以任取,这只取到占位作用,但一旦起定,在函数形参列表中就要对应。
7.2调用
vector<int> ivec;
display(msg,ivec);//此时第二个参数绑定为int型
7.3模板函数同时也可以重载。
8.函数指针