本节书摘来自异步社区出版社《C++编程惯用法——高级程序员常用方法和技巧》一书中的第2章,第2.6节,作者: 【美】Robert B. Murray ,更多章节内容可以访问云栖社区“异步社区”公众号查看。
2.6 重载、缺省值以及省略符
C++中允许用户写出这样的代码:使用不同(个数或类型)的参数来调用(似乎是)同一个函数:
f();
f(0);
f(x,y,z);
(当然,这些函数都应该对它们的参数有着同样的抽象行为。)在C++中有三种方法可以这么做:函数重载、使用有缺省值的参数以及使用省略符。对于在同一个函数名中同时使用这三种方法中的多种所出现的结果,C++语言规则有着明确的定义。不过它们比较难以掌握,并且还容易让人觉得惊奇。即使我们能够很好地理解它们,那些维护我们代码的人也可能不一定能够完全掌握它们。对于同一个名字来说,我们应该对它选择一种方案并且一直坚持使用这种方法。
省略符只应该用在类似于printf这样的需要无限(或近似无限)个重载版本的函数中。在使用了省略符的函数中并没有对那些不定参数的类型进行编译期的类型检测,在函数内部我们还必须使用定义于头文件stdarg.h中的充满魔幻色彩的宏[4]来获得那些不定参数。如果函数没有正确获得该参数,那么函数的返回值就将无法确定。
假设我们已经去除了省略符,在使用缺省值和重载之间的选择通常都很容易。使用缺省值可以让我们使用多种不同的方法来同一个函数;使用重载则适用于需要调用不同的函数这种场合之下。
如果这两者之间有一个是另外一个的简化方式,并且同一个实现可以用在这两种场合之下,那么我们最好选择使用带缺省值的方式。例如,我们有一个类String,它的构造函数带有一个const char*的参数,但是我们又希望它有一个缺省的构造函数。为了简便,我们可以使用一个带缺省值的参数:
class String {
//此处忽略细节
public:
String (const char* = "");
};
String s; //等同于“string s("");”
当多个事物在概念上相似,但实现形式又不一致时,我们应该选择使用重载:
void print(const Data&);
void print(const Location&);
void print(const Employee&);
上面三个print在概念上来说是一样的,但它们的实现方法不一样,所以我们必须对它们使用重载。
2.6.1 缺省的指针和引用参数
当我们为指针参数提供缺省值时,下面这个小的语法陷阱就很容易出现:
void f(const char*="");
编译器会将=当作一个单独的token来处理,这样就将造成一个语法错误。我们应该在后面增加一个空格:
void f(const char*="");
对于有着缺省值的引用对象来说,编译器也是同样处理的:
const String empty;
void f(const String& = empty); //语法错误
void f(const String& = empty); //OK