📜  错误:重载“函数(x)”的调用不明确| C++中函数重载的歧义

📅  最后修改于: 2022-05-13 01:55:10.459000             🧑  作者: Mango

错误:重载“函数(x)”的调用不明确| C++中函数重载的歧义

先决条件:C++ 中的函数重载

函数重载是面向对象编程的一个特性,其中两个或多个函数可以具有相同的名称但不同的参数。当一个函数名被不同的作业重载时,它被称为函数重载。如果两个或多个函数在以下任何一个方面不同,则称它们为重载 -

  1. 参数的数量。
  2. 论据的顺序。
  3. 参数类型。

在函数重载中,有时会出现编译器无法在两个正确重载的函数之间进行选择的情况。这种情况据说是模棱两可的。

歧义语句是产生错误的语句,包含歧义的程序将无法编译。自动类型转换是歧义的主要原因。在 C++ 中,用于调用函数的参数类型转换为函数定义的参数类型。

让我们通过几个例子来理解歧义。

重载函数的调用不明确

示例 1:重载 'test(char)' 的调用不明确

这种歧义是如何发生的:
下面是演示歧义的 C++ 程序。

C++
// C++ program to implement
// the above approach
#include 
using namespace std;
  
// Overloaded Function with
// float type parameter
void test(float f)
{
    cout << "Overloaded Function with float "
         << "parameter being called";
}
  
// Overloaded Function with
// double type parameter
void test(double d)
{
    cout << "Overloaded Function with double "
         << "parameter being called";
}
  
// Driver code
int main()
{
    // Overloaded Function called
    // with char type value
    test('a');
  
    return 0;
}


C++
// C++ program to implement
// the above approach
#include 
using namespace std;
  
// Overloaded Function with
// float type parameter
void test(float f)
{
    cout << "Overloaded Function with float "
         << "parameter being called";
}
  
// Overloaded Function with
// double type parameter
void test(double d)
{
    cout << "Overloaded Function with double "
         << "parameter being called";
}
  
// Driver code
int main()
{
    // Overloaded Function called
    // with char type value
    // typecasted to float
    test((float)('a'));
  
    return 0;
}


C++
// C++ program to implement
// the above approach
#include 
using namespace std;
  
// Overloaded function with
// int type parameter
void test(int f)
{
    cout << "Overloaded Function with "
         << "int type parameter called";
}
  
// Overloaded function with
// double type parameter
void test(double d)
{
    cout << "Overloaded Function with "
         << "double type parameter called";
}
  
// Driver code
int main()
{
    // Overloaded Function called
    // with char type value
    test('a');
    return 0;
}


C++
// C++ program to implement
// the above approach
#include 
using namespace std;
  
// Overloaded function with
// int type parameter
void test(int f)
{
    cout << "Overloaded Function with "
         << "int type parameter called";
}
  
// Overloaded function with
// long type parameter
void test(long l)
{
    cout << "Overloaded Function with "
         << "long type parameter called";
}
  
// Driver code
int main()
{
    // Overloaded Function called
    // with float type value
    test(2.5f);
    return 0;
}


C++
// C++ program to implement
// the above approach
#include 
using namespace std;
  
// Overloaded function with
// int type parameter
void test(int f)
{
    cout << "Overloaded Function with "
         << "int type parameter called";
}
  
// Overloaded function with
// long type parameter
void test(long l)
{
    cout << "Overloaded Function with "
         << "long type parameter called";
}
  
// Driver code
int main()
{
    // Overloaded Function called
    // with float type value
    test((int)(2.5f));
    return 0;
}


C++
// C++ program to implement
// the above approach
#include 
using namespace std;
  
// Overloaded function with
// int type parameter
void test(double d)
{
    cout << "Overloaded Function with "
         << "double type parameter called";
}
  
// Overloaded function with
// long type parameter
void test(long l)
{
    cout << "Overloaded Function with "
         << "long type parameter called";
}
  
// Driver code
int main()
{
    // Overloaded Function called
    // with float type value
    test(2.5f);
    return 0;
}


C++
// C++ program to implement
// the above approach
#include 
using namespace std;
  
// Overloaded Function with
// one int type parameter
void test(int i)
{
    cout << "Overloaded function with "
         << "one int parameter called " << endl;
    cout << i;
}
  
