【共读Primer】58.[6.5]参数匹配 Page217

一般来说函数的选择是比较明确的事情,因为有着参数类型和参数数量的标准。

但是如果将类型转换和默认参数都加入到重载函数中,这个过程就变的复杂起来。

来看看一下代码:

void f();
void f(int);
void f(int ,int);
void f(double, double = 3.14);

在函数的选择过程中分为两步:

1. 找到当前作用域可见的所有名称相同的函数

2. 找到参数数量相等类型相同或可转换的函数

f(5.6); // 调用 void f(double, double)

那么在一些极端情况下还存在第三部:

3. 寻找最佳匹配

我们知道int和double这两个内置类型是可以进行转化的,所以对上面的函数调用

如果不存在void f(double, double = 3.14), 那么void f(int) 将会被调用 

这里void f(double, double=3.14)就是最佳匹配,

那么我们来看看一个更复杂的情况

f(42, 2.56); // 这个调用完全没有精确的匹配函数,编译器应该如何选择?

我们来编码实际操作一下:

#include <iostream>

void f(){std::cout << "f()" << std::endl;};
void f(int){std::cout << "f(int)" << std::endl;};
void f(int, int){std::cout << "f(int, int)" << std::endl;};
void f(double, double = 3.14){std::cout << "f(double, double = 3.14)" << std::endl;};

int main()
{
    f(5.6);
    f(42, 2.56);
}

对于上面的代码编译情况如下, 意思是编译器也不知道改掉用哪个,两者处于平等位置,没有最优调用

在此类重载的选择上的原则是

1. 每个参数匹配都不劣于其他的函数匹配。

2. 至少有一个参数的匹配优于其他函数

而本次我们写的调用,

针对第一个参数来说f(int, int) 更匹配,但是第二个参数需要做转换。

针对第二个参数来说f(double,double=3.14)更匹配,但是第一个参数需要转换。

所以对于编译器来说两个可行函数的优劣没有区别,无法进行更优选择,则产生二义性错误。

#include <iostream>

void f(){std::cout << "f()" << std::endl;};
void f(int){std::cout << "f(int)" << std::endl;};
void f(int, int){std::cout << "f(int, int)" << std::endl;};
void f(double, double = 3.14){std::cout << "f(double, double = 3.14)" << std::endl;};

int main()
{
    f(5.6);
    // f(42, 2.56);
}

本次代码编译运行结果如下:

实参类型转换

而在参数匹配的过程中类型转换也被划分为几个级别:

1. 精确匹配

以下情形属于精确匹配 :

a. 实参类型和形参类型相同

b. 实参从数组类型或函数类型转换成对应的指着那类型

c. 向实参添加顶层const或者从实参删除顶层const

2. 通过const转换实现的匹配

3. 通过类型提示鞥实现的匹配

4. 通过算术类型转换或指针转换实现的匹配

5. 通过类类型转换实现的匹配

以上的所有情况从上到下的每级的匹配程度低于上一级。

在转换过程中,遵循的原则是从小向打的转换

如short和int的两个匹配类型中如果都需要转换,通常会选择int

void ff(int);
void ff(short);
ff(‘a‘); // char提升为int

而在算数类型的转换中并没有高低的区别。

void manip(long);
void manip(float);
manip(3.14); // 调用将产生二义性

const和参数匹配

非const参数可以作为const实参进行传递,但是const实参不能作为非const参数 传递。

所以当一个函数有const和非const两个版本时,那么将根据参数的精确类型来匹配。

否则将可以使用非const实参调用const形参的函数

void lookup(Account &);
void lookup(const Account&);
const Account a;
Account b;

lookup(a);  // 这个参数只能通过lookup(const Account&)来调用
lookup(b);  // 这个参数两个重载都可以调用,但lookup(Account&)匹配更精确

原文地址:https://www.cnblogs.com/ChattyKu/p/9625549.html

时间: 2024-07-29 19:47:05

【共读Primer】58.[6.5]参数匹配 Page217的相关文章

【共读Primer】46.[6.3]参数传递--main函数处理参数 Page196

前面所讲到的main函数都是空参数列表的. 相信大家都见过启动程序带的参数,那么这些参数时如何传递进去的. 现在我们来看一下main函数声明的完整形式 int main(int argc, char **argv) { for (int i = 0; i < argc; ++i) { std::cout << "command param " << i << " is :"<< argv[i] <<

【共读Primer】10.&lt;2.3&gt; 复合类型 Page45

C++的复合类型 引用和指针 引用就像是类型的别名 int ival = 1024; int &refVal = ival; // int &refVal2 ; // 报错:引用必须被初始化 int &refVal1 = ival, &refVal2 = ival, &refVal3 = refVal1, Val4=ival; // refVal1/refVal2/refVal3都是引用,其中refVal3用另一个引用进行初始化 // Val4是一个int它并不是引

【共读Primer】49.[6.3]返回类型和return语句--关于返回值 Page201

值是如何被返回的 返回值用于初始化调用点的一个临时量. 在下面的函数中,返回值的内容是被拷贝到调用点 string make_plural(size_t ctr, const string &word, const string &ending) { return (ctr > 1) ? word + ending : word; } 在下面的函数中则是将引用型参数作为返回值直接返回了参数的引用 const string & shorterString(const strin

【共读Primer】53.[6.4]函数重载 Page207

在同一个作用域内,几个函数名字相同但形参列表不同,我们成为重载(voerloaded)函数. void print(const char *cp); void print(const int *beg, const int*end); void print(const int ia[], size_t size); int j[2] = {0, 1} print("Hello World"); print(j , end(j) - begin(j)); print(begin(j) -

【共读Primer】64.[7.3]类类型 Page249

类类型 对于类来说每个类的定义都是唯一的类型,即使两个类的成员完全一样,他们仍然是不同的类型 struct First { int memi; int getMem(){return memi;}; }; struct Second { int memi; int getMem(){return memi;}; }; First obj1; Second obj2 = obj1; // 两个不同的类型无法进行赋值操作 类的声明 同函数一样,类也可以只声明而不定义,这种语法的常用场景是在使用类的地

【共读Primer】3.&lt;1.3&gt;注释简介 Page8

C++的注释有两种 1.  双斜杠开始到本行结束 (//) 2. 斜杠星开始 星斜杠结束 (/*)(*/) 1 #include <iostream> // 标准库中输入输出流的库名称 2 /* 3 * 简单主函数: 4 * 读取两个数,求它们的和 5 */ 6 int main() 7 { 8 std::cout << "Enter two numbers:" << std::endl;// 输出一个提示信息的字符串,并在结尾换行 9 int v1

【共读Primer】8.&lt;2.1&gt; 基本内置类型(2) Page32

虽然C++中的类型是强制声明的,但是这并不意味着不同类型之间不可以进行一些计算或赋值. 我们来看下面的一组代码 1 #include <iostream> 2 3 int main() 4 { 5 bool b = 42; 6 int i = b; 7 double pi = i; 8 unsigned char c = -1; 9 signed char c2 = 256; 10 std::cout << "bool b =" << b 11 &l

【共读Primer】19.&lt;3.5&gt; 数组-C风格字符串 Page109

C风格的字符串是指以空字符'\0'结尾的一个字符串. 这种字符串虽然在C++中兼容,但是极易引起内存安全问题,所以不建议使用. 但是作为一个语言特性,我们应该了解它,这样才能在碰到的时候做到心中有数. 3.5.4 C标准库string函数 这里所说的string函数并不是std::string的函数,而是在C的标准库中,对C风格字符串进行操作的一些全局函数. strlen(p); //计算p的长度,不计入空字符结尾 strcmp(p1, p2); // 比较两个字符串p1和p2是否相等,相等返回

【共读Primer】20.&lt;3.6&gt; 多维数组 Page112

C++中的多位数组,严格来说是数组的数组. int ia[3][4]; //大小为3的数组,每个元素是含有4个整数的数组 // 大小为10的数组,每个元素都是大小为20的数组, // 这些数组的元素是含有30个整数的数组 int arr[10][20][30] = {0}; // 将所有元素初始化为 0 初始化多维数组 int ia1[3][4] = { {0,1,2,3}, {4,5,6,7}, {8,9,10,11} }; // 以下语句等价于上面的初始化 int ia2[3][4] = {