重新定义是否意味着我们正在尝试定义一个已经定义的实体?这个问题出现在下面的代码示例中:
int a=5;
int main()
{
int a=3;//redefinition? I think no, because `int a` denote an entity different from the global "a"
}
和另一个例子:
int foo(){ return 1; }
int main()
{
int foo();
int a=foo();//Now a is 1
}
我们不能在main()
函数体中定义刚刚声明的foo()
函数,但是如果可以的话,它会被重新定义吗?
局部变量可能会遮蔽全局变量,这就是::
作用域解析运算符对
#include <iostream>
using namespace std;
int a=5;
int main()
{
int a=3;
cout << a; // 3
cout << ::a; // 5
}
所以这里没有ODR问题。
至于第二个例子,函数声明在另一个函数内(当它不被最令人烦恼的解析混淆时),我建议这个问题:函数内的函数声明有什么用?和:不,你不能在main()中重新定义函数。您可以重新声明它(即使使用不同的参数,从而声明一个新函数),但这并不意味着您可以这样定义。
我推荐你阅读维基页面上的一段精彩摘录:
简而言之,ODR声明:
在任何翻译单元中,模板、类型、函数或对象都可以定义不超过一个。其中一些可以有任意数量的声明。定义提供了一个实例。
在整个程序中,对象或非内联函数不能有多个定义;如果使用对象或函数,则必须只有一个定义。你可以声明一个永远不会用到的对象或函数,在这种情况下,您不需要提供定义。无论如何也不能定义不止一个。
有些东西,比如类型,模板,而外部内联函数,可以定义在一个以上翻译单元。对于给定的实体,每个定义必须是相同。不同翻译单位中的非外部对象和函数是不同的实体,即使它们的名称和类型相同。
某些违反ODR的行为必须由编译器诊断。其他违反,特别是那些跨越翻译单元的违反,则不是需要诊断。1
不,在处理重定义时,记住SCOPE是很重要的。它只适用于在同一作用域
中定义的具有相同名称的两个变量在示例1中,第二个a是LOCAL SCOPE,并且是函数的局部。因此,这就是在退出函数体
No。int a = foo();
或int a = 3;
,在main()
里面,是一个新的变量,也叫做a
。
重定义是试图重新定义相同的变量,例如:
int a = 5;
int a = 6;
也int foo();
不是定义。这是一个宣言。函数定义包括{ }
重定义在某种程度上会导致编译时错误。例如:
int a;
bool a;
或
void f();
int f;
在你的例子中,没有编译时错误。它是关于名称隐藏,范围和解析规则。
int a = 5;
{
int a = 6; //because of { } internal a is in other scope and can be defined without error
int b = a; //b == 6
}
int b = a; //b == 5
在最后一种情况下,你有两个不同的"a",每个都在自己的程序范围内。在程序的某一点上,如果您使用"a"这样的名称,则在该名称后面只有一个实体。如果编译器不能在不同的变体之间找到"a"的最佳匹配,你会得到重新定义和错误。
第一个不是像你想的那样由于作用域不同而重新定义的
第二个是重新声明,但是你可以多次重新声明一些东西,尽管这个笑话会随着重复而变得陈旧。
如果你允许在函数内部定义函数,你就可以编写所有的语义,因为现在还没有这样的(除了lambda)。
对于这样做的人,请查看GCC C编译器,"嵌套函数"one_answers"语句表达式"。
无论如何,重新定义将是一个错误,由于一个定义规则。