重载函数声明的顺序在 C++ 中重要吗?
Does the order of overloaded function declaration matter in c++?
我目前定义了一个多次重载的函数。对于某些重载定义,它会使用不同类型的输入调用相同的函数。因此,函数 Foo 被定义为采用类型 A,但在函数体内,它调用类型 B 上的 Foo。但是,类型 B 上的 Foo 在定义 A 之后被定义。
我目前在编译时遇到错误,我认为这是由于重载定义的顺序造成的。我没有明确的错误信息和调试工具,所以我想知道上面的场景是否确实会导致错误。
void Foo (A input) {
B b = B();
Foo(b);
}
void Foo (B input) {
printf("%s", input.toString());
}
int main() {
A a = A();
Foo(a);
return 0;
}
//code has been oversimplified
我认为这个问题可以归结为 "does the compiler only check whether function has been defined or does it check whether the function has been defined on particular input?"
重载的声明顺序无关紧要,因为以下是等价的:
// 1.
void foo(int);
void foo(double);
foo(42);
// 2.
void foo(double);
void foo(int);
foo(42);
重载的声明顺序在以下不等价的意义上很重要:
// 3.
void foo(int);
foo(42);
void foo(double);
// 4.
void foo(double);
foo(42);
void foo(int);
简而言之:只有在函数调用之前声明的函数才会参与重载决策。
在您的示例程序中 Foo(A)
要么具有无限递归(如果 B
隐式转换为 A
),要么程序是 ill-formed 因为您还没有声明Foo(B)
通话前。
Does the compiler only check whether function has been defined
一般来说,编译器根本不去检查函数是否已经定义。但是,函数必须在调用之前声明。
简短的回答是肯定的——顺序很重要。 (此外,它实际上与重载无关 - 您可以将 Foo(B)
重命名为 Goo(B)
。)
针对您的特定问题的一种常见补救措施是 forward-declare Foo(B)
:
// Forward declaration
void Foo(B);
void Foo (A input) {
B b = B();
Foo(b); // Compiler now knows about Foo(B), so this is fine.
}
void Foo (B input) {
// ...
}
编译器需要了解该特定函数 - 它必须在使用前声明。但是,它可以在别处定义。在 link 时,收集所有编译器输出并且符号 "linked" 在一起 - linker 将弄清楚如何生成正确的指令以从该行调用 Foo(B)
,或者可能将其内联,等等
有时函数必须是 forward-declared。例如
void Foo() {
if (condition) Goo();
}
void Goo() {
if (condition) Foo();
}
Foo
和 Goo
都需要了解彼此,因此您可以在 Foo()
的定义之前声明两者(或将它们放在 header 中,如果合适的话)。
Does the order of overloaded function declaration matter in c++?
简短回答:是的。 C++ 中的顺序很重要。举个例子:
i = 45;
int i;
这会导致错误(当然假设更高范围内没有其他i
)。它是变量、函数、class 还是其他什么都没有关系;在 C++ 中,符号必须在使用前声明。即使是重载函数,你在定义中使用的任何重载都必须在前面。
绝招
虽然您必须在使用前声明一个函数,但您不必在使用前定义一个函数。我相信一个例子会有所帮助:
void Foo (A input);
void Foo (B input);
这些是函数声明。请注意,它缺少一个定义——即一个实现。这只是告诉编译器有这样一个函数。它不需要知道它做了什么,只知道它在那里。
这对我们有什么帮助?好吧,考虑下面的程序(顺便说一句,它有效):
void Foo (A input);
void Foo (B input);
int main() {
A a = A();
Foo(a);
return 0;
}
void Foo (A input) {
B b = B();
Foo(b);
}
void Foo (B input) {
printf("%s", input.toString());
}
注意到这个程序有什么有趣的地方了吗?我们可以在main()
定义之前调用Foo(A)
。这是将 Foo(A)
的声明放在 main()
的定义之上的好处。编译器知道 Foo(A)
存在,所以我们可以从 main()
调用它,即使我们还没有它的定义。
像这样使用声明的真正有趣之处在于,一旦我们有了声明,我们就可以按任何顺序放置定义.例如,我们可以这样做:
void Foo (A input);
void Foo (B input);
int main() {
A a = A();
Foo(a);
return 0;
}
void Foo (B input) {
printf("%s", input.toString());
}
void Foo (A input) {
B b = B();
Foo(b);
}
或者这个:
void Foo (A input);
void Foo (B input);
void Foo (A input) {
B b = B();
Foo(b);
}
int main() {
A a = A();
Foo(a);
return 0;
}
void Foo (B input) {
printf("%s", input.toString());
}
甚至这样:
void Foo (B input) {
printf("%s", input.toString());
}
int main() {
A a = A();
Foo(a);
return 0;
}
void Foo (A input) {
B b = B();
Foo(b);
}
因为这一切都在声明之后,在这种情况下定义顺序无关紧要。
在我离开之前值得一提的是:如果我们有这样的声明块:
void Foo (A input);
void Foo (B input);
Re-arranging 这个块的顺序无关紧要。所以,我们也可以这样做:
void Foo (B input);
void Foo (A input);
只要这些声明出现在所有定义之前,我们仍然很好。
我目前定义了一个多次重载的函数。对于某些重载定义,它会使用不同类型的输入调用相同的函数。因此,函数 Foo 被定义为采用类型 A,但在函数体内,它调用类型 B 上的 Foo。但是,类型 B 上的 Foo 在定义 A 之后被定义。
我目前在编译时遇到错误,我认为这是由于重载定义的顺序造成的。我没有明确的错误信息和调试工具,所以我想知道上面的场景是否确实会导致错误。
void Foo (A input) {
B b = B();
Foo(b);
}
void Foo (B input) {
printf("%s", input.toString());
}
int main() {
A a = A();
Foo(a);
return 0;
}
//code has been oversimplified
我认为这个问题可以归结为 "does the compiler only check whether function has been defined or does it check whether the function has been defined on particular input?"
重载的声明顺序无关紧要,因为以下是等价的:
// 1.
void foo(int);
void foo(double);
foo(42);
// 2.
void foo(double);
void foo(int);
foo(42);
重载的声明顺序在以下不等价的意义上很重要:
// 3.
void foo(int);
foo(42);
void foo(double);
// 4.
void foo(double);
foo(42);
void foo(int);
简而言之:只有在函数调用之前声明的函数才会参与重载决策。
在您的示例程序中 Foo(A)
要么具有无限递归(如果 B
隐式转换为 A
),要么程序是 ill-formed 因为您还没有声明Foo(B)
通话前。
Does the compiler only check whether function has been defined
一般来说,编译器根本不去检查函数是否已经定义。但是,函数必须在调用之前声明。
简短的回答是肯定的——顺序很重要。 (此外,它实际上与重载无关 - 您可以将 Foo(B)
重命名为 Goo(B)
。)
针对您的特定问题的一种常见补救措施是 forward-declare Foo(B)
:
// Forward declaration
void Foo(B);
void Foo (A input) {
B b = B();
Foo(b); // Compiler now knows about Foo(B), so this is fine.
}
void Foo (B input) {
// ...
}
编译器需要了解该特定函数 - 它必须在使用前声明。但是,它可以在别处定义。在 link 时,收集所有编译器输出并且符号 "linked" 在一起 - linker 将弄清楚如何生成正确的指令以从该行调用 Foo(B)
,或者可能将其内联,等等
有时函数必须是 forward-declared。例如
void Foo() {
if (condition) Goo();
}
void Goo() {
if (condition) Foo();
}
Foo
和 Goo
都需要了解彼此,因此您可以在 Foo()
的定义之前声明两者(或将它们放在 header 中,如果合适的话)。
Does the order of overloaded function declaration matter in c++?
简短回答:是的。 C++ 中的顺序很重要。举个例子:
i = 45;
int i;
这会导致错误(当然假设更高范围内没有其他i
)。它是变量、函数、class 还是其他什么都没有关系;在 C++ 中,符号必须在使用前声明。即使是重载函数,你在定义中使用的任何重载都必须在前面。
绝招
虽然您必须在使用前声明一个函数,但您不必在使用前定义一个函数。我相信一个例子会有所帮助:
void Foo (A input);
void Foo (B input);
这些是函数声明。请注意,它缺少一个定义——即一个实现。这只是告诉编译器有这样一个函数。它不需要知道它做了什么,只知道它在那里。
这对我们有什么帮助?好吧,考虑下面的程序(顺便说一句,它有效):
void Foo (A input);
void Foo (B input);
int main() {
A a = A();
Foo(a);
return 0;
}
void Foo (A input) {
B b = B();
Foo(b);
}
void Foo (B input) {
printf("%s", input.toString());
}
注意到这个程序有什么有趣的地方了吗?我们可以在main()
定义之前调用Foo(A)
。这是将 Foo(A)
的声明放在 main()
的定义之上的好处。编译器知道 Foo(A)
存在,所以我们可以从 main()
调用它,即使我们还没有它的定义。
像这样使用声明的真正有趣之处在于,一旦我们有了声明,我们就可以按任何顺序放置定义.例如,我们可以这样做:
void Foo (A input);
void Foo (B input);
int main() {
A a = A();
Foo(a);
return 0;
}
void Foo (B input) {
printf("%s", input.toString());
}
void Foo (A input) {
B b = B();
Foo(b);
}
或者这个:
void Foo (A input);
void Foo (B input);
void Foo (A input) {
B b = B();
Foo(b);
}
int main() {
A a = A();
Foo(a);
return 0;
}
void Foo (B input) {
printf("%s", input.toString());
}
甚至这样:
void Foo (B input) {
printf("%s", input.toString());
}
int main() {
A a = A();
Foo(a);
return 0;
}
void Foo (A input) {
B b = B();
Foo(b);
}
因为这一切都在声明之后,在这种情况下定义顺序无关紧要。
在我离开之前值得一提的是:如果我们有这样的声明块:
void Foo (A input);
void Foo (B input);
Re-arranging 这个块的顺序无关紧要。所以,我们也可以这样做:
void Foo (B input);
void Foo (A input);
只要这些声明出现在所有定义之前,我们仍然很好。