【问题标题】:What does "redefinition" mean? [closed]“重新定义”是什么意思? [关闭]
【发布时间】:2014-05-15 11:34:34
【问题描述】:

重新定义是否意味着我们正在尝试定义一个已经定义的实体。这个问题出现在以下代码示例中:

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() 函数,但如果可以的话,它会重新定义吗?

【问题讨论】:

  • @Deduplicator 我不明白重新定义是什么意思。我只是在想。我正在努力理解...
  • 请注意,在 C 中,declarationdefinition 之间存在差异。

标签: c++ redefinition one-definition-rule


【解决方案1】:

局部变量可能会影响全局变量,这就是 :: 范围解析运算符的用途

#include <iostream>
using namespace std;

int a=5;

int main()
{
    int a=3;

    cout << a; // 3
    cout << ::a; // 5
}

所以这里没有ODR 问题。

至于第二个例子,另一个函数内部的函数声明(当它不被最麻烦的解析混淆时),我推荐这个问题:Is there a use for function declarations inside functions?

而且:不,你不能在 main() 中重新定义你的函数。您可以重新声明它(即使使用不同的参数,从而声明一个新函数),但这并不意味着您可以定义它。

我推荐阅读wiki page 的一段精彩摘录:

简而言之,ODR 指出:

  • 在任何翻译单元中,模板、类型、函数或对象都可以 定义不超过一个。其中一些可以有任意数量的 声明。定义提供了一个实例。

  • 在整个 程序、对象或非内联函数不能有多个 定义;如果使用了一个对象或函数,它必须只有一个 定义。您可以声明一个从未使用过的对象或函数, 在这种情况下,您不必提供定义。在任何情况下都不能 有不止一个定义。

  • 有些东西,比如类型、模板、 和 extern 内联函数,可以定义在多个 翻译单元。对于给定的实体,每个定义必须是 相同的。不同翻译单元中的非外部对象和函数 是不同的实体,即使它们的名称和类型相同。

编译器必须诊断出一些违反 ODR 的情况。其他 违规,尤其是跨越翻译单元的违规,不属于 需要确诊。1

【讨论】:

  • 你的意思是重新定义是我们试图重新定义已经定义的实体吗?
  • ODR = 一个 DEFINITION 规则,这意味着你不能重新定义东西,否则你会得到重复的符号。所以是的。
  • 非常感谢。我没有一天试图理解这个概念。现在我明白了。 :)
【解决方案2】:

不,在处理重新定义时,记住 SCOPE 很重要。它仅适用于在 SAME SCOPE 中定义的两个同名变量

在示例 1 中,第二个 a 是 LOCAL SCOPE 并且是函数的局部变量。因此,这就是在退出函数体之前查看和引用的 a

【讨论】:

  • 恰恰相反。重新定义与范围无关。范围处理名称的声明,定义处理名称表示的实体。
【解决方案3】:

没有。 int a = foo();int a = 3;main() 内部是一个新变量,也称为 a

重定义是尝试重新定义同一个变量,例如:

int a = 5;
int a = 6;

还有

int foo();

不是一个定义。这是一个宣言。一个函数定义包括{ }

【讨论】:

  • 这并不能解释我的误解。请参阅我的第一个示例,其中 int 重新定义为 main()。
【解决方案4】:

重新定义在某种程度上会导致编译器时错误。 例如:

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”的最佳匹配,则会出现重新定义和错误。

【讨论】:

  • 你的例子不是重新定义的例子。它们是不相容的名称重新声明。特别是,在任何情况下都不能定义构造 void f();,它始终只是一个声明。
  • 你是对的。然而,问题不完全是关于重新定义,而是关于名称范围的误解。
【解决方案5】:

第一个不是因为范围不同而重新定义,和你想的一样。

第二个是重新声明,但可以根据需要多次重新声明某事,尽管这个笑话会随着重复而变得陈旧。

如果您允许在函数内部定义函数,则可以编写所有语义,因为目前还没有(除了 lambda)。
对于这样做的人,请查看 GCC C 编译器、“嵌套函数”和“语句表达式”。

无论如何,由于单一定义规则,重新定义将是一个错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-29
    • 2014-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-03
    相关资源
    最近更新 更多