默认参数
默认参数指的是当函数调用中省略了实参时自动使用的一个值,例如:
void wow(int n);
设置n有默认值1, 那么当调用wow()的时候相当于wow(1).
如何设置默认值呢? 通过函数原型, 例如:
char * left(const char * str, int n = 1);
这个函数原型就声明了left的第二个参数的默认值是1. 如果省略了参数n, 则默认值是1, 否则, 传递的值将覆盖1.
对于带参数列表的函数, 必须从右向左添加默认值, 也就是说, 要为某个参数设置默认值, 则必须为它右边的所有参数提供默认值:
// 合法的
int harpo(int n , int m = 4, int j = 5);
// 合法的
int groucho(int k = 1, int m = 2, int n = 3);
// 非法的, 因为没有将j设置默认值
int chico(int n, int m = 6, int j);
那么harpo的调用方法:
// 相当于harpo(2, 4, 5);
beep = harpo(2);
// 相当于harpo(1, 8, 5)
beep = harpo(1, 8);
// 没有使用默认值
beep = harpo(6, 7, 8);
实参按从左到右的顺序依次被赋给相应的形参, 而不能跳过任何参数
// 这样是非法的, 不能把m设置成4
beeps = harpo(3, ,8);
看一个完整的demo
#include <iostream>
using namespace std;
const int ArSize = 80;
// 函数原型, 第二个参数设置了默认值
char * left(const char * str, int n = 1);
int main()
{
char sample[ArSize];
cout << "Enter a string : " << endl;
cin.get(sample, ArSize);
char* ps = left(sample, 4);
cout << ps << endl;
// 记得释放空间
delete[] ps;
// 可以重新使用
// 使用了默认的1
ps = left(sample);
cout << ps << endl;
delete[] ps;
return 0;
}
char* left(const char* str, int n)
{
if(n < 0)
n = 0;
char* p = new char[n + 1];
int i;
for (i = 0; i < n && str[i]; i++)
{
p[i] = str[i];
// *(p + i) = *(str + i);
}
while(i <= n)
p[i++] = '\0';
return p;
}
程序运行结果:
函数重载
C++函数重载的关键是函数的参数列表, 函数重载的要求:
1.函数的函数名是相同的
2.函数的参数列表是不同的, 也就是参数数目或参数类型不同
3.函数的返回值不能作为区分重载函数的依据
C++中的函数重载和java中的函数重载类似例如:
void print(const char* str, int width); // #1
void print(double d, int width); // #2
void print(long l, int width); // #3
void print(int i, int width); // #4
void print(const char* str); // #5
使用print()函数时, 编译器将根据所采取的用法使用有相应参数列表的原型:
print("Pancakes", 15); // 使用#1
print("Abc"); // 使用#5
print(1999.0, 15); // 使用#2
print(1999, 15); // 使用#4
print(1999L, 15); // 使用#3
使用重载函数的时候, 需要在函数调用中使用正确的参数列表, 例如下面这个:
unsigned int year = 2000;
print(year , 6);
上面这个写法print不能与任何一个原型匹配, 没有匹配的原型并不会自动停止使用其中的某个函数, 因为c++将尝试使用标准类型转换强制进行匹配, 如果原型#2是print()唯一的原型, 则函数调用print(year, 6)将把year转换为double类型, 但是在上面代码中, 有三个数字作为第一个参数的原型, 因此有3中转换year的方式, 这种情况下, C++将拒绝这种函数调用, 并报错.
注意一点:编译器在检查函数参数列表时, 将把类型引用和类型本身视为同一个参数列表, 因此:
double cube(double x);
double cube(double & x);
这两个方法并不是函数重载
请看下面的函数原型:
void dribble(char* bits); // #1
void dribble(const char* cbits); // #2
void dabble(char* bits); // #3
void drivel(const char* bits); // #4
下面列出了各种函数调用对应的原型: // #5
const char p1[20] = "asdfghjkl";
char p2 = "qwertyuio";
dribble(p1); // #2
dribble(p2); // #1
dabble(p1); // 匹配不上, 因为dabble接收的是const char *
dabble(p2); // #3
drivel(p1); // #4
drivel(p2); // #4
dribble()函数有两个原型, 一个用于const指针, 另一个用于常规指针, 编译器将根据实参是否是const来决定用哪个原型, dabble函数只能与非const参数进行调用匹配, drivel可以与非const和const参数进行调用匹配, 这是因为非const赋值给const是合法的, 反之是非法的.
重载引用参数
void staff(double & rs);
void staff(const double & rcs);
void stove(double & r1);
void stove(const double & r2);
void stove(double && r3);
这让您能够根据参数是左值, const还是右值来定制函数行为:
double x = 55.5;
const double y = 33.0;
stove(x) // stove(double & r1)
stove(y); // stove(const double & r2)
stove(x + y); // stove(double && r3)
如果没有定义函数stove(double && r3), stove(x+y)将调用函数stove(double & r1)
看一个完整的例子:
#include <iostream>
using namespace std;
// 重载了left方法
// 值传递
// unsigned后面没有加类型名, 则默认是unsigned整型
unsigned long left(unsigned long num, unsigned ct);
// 第二个参数有默认值
char* left(const char* str, int n = 1);
int main()
{
char* trip = "asdfghjkl";
unsigned long n = 12345678;
int i;
char* temp;
for(i = 1; i < 10; i++)
{
cout << left(n, i) << endl;
temp = left(trip, i);
cout << temp << endl;
delete[] temp;
}
return 0;
}
unsigned long left(unsigned long num, unsigned ct)
{
unsigned digits = 1;
unsigned long n = num;
if(ct == 0 || num == 0)
return 0;
while(n /= 10)
digits++;
if(digits > ct){
ct = digits - ct;
while(ct--)
num /= 10;
return num;
} else {
return num;
}
}
char* left(const char* str, int n)
{
if(n < 0)
n = 0;
char* p = new char[n + 1];
int i;
// str[i]表示str[i]不能是空字符, 如果是空字符就结束循环
for(i = 0; i < n && str[i]; i++)
{
p[i] = str[i];
// *(p + i) = *(str + i);
}
while(i <= n){
p[i++] = '\0';
}
return p;
}
输出结果:
指的注意的都写到注释里了