重载函数声明的顺序在 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
我认为这个问题可以归结为"编译器是只检查函数是否已定义,还是检查函数是否已在特定输入上定义?
重载的声明顺序无关紧要,因为以下内容是等效的:
// 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
),要么程序格式不正确,因为您尚未在调用之前声明Foo(B)
。
编译器是否只检查是否已定义函数
通常,编译器根本不检查是否已定义函数。但是,必须先声明函数,然后才能调用它。
简短的回答是肯定的 - 顺序很重要。 (此外,它实际上与重载无关 - 您可以将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()
的定义之前声明两者(或者如果合适,将它们放在标题中)。
重载函数声明的顺序在 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());
}
注意到这个程序有什么有趣的东西了吗?我们可以在定义之前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);
重新排列此块的顺序无关紧要。因此,我们也可以这样做:
void Foo (B input);
void Foo (A input);
只要这些声明出现在所有定义之前,我们仍然很好。
- "error: no matching function for call to"构造函数错误
- 什么时候调用组成单元对象的析构函数
- 继承函数的重载解析
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- C++模板来检查友元函数的存在
- 递归函数计算序列中的平方和(并输出过程)
- 对RValue对象调用的LValue ref限定成员函数
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 在C++STL中是否有Polyval(Matlab函数)等价物?
- 为什么使用 "this" 指针调用派生成员函数?
- 将对象数组的引用传递给函数
- 函数调用中参数的顺序重要吗
- 函数向量_指针有不同的原型,我可以构建一个吗
- 使用不带参数的函数访问结构元素
- 代码在main()中运行,但在函数中出现错误
- 内置函数可查看CPP中的成员变量
- 如何获取std::result_of函数的返回类型
- 如何在c++中为模板函数实例创建快捷方式
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