Skip to content
0

C++函数

函数参数

参数类型函数不需要修改实参函数需要修改实参
基本数据类型值传递引用或指针
数组const指针指针
结构体const指针或const引用引用或指针
类对象const引用或const指针引用或指针

以上只是指导建议,实际情况很可能会有不同的选择。如对于基本类型,cin使用引用,因此可以使用cin>>n,而不是cin>>&n

函数返回对象的情况

返回对象

当函数返回的对象是局部变量时,则不应该按引用方式返回,因为函数执行完后局部变量将调用析构函数,引用指向的对象将不再存在。通常,被重载的运算符会返回对象。

这种情况下,存在调用复制构造函数来创建被返回的对象的开销,但这是不可避免的。

返回const对象

意义不大。

返回const引用

返回指向const对象引用的场景:为了提高效率,函数返回的是传参的对象的引用。如比较两个对象:

c++
const Person& Max(const Person& p1, const Person& p2)
{
  if (p1.age > p2.age)
    return p1;
  else
    return p2;
}

返回非const引用

两种常见的情形:

  1. 重载赋值运算符,旨在提高效率。一般来说,对象都是可修改的,所以返回不会加const。
  2. 重载与cout一起使用的<<运算符。这种情形只能返回非const引用ostream &,如果返回类型是ostream,将要求调用ostream类的复制构造函数,而ostream类没有公有的复制构造函数。

函数重载

同一作用域内,函数名相同,但函数参数的类型或个数或顺序不同。重载的函数可以有不同的返回类型, 但是仅仅函数返回类型不同不是重载。

函数模板

函数模板使用泛型来定义函数,通过将类型作为参数传递给模板,可使编译器生成该类型的函数。

如果要将同一算法用于不同形参类型的函数,应该使用函数模板。比如有个函数交换两个值,参数类型有整型、浮点型等,如果为每种类型定义一个函数,代码就会很冗余。

c++
// 隐式实例化:常规函数模板
template <typename T> void Swap(T &a, T &b);

// 显式实例化:根据上面的函数模板生成double类型的函数定义。
// 意义不是很大,本身传入double类型的参数时编译器就会生成double类型的函数定义。
template void Swap(double &a, double &b);

template <typename T>
void Swap(T &a, T &b) {
    T temp;
    temp = a;
    a = b;
    b = temp;
}

但并非所有的类型都使用相同的算法,这时可以使用显式具体化——对特定类型,不使用函数模板来生成函数定义,而使用专门为此类型显式地定义的函数定义。

c++
struct job {
  char name[40];
  double salary;
  int floor;
};
// 显示具体化
template <> void Swap<job>(job& j1, job& j2);  // <job>可以省略

template <> void Swap(job& j1, job& j2) {
    double t1;
    int t2;
    t1 = j1.salary;
    j1.salary = j2.salary;
    j2.salary = t1;
    t2 = j1.floor;
    j1.floor = j2.floor;
    j2.floor = t2;
}

如果函数模板的参数有变化,这时可以重载函数模板。

c++
// 重载函数模板
template <typename T> void Swap(T a[], T b[], int n);

template <typename T>
void Swap(T a[], T b[], int n) {
    T temp;
    for (int i = 0; i < n; i++) {
        temp = a[i];
        a[i] = b[i];
        b[i] = temp;
    }
}

提示

重载是因为函数参数不同,显式具体化是因为算法不同。