C++ 有没有办法解决循环依赖?
C++ Is there a way to work around circular dependency?
现在我知道在 C++ 中任何东西都必须在使用之前声明。但是如果我有两个相互引用的函数呢?
例如:
void func1() {
func2();
}
void func2() {
func1();
}
完全不可能做到这一点吗?
前向声明正是您想要的:
void func2(); // forward declare func2
void func1() {
func2();
}
void func2() {
func1();
}
第一个void func2();
称为前向声明。你保证你最终会按照这个原型来定义它。
您可以简单地将一个函数放在另一个函数中,然后表示为 class 的(通常 static
)成员函数,或表示为 lambda。
这假设来自其他地方的顶级调用总是针对其中一个函数。
另一种可能性,两个函数都可用于顶级调用代码,将两个函数放置为(最自然的 static
)class 的成员,其中它们可以内联定义.
但我认为只使用前向声明更干净。
确实没有任何充分的理由避免它,所以像上面提到的那样的解决方法只会让其他程序员浪费一些时间挠头——这到底是什么为了?
修正案:class范围方法示例:
struct Recursive
{
static void func1() { if( some_condition ) { func2(); } }
static void func2() { if( some_condition ) { func1(); } }
};
嵌套函数方法示例:
void func1()
{
const auto func2 = []{ if( some_condition ){ func1(); } }
if( some_condition ) { func2(); }
}
如果没有某种前向声明,那段代码是不可能的吗?是的。想想看,编译器到这里的时候:
void func1() {
func2();
}
他以前从未见过func2
,因此无法编译。
大多数人会创建一个包含函数声明的 .h
文件,这样您就可以避免此类事情。例如,
foo.h
void func1();
void func2();
foo.c
#include "foo.h"
void func1() {
func2();
}
void func2() {
func1();
}
您需要转发声明 func2()
才能在 func1()
:
中使用它
void func2();
void func1() {
func2();
}
void func2() {
func1();
}
现在在 func1()
引用 func2()
、func2()
的位置已经声明,并且在 func2()
引用 func1()
、func1()
将被宣布。
但是,调用这两个函数中的任何一个都会导致死循环,从而导致堆栈溢出。
成员函数当然可以。例如:
class A {
void func1() {
func2();
}
void func2() {
func1();
}
};
如果您需要两个 类 相互了解,问题可能会更多,但这是否回答了您的问题?
编辑:您不需要在定义之前声明成员函数。
您应该接受其他答案之一,因为这就是 C++ 语言的工作方式并且对此无能为力,如果您担心编写大量转发很痛苦,您应该注意一些框架已经提供 headers 只是为了提前声明一些东西,这样用户就不会拥有了。
这是为了方便,当确实有很多东西是前向声明的,或者有一些东西需要正确声明时(例如模板、别名,我偶尔也会看到一些宏技巧)。
此外,通常您必须将声明和定义放在不同的文件中,以避免在可能的情况下重新编译,并且通常会使项目更加清晰和易于管理。
Functions.hpp
void func();
void func2();
Functions.cpp
#include "Functions.hpp"
void func(){
func2();
}
void func2(){
func();
}
用户代码:
main.cpp
#include "Functions.hpp"
int main(){
func();
return 0;
}
另请注意,您对 "Declaration" 和 "Forward Declaration" 有一些困惑。
实际上,当您在代码中放置函数签名时,您就是在声明它:
int function3(); // function declared
前向声明 是关于告诉 class 存在而不告诉任何关于其签名的更多信息:
class myclass; //forward declaration
//possible declarations using "myclass" forward declaration
int function4(myclass & ref);
int function5(myclass * ref);
前向声明用于保持 headers 简单并通过将不需要的细节移至实现 (.cpp) 文件来减少编译时间(在某些情况下很多)。
现在我知道在 C++ 中任何东西都必须在使用之前声明。但是如果我有两个相互引用的函数呢? 例如:
void func1() {
func2();
}
void func2() {
func1();
}
完全不可能做到这一点吗?
前向声明正是您想要的:
void func2(); // forward declare func2
void func1() {
func2();
}
void func2() {
func1();
}
第一个void func2();
称为前向声明。你保证你最终会按照这个原型来定义它。
您可以简单地将一个函数放在另一个函数中,然后表示为 class 的(通常 static
)成员函数,或表示为 lambda。
这假设来自其他地方的顶级调用总是针对其中一个函数。
另一种可能性,两个函数都可用于顶级调用代码,将两个函数放置为(最自然的 static
)class 的成员,其中它们可以内联定义.
但我认为只使用前向声明更干净。
确实没有任何充分的理由避免它,所以像上面提到的那样的解决方法只会让其他程序员浪费一些时间挠头——这到底是什么为了?
修正案:class范围方法示例:
struct Recursive
{
static void func1() { if( some_condition ) { func2(); } }
static void func2() { if( some_condition ) { func1(); } }
};
嵌套函数方法示例:
void func1()
{
const auto func2 = []{ if( some_condition ){ func1(); } }
if( some_condition ) { func2(); }
}
如果没有某种前向声明,那段代码是不可能的吗?是的。想想看,编译器到这里的时候:
void func1() {
func2();
}
他以前从未见过func2
,因此无法编译。
大多数人会创建一个包含函数声明的 .h
文件,这样您就可以避免此类事情。例如,
foo.h
void func1();
void func2();
foo.c
#include "foo.h"
void func1() {
func2();
}
void func2() {
func1();
}
您需要转发声明 func2()
才能在 func1()
:
void func2();
void func1() {
func2();
}
void func2() {
func1();
}
现在在 func1()
引用 func2()
、func2()
的位置已经声明,并且在 func2()
引用 func1()
、func1()
将被宣布。
但是,调用这两个函数中的任何一个都会导致死循环,从而导致堆栈溢出。
成员函数当然可以。例如:
class A {
void func1() {
func2();
}
void func2() {
func1();
}
};
如果您需要两个 类 相互了解,问题可能会更多,但这是否回答了您的问题?
编辑:您不需要在定义之前声明成员函数。
您应该接受其他答案之一,因为这就是 C++ 语言的工作方式并且对此无能为力,如果您担心编写大量转发很痛苦,您应该注意一些框架已经提供 headers 只是为了提前声明一些东西,这样用户就不会拥有了。
这是为了方便,当确实有很多东西是前向声明的,或者有一些东西需要正确声明时(例如模板、别名,我偶尔也会看到一些宏技巧)。
此外,通常您必须将声明和定义放在不同的文件中,以避免在可能的情况下重新编译,并且通常会使项目更加清晰和易于管理。
Functions.hpp
void func();
void func2();
Functions.cpp
#include "Functions.hpp"
void func(){
func2();
}
void func2(){
func();
}
用户代码: main.cpp
#include "Functions.hpp"
int main(){
func();
return 0;
}
另请注意,您对 "Declaration" 和 "Forward Declaration" 有一些困惑。
实际上,当您在代码中放置函数签名时,您就是在声明它:
int function3(); // function declared
前向声明 是关于告诉 class 存在而不告诉任何关于其签名的更多信息:
class myclass; //forward declaration
//possible declarations using "myclass" forward declaration
int function4(myclass & ref);
int function5(myclass * ref);
前向声明用于保持 headers 简单并通过将不需要的细节移至实现 (.cpp) 文件来减少编译时间(在某些情况下很多)。