1 参数传递
  非引用形参
  普通的非引用类型的参数通过复制对应的实参实现初始化。当用实参副本初始化形参时,函数并没有访问调用所传递的实参的本身,
因此不会修改实参的值。
(1)指针形参
  函数的形参可以是指针,此时将复制实参指针。与其他非引用的类型的形参一样,该类形参的任何变化也仅作用于局部副本。如果函数将新指针赋值
给形参,主调函数使用实参的值不会发生任何变化。例如:
void reset(int *p)
{
   *p=0;//将p指向的值改为0
    p=0;//在reset函数内指针,修改的是指针p的副本,退出函数后,p的值不变
}
(2)const形参
  在调用函数时,如果该函数使用非引用的非const参数,则既可以给该函数传递const实参的值,也可以传递非const的值
这种行为源于const对象的标准初始化规则。反之亦然。
  
  引用形参
  void(int &a,int &b)
  {
      int temp=v2;
      v2=v1;
      v1=temp;
  }
(1)可以使用形参返回额外的值
(2)利用const引用避免复制
  更灵活的指向const的引用
  如果函数具有普通的非const的引用实参,则显然不能通过const对象进行调用。因为此时的函数可以修改传递过来的对象,这违背了实参const的特性。
  并且,调用这样的函数时,传递一个右值或具有许要转换的类型的对象时也是不允许的。例如:
int incr(&val)
{
  return val++;
}

int main()
{
  short v1=0;
  const int v2=43;
  int v3=incr(v1);       //error v1不是一个int类型的
  int v3=incr(v2);       //error v2是一个const类型
  int v3=incr(0);        //error 0是一个右值
  int v3=incr(v1+v2);    //error v1+v2的表达式是个右值
  
}

应该将不需要修改的引用形参定义为const引用。普通的非const引用形参在使用时不太灵活。这样的形参既不能用const对象初始化,也不能用字面值或者产生右值的表达式实参初始化。

2  数组形参


数组有两个特殊的性质,影响我们定义和使用作用在数组上的函数:一个是不能复制数组,二是使用数组名时,数组名会自动化转化为指向第一个元素的指针。


数组形参的定义

void printValues(int*) {};

void printValues(int[]) {};

void printValues(int[10]) {};

虽然不能直接传递数组,但是函数的形参可以写成数组的形式。虽然形式表示方式不同,但可将使用数组语法定义的形参看做指向数组元素类型的指针。


   数组实参


   和其他类型一样,数组形参可定义为引用类型或非引用类型。大部分情况下,数组以普通的的非引用类型传递,此时数组会转化为指针。一般来说,非引用类型的形参会初始化其相应

实参的副本。而在传递数组时,实参是指向数组第一个元素的指针,形参复制的是这个指针的值,而不是数组元素本身。函数操纵的是指针的副本,因此不会修改实参指针的值。然而函数

可通过该指针改变它所指向的数组元素的值。通过指针形参做的任何改变都在修改数组元素的本身。

当不需要修改数组形参的元素时,函数应该将形参定义为指向const对象的指针。


  通过引用传递实参

  和其他类型一样,数组形参可声明为数组的引用。如果形参是数组的引用,编译器不会将数组实参转化为指针,而是传递数组的引用本身。在这种情况下,数组大小成为形参和实参类型

的一部分。

void printValues(int(&arry)[10]);


&arry两边的括号是必须的,因为下标操作具有更高的优先级



3 成员函数

  

  函数原型必须在类中定义,但是函数体可以在类中定义也可以在类外定义。类的所有成员都必须在类定义的花括号里面声明,此后,就不能再为类增加任何成员。

  编译器隐式的将在类内定义的成员函数当作内联函数。const成员函数不能修改调用该函数的对象。

  const对象、指向const对象的指针或引用只能调用其const成员函数。

  在类的外面定义成员函数必须指定他们是类的成员。

  double Sales_item::avg_price() const

  {

if(units_sold)

return revenue/unite_sold;

else

return 0;

  }

 

  构造函数是特殊的成员函数,与其他成员函数不同,构造函数与类同名,而且没有返回值。一个类可以有多个构造函数,每个构造函数必须有与其他构造函数不同数目或类型的形参。

  

class Sales_item

{

  public:

double avg_price() const;

bool some_sibn(const Sales_item &rhs) const

{return isbn==rhs.isbn;}

Sales_item():units_sold(0),revenue(0.0){};

  private:

std::string isbn;

unsigned units_sold;

double revenue;

};


构造函数中,在冒号与花括号之间的代码称之为构造函数的初始化列表。它跟在构造函数的形参表之后,以冒号开头。构造函数的初始化式是一系列成员名,每个成员后面是括在圆括中的

初始值。多个成员的初始值用逗号分隔。


4 重载函数


  出现在相同作用域的两个函数,如果具有相同的名字而形参表不同,则称为重载函数。

  重载确定的三个步骤:

void f();

void f(int);

void f(int,int);

void f(double,double==3.14);

f(5.6);


(1)候选函数

函数重载确定的第一步就是确定该调用所考虑的重载函数的集合,该集合中的函数成为候选函数。候选函数与被调用函数同名的函数,并且在调用点上,它的声明可见。


(2)选择可行函数

第二步是从候选函数中选出一个或者多个可行函数。可行函数必须满足两个条件:第一,函数的形参个数与调用的实参个数相同;第二,每一个实参的类型必须与对应形参的类型匹配,或者

可被隐式的转化为队形的形参类型。


(3)寻找最佳匹配

函数重载确定的第三步是确定与函数调用中使用的实际参数匹配最佳的可行函数。

 posted on 2008-10-26 19:40  清水湾  阅读(218)  评论(0)    收藏  举报