我目前定义了一个函数,该函数会多次重载。对于某些重载的定义,它使用不同的输入类型调用相同的函数。因此,将函数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
我认为这个问题可以归结为“编译器只检查是否已定义函数,还是只检查特定输入上是否已定义函数?”
答案 0 :(得分:5)
在以下等价的意义上,重载的声明顺序无关紧要:
// 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
),或者由于您未声明{{1} }。
编译器是否仅检查功能是否已定义
通常,编译器根本不检查是否已定义函数。但是,必须先声明函数才能调用。
答案 1 :(得分:3)
答案很简单-顺序很重要。 (此外,它确实与重载无关-您可以将Foo(B)
重命名为Goo(B)
。)
针对您的特定问题的一种常见补救方法是向前声明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) {
// ...
}
编译器需要了解该特定功能-在使用前必须已声明。但是,可以在其他地方定义。在链接时,将收集所有编译器输出,并将符号“链接”在一起-链接器将找出如何产生正确的指令以从该行调用Foo(B)
,或可能对其进行内联等等。
有时可能必须对函数进行前向声明。例如
void Foo() {
if (condition) Goo();
}
void Goo() {
if (condition) Foo();
}
Foo
和Goo
都需要彼此了解,因此您可以在Foo()
的定义之前声明两者(或在适当的情况下将它们放在标题中)。
答案 2 :(得分:1)
重载函数声明的顺序在c ++中重要吗?
简短的回答:是的。顺序在C ++中很重要。请看以下示例:
i = 45;
int i;
这将导致错误(当然,假设更高范围中没有其他i
)。它是变量,函数,类还是其他东西都没有关系。在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());
}
注意到此程序有什么有趣的地方吗?我们可以在定义之前在Foo(A)
中调用main()
。将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);
重新排列此块的顺序无关紧要。因此,我们也可以这样做:
void Foo (B input);
void Foo (A input);
只要这些声明先于所有定义,我们还是不错的。