C++ Primer 学习(第六章)

1.函数的实参类型必须与对应的形参类型相匹配或者实参的类型能够隐式地转换成形参的类型。例如定义函数:

int fact(int val)
{
  int ret=1;
  while(val>1)
     ret*=val--;
  return ret;
}

那么调用fact(3.14)也是合法的,因为double类型的可以转换成int,等价调用fact(3)。

2.函数形参列表中的形参通常用逗号隔开,其中每个形参都是含有一个声明符的声明。即使两个形参的类型一样,也必须把两个类型都写出来,但形参名是可选的,不过由于在函数中我们无法使用未命名的形参,所以形参一般都应该有个名字。例如:

int f1(int v1, v2) {/*...*/}   //错误
int f2(int v1,int v2) {/*...*/} //正确
int f3(int ,int ) {/*...*/}  //正确,不过形参没有名字,在函数体里就无法使用该形参,所以一般形参都应该有个名字

3.形参和函数体内部定义的变量统称为局部变量。它们对函数而言是"局部"的,仅在函数的作用域内可见,同时局部对象还会隐藏在外层作用域中同名的其他所有声明。局部对象当到达块末尾时就会被销毁。当块执行结束后,块中创建的局部对象的值就变成未定义的了。

将局部变量定义成static类型,这样的对象称为局部静态变量。局部静态变量在程序的执行路径第一次经过对象定义语句时初始化,并且直到程序终止才被销毁,在此期间即使对象所在的函数结束执行也不会对它有影响。例如下面的函数统计自己被调用了多少次:

size_t count_calls()
{
  static size_t ctr=0;//调用结束后,这个值仍然有效,ctr只在第一次调用时被初始化
  return ++ctr;
}
int main()
{
  for(size_t i=0;i!=10;++i)
     cout<<count_calls()<<endl;
  return 0;
}

如果局部静态变量没有显式的初始值,它将执行值初始化,内置类型的局部静态变量初始化为0。

4.函数只能定义一次,但可以声明多次。

5.和其他变量一样,形参的类型决定了形参和实参交互的方式。如果形参是引用类型,它将绑定到对应的实参上;否则,将实参的值拷贝后赋给形参。当形参是引用类型时,引用形参就是它对应的实参的别名。

C程序员常常使用指针类型的形参访问函数外部的对象。而在C++语言中,建议使用引用类型的形参替代指针

6.当用实参初始化形参时会忽略掉顶层const。换句话说,形参的顶层const被忽略掉了。当形参有顶层const时,传给它常量对象或者非常量对象都是可以的。例如:

void fcn(const int i) {/*...*/}  //fcn能够读取i,但是不能向i写值

调用fcn函数时,既可以传入const int也可以传入int,因为用实参初始化形参时会忽略掉顶层const。因为这一特性,所以注意下面函数的定义:

void fcn(const int i) {/*...*/}
void fcn(int i) {/*...*/} //错误:重复定义了fcn(int)

因为顶层const被忽略掉了,所以上述代码尽管形式上有差异,但实际上第2行函数的形参和第1行函数的形参没什么不同。

7.我们可以使用非常量初始化一个底层const对象,但是反过来不行;同时一个普通的引用必须用同类型的对象去初始化。先看下述代码:

int i=42;
const int *cp=&i;//正确,这是一个底层const,因为cp的值可以改变,只是不能通过cp指针改变其所指的值i,i本身是个变量,所以说可以使用非常量初始化一个底层const对象
const int &r=i;//正确,凡是声明为引用的const都是底层const
const int &r2=42;//正确
int *p=cp;//错误,指针p是非常量,指针cp是底层const属性,不能用底层const去初始化非常量
int &r3=r;//错误,不能用底层const引用去初始化非常量引用
int &r4=42;//错误,不能用字面值初始化一个非常量引用

理解了上述代码,对于形参的初始化规则与上述变量的初始化规则其实是相同的。

在这里先定义两个函数形参类型分别为int *和int&的函数:

void reset(int *ip) {/*...*/}
void reset(int &i)  {/*...*/}

下述代码在上述两个函数已经定义的基础上写出,注意下述代码的合法性:

int i=0;
const int ci=i;
string::size_type ctr=0;
reset(&i);//正确,调用形参类型为int*的reset函数
reset(&ci);//错误,不能用指向const int对象的指针初始化int*
reset(i);//正确,调用形参类型为int&的reset函数
reset(ci);//错误,不能把普通引用绑定到const对象ci上,普通引用只能用同类型的对象初始化
reset(42);//错误,不能把普通引用绑定到字面值上,普通引用只能用同类型的对象初始化
reset(ctr);//错误,类型不匹配,普通引用只能用同类型的对象初始化

猜你喜欢

转载自blog.csdn.net/lovebasamessi/article/details/83022533