// Overloaded Functionwith
// two int type parameter
void test(int i, int j = 5)
{
    int sum;
    sum = i + j;
  
    cout << "Overloaded function with "
         << "two int parameter called " << endl;
    cout << sum;
}
  
// Driver code
int main()
{
    // Overloaded Function called
    // with two int values
    // Unambiguous call
    test(10, 11);
  
    // Overloaded Function called
    // with one int value
    // Ambiguous call
    test(10);
  
    return 0;
}


C++
// C++ program to implement
// the above approach
#include 
using namespace std;
  
// Overloaded Function with
// one int type parameter
void test(int i)
{
    cout << "Overloaded function with "
         << "one int parameter called " << endl;
    cout << i << endl;
}
  
// Overloaded Functionwith
// two int type parameter
void test(int i, int j)
{
    int sum;
    sum = i + j;
  
    cout << "Overloaded function with "
         << "two int parameter called " << endl;
    cout << sum << endl;
}
  
// Driver code
int main()
{
    // Overloaded Function called
    // with two int values
    // Unambiguous call
    test(10, 11);
  
    // Overloaded Function called
    // with one int value
    // Ambiguous call
    test(10);
  
    return 0;
}


输出:

为什么会出现歧义:

当没有精确的类型匹配时,编译器会寻找最接近的匹配。 “test('a');”的最接近匹配将是“void test(int a)”,因为它不存在,所以 void test(double d) 和 void (float f) 会导致歧义。两者都是有效的转换。这种混淆会导致显示错误消息并阻止程序编译。

笔记:
根据 C 语言规范,任何比 int 短的整数类型,例如 bool、char、short 都会隐式转换为 int。

如何解决歧义:

有两种方法可以解决这种歧义:

  1. 将 char 类型转换为浮动。
  2. 删除歧义生成函数 float 或 double 之一,并添加带有 int 类型参数的重载函数。

解决方案 1:将 char 类型转换为浮动

下面是演示如何将 char 类型转换为 float 解决问题的 C++ 程序。

C++

// C++ program to implement
// the above approach
#include 
using namespace std;
  
// Overloaded Function with
// float type parameter
void test(float f)
{
    cout << "Overloaded Function with float "
         << "parameter being called";
}
  
// Overloaded Function with
// double type parameter
void test(double d)
{
    cout << "Overloaded Function with double "
         << "parameter being called";
}
  
// Driver code
int main()
{
    // Overloaded Function called
    // with char type value
    // typecasted to float
    test((float)('a'));
  
    return 0;
}
输出
Overloaded Function with float parameter being called

解决方案 2:删除歧义生成函数 float 或 double 之一,并添加带有 int 类型参数的重载函数。

下面是一个 C++ 程序,用于演示如何添加带有 int 类型参数的重载函数可以解决上述代码中的歧义。

C++

// C++ program to implement
// the above approach
#include 
using namespace std;
  
// Overloaded function with
// int type parameter
void test(int f)
{
    cout << "Overloaded Function with "
         << "int type parameter called";
}
  
// Overloaded function with
// double type parameter
void test(double d)
{
    cout << "Overloaded Function with "
         << "double type parameter called";
}
  
// Driver code
int main()
{
    // Overloaded Function called
    // with char type value
    test('a');
    return 0;
}
输出
Overloaded Function with int type parameter called

示例 2:重载 'test(float)' 的调用不明确

这种歧义是如何发生的:
下面是一个 C++ 程序,演示了在使用 float 值类型调用重载函数并且没有具有 float 或 double 参数的函数的情况下会发生什么情况。

C++

// C++ program to implement
// the above approach
#include 
using namespace std;
  
// Overloaded function with
// int type parameter
void test(int f)
{
    cout << "Overloaded Function with "
         << "int type parameter called";
}
  
// Overloaded function with
// long type parameter
void test(long l)
{
    cout << "Overloaded Function with "
         << "long type parameter called";
}
  
// Driver code
int main()
{
    // Overloaded Function called
    // with float type value
    test(2.5f);
    return 0;
}

输出:

为什么会出现歧义:
上面的代码会抛出一个错误,因为 test(2.5f)函数调用将查找 float函数,如果不存在它只会提升为 double,但没有函数定义为 double 或 float 类型的参数。

除非明确指定,否则所有浮点字面量在 C++ 中自动为 double 类型。在这种歧义中,浮点类型的变量被隐式转换为双精度类型,如果没有浮点或双精度类型的重载函数并且使用浮点值调用该函数,那么程序将抛出错误。

笔记:
在以下情况下,浮点数会转换为双精度:

  • float 是函数调用的参数,对应于函数原型中的参数类型 double。
  • 二元运算符有 double 和 float 作为两种参数类型。
  • 条件运算符具有 double 和 float 作为第二个和第三个操作数。
  • 浮点值被强制转换为 double。
  • 浮点值被分配给 double。

如何解决歧义:

有两种方法可以解决歧义-

  1. 将 float 类型转换为 int。
  2. 删除歧义生成函数 int 或 long 之一,并添加带有双精度类型参数的重载函数。

解决方案 1:将 float 类型转换为 int

下面是演示如何将 float 类型转换为 int 解决问题的 C++ 程序。

C++

// C++ program to implement
// the above approach
#include 
using namespace std;
  
// Overloaded function with
// int type parameter
void test(int f)
{
    cout << "Overloaded Function with "
         << "int type parameter called";
}
  
// Overloaded function with
// long type parameter
void test(long l)
{
    cout << "Overloaded Function with "
         << "long type parameter called";
}
  
// Driver code
int main()
{
    // Overloaded Function called
    // with float type value
    test((int)(2.5f));
    return 0;
}
输出
Overloaded Function with int type parameter called

解决方案 2:删除歧义生成函数 int 或 long 之一,并添加具有 double 类型参数的重载函数。

下面是一个 C++ 程序,它演示了如何通过添加一个带有双精度类型参数的重载函数来解决这种歧义。

C++

// C++ program to implement
// the above approach
#include 
using namespace std;
  
// Overloaded function with
// int type parameter
void test(double d)
{
    cout << "Overloaded Function with "
         << "double type parameter called";
}
  
// Overloaded function with
// long type parameter
void test(long l)
{
    cout << "Overloaded Function with "
         << "long type parameter called";
}
  
// Driver code
int main()
{
    // Overloaded Function called
    // with float type value
    test(2.5f);
    return 0;
}
输出
Overloaded Function with double type parameter called

使用不同数量的参数调用重载函数

'void test(int, int)函数的重新定义:
让我们看看另一种歧义场景,当它是两个参数并且其中一个参数设置了默认值时,就会出现歧义。

C++

// C++ program to implement
// the above approach
#include 
using namespace std;
  
// Overloaded Function with
// one int type parameter
void test(int i)
{
    cout << "Overloaded function with "
         << "one int parameter called " << endl;
    cout << i;
}
  
// Overloaded Functionwith
// two int type parameter
void test(int i, int j = 5)
{
    int sum;
    sum = i + j;
  
    cout << "Overloaded function with "
         << "two int parameter called " << endl;
    cout << sum;
}
  
// Driver code
int main()
{
    // Overloaded Function called
    // with two int values
    // Unambiguous call
    test(10, 11);
  
    // Overloaded Function called
    // with one int value
    // Ambiguous call
    test(10);
  
    return 0;
}

输出:

为什么会出现歧义:

这里,在明确的调用语句 test(10, 11) 中指定了两个参数,因此没有歧义。在模棱两可的调用语句 test(10) 中,编译器会混淆是调用第一个带有一个参数的函数test() 还是调用带有两个参数的第二个 test()函数,其中一个是默认参数。这会导致程序抛出错误。

如何解决歧义:

解决歧义的一种解决方案是从具有两个 int 参数的重载函数中删除默认值。下面是演示上述方法的 C++ 程序 -

C++

// C++ program to implement
// the above approach
#include 
using namespace std;
  
// Overloaded Function with
// one int type parameter
void test(int i)
{
    cout << "Overloaded function with "
         << "one int parameter called " << endl;
    cout << i << endl;
}
  
// Overloaded Functionwith
// two int type parameter
void test(int i, int j)
{
    int sum;
    sum = i + j;
  
    cout << "Overloaded function with "
         << "two int parameter called " << endl;
    cout << sum << endl;
}
  
// Driver code
int main()
{
    // Overloaded Function called
    // with two int values
    // Unambiguous call
    test(10, 11);
  
    // Overloaded Function called
    // with one int value
    // Ambiguous call
    test(10);
  
    return 0;
}
输出
Overloaded function with two int parameter called 
21
Overloaded function with one int parameter called 
10