为什么在编译单元中定义多个具有相同名称的函数违反了“一个定义规则”?编译器如何识别违反ODR的代码与使用函数重载的代码之间?
答案 0 :(得分:3)
在C ++中,定义包括参数类型(并且自C ++ 17起为异常规范)。
所以,重命名是可能的,因为即使名称相同,功能也不相同。
答案 1 :(得分:1)
一个定义规则意味着每个重载函数必须定义一次。因此没有矛盾。每个重载函数在某些方面有所不同,例如参数的数量或类型,是否存在c / v限定符(在参数声明或类成员函数本身中)等等。
有时候初学者将这些函数声明视为重载函数的声明
void f( int a[100] );
void f( int a[10] );
void f( int a[] );
void f( int *a );
但是,编译器会隐式地将数组类型的参数调整为数组元素类型的指针。
您可以在程序中包含所有这些(冗余)声明,但必须仅定义一次函数。
因此,上面的声明声明了相同的一个函数,编译器将其参数调整为类型int *
。
考虑到这些函数声明声明了两个重载函数
void f( int *a );
void f( const int *a );
(这里指针本身不是常量,它是指针所指向的数据是常量)
这两个声明
void f( int x );
void f( const int x );
声明相同的一个函数,因为当编译器确定函数是重载还是相同时,const限定符将被丢弃。
当函数参数具有函数类型时,可能会引起同样的困惑。例如
void f( void g() );
void f( void ( *g )() );
同样,编译器会隐式地将函数类型的参数调整为指向该函数的指针。
这是一个演示程序
#include <iostream>
void f( void g() );
void f( void ( *g )() );
void g() { std::cout << "Hello Philippa Richter\n"; }
void f( void g() )
{
g();
}
int main()
{
f( g );
}
其输出为
Hello Philippa Richter
请注意,函数f
仅被定义了一次,尽管它被声明了三次,包括同时声明了它的定义。
答案 2 :(得分:0)
“一个定义规则”不适用于具有相同名称的事物;它适用于假装相同的事物。
两个名为foo
的类(在全局范围内声明,在名称空间,类或函数之外)自称为相同;他们必须一样。如果您在一个程序中更改定义,就会对编译器撒谎。 (这就像根据术语的特殊定义与某人争论,然后假装证明适用于常规术语的某些事物。)
两个名为bar
的函数除非它们具有相同的参数列表,否则它们不会假装相同。