C++ Primer Plus书之--C++ 默认参数和函数重载

默认参数

默认参数指的是当函数调用中省略了实参时自动使用的一个值,例如:

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;
}

输出结果:

指的注意的都写到注释里了

猜你喜欢

转载自blog.csdn.net/c1392851600/article/details/84780741