函数重载和ODR如何共存? (C ++)

时间:2019-07-06 13:25:36

标签: c++ function compilation overloading one-definition-rule

为什么在编译单元中定义多个具有相同名称的函数违反了“一个定义规则”?编译器如何识别违反ODR的代码与使用函数重载的代码之间?

3 个答案:

答案 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的函数除非它们具有相同的参数列表,否则它们不会假装相同。