主题
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引用
两种常见的情形:
- 重载赋值运算符,旨在提高效率。一般来说,对象都是可修改的,所以返回不会加const。
- 重载与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;
}
}提示
重载是因为函数参数不同,显式具体化是因为算法不同。