English 中文(简体)
调用方法时的C++前向声明问题
原标题:
  • 时间:2009-01-20 06:40:43
  •  标签:

我有一个问题,我认为它与前向声明有关,但也许不只是。

这是相关的代码:

A.h (这是无法被翻译的字符或字符串,请提供更具体的内容或上下文。)

#ifndef A_H_
#define A_H_

#include "抱歉,这个信息无法翻译,因为它缺乏上下文。"

class A
{
    private:
        B b;

    public:
        A() : b(*this) {}
    
        void bar() {}
};

#endif /*A_H_*/

抱歉,这个信息无法翻译,因为它缺乏上下文。

#ifndef B_H_
#define B_H_

#include "A.h (这是无法被翻译的字符或字符串,请提供更具体的内容或上下文。)"

class A;

class B
{
    private:
        A& a;

    public:
        B(A& a) : a(a) {}
    
        void foo() { /*a.bar();*/ } //doesn t compile
};

#endif /*B_H_*/

主要.cpp

#include "A.h (这是无法被翻译的字符或字符串,请提供更具体的内容或上下文。)"

int main()
{
    A a;

    return 0;
}

问题似乎出在A :: bar ()的调用上。 程序成功编译,直到我尝试调用此方法,在这一点上,我收到两个错误:

错误:不完整类型“struct A”的无效使用

错误:结构体A的前向声明

我猜测这是因为A::bar()还未被定义或声明,因为两个头文件互相引用。然而,我前向声明了类A,但不知道还需要做什么。我对C++还不太熟悉,请见谅。我在其他任何地方都找不到这个问题的答案。提前感谢!

最佳回答

您遇到了循环引用问题,需要将B.h分离出来。可以尝试这样做:

I'm sorry, but "B.h" doesn't have a clear meaning or context in English, so I can't provide an accurate translation into Chinese. Could you please provide more information or context?

#ifndef B_H_
#define B_H_

// don t include A.h here!

class A;

class B
{
   private:
      A& a;

   public:
      B(A& a) : a(a) {}

      void foo();
};

#endif /*B_H_*/

B.cpp:(B点C++程序文件)

#include "B.h"
#include "A.h"

void B::foo() { a.bar(); } // now you re ok

编辑:为什么需要将它分成两个文件的解释:

B包含对A的引用,它可以是所谓的不完整类型。您无法对其调用任何函数,因为编译器还不知道A是什么 - 它只知道它是某种类别的类。一旦您包含了A.h(在.cpp文件中),那么A就是一个完整的类型,您可以随心所欲地使用它。

你不能把所有东西都放在一个头文件里,因为你会得到一个循环引用。你用你的包含保护来防止无限循环,但你得到了一个你不想要的东西。看看编译器在你以前编译 main.cpp 时得到了什么。

// #include "A.h" ==>
#define A_H_

// #include "B.h" ==>
#define B_H_

// #include "A.h" ==> nothing happens! (since A_H_ is already defined)

class A;

class B {
private:
    A& a;

public:
    B(A& a) : a(a) {}

    void foo() { a.bar(); } // <-- what the heck is A here?
                            //     it s not defined until below
};

class A {
private:
   B b;

public:
   A() : b(*this) {}

   void bar() {}
};

int main() {
    A a;
    return 0;
}
问题回答

#include 这一行将只是用的内容替换该行。因此,当计算机尝试编译您的main.cpp时,它将把所有内容汇集在一起,看起来像以下内容。在您想要使用A::bar()的位置,它还没有被定义。

// result from #include "A.h"

#ifndef A_H_
#define A_H_

// Now, #include "B.h" in A.h will get you the following
#ifndef B_H_
#define B_H_

// here you include "A.h" again, but now it has no effect
// since A_H_ is already defined

class A;

class B
{
    private:
            A& a;
    public:
            B(A& a) : a(a) {}
            // Oops, you want to use a.bar() but it is not defined yet
            void foo() { /*a.bar();*/ } 
};

#endif /*B_H_*/

class A
{
    private:
            B b;
    public:
            A() : b(*this) {}
            void bar() {}
};
#endif /*A_H_*/

// now this is your main function
int main()
{
    A a;
    return 0;
}

正如其他人所提到的,循环引用似乎是您的问题。 另一个短语是“相互依赖”。 但是,与其尝试找到正确的语法使您的应用程序编译和运行(我假设实际问题存在于您发布的程序略微更高级的程序中),不如从面向对象设计的角度攻击问题。

一般规则是,在任何可能的情况下都应该避免相互依赖。我以前在自己的代码中遇到过这个问题(导致了好几天的调试,拉扯头发,咒骂编译器),现在我终于能够克服它了。我将以一个简化版的问题作为具体示例,来演示如何处理这个问题,希望你能够理解其中的含义,并最终理解一切。

假设我们有两个类:Data和DataAnalyzer

数据持有对数据分析器的引用(用于分析数据),而数据分析器持有对数据的引用(需要分析的数据)——相互依赖!为了消除这种依赖关系,我们从DataAnalyzer中提取一个接口(在C++中,纯虚类),该接口定义了DataAnalyzer所需的公共方法/属性。它可能看起来像:

class IAnalyzer
{
public:
    virtual void Analyze () = 0;
};

当我们定义 DataAnalyzer 时,我们这样做:

class DataAnalyzer : public IAnalyzer
{
public:
    DataAnalyzer (Data* data);

    virtual void Analyze (); // defined in DataAnalyzer.cpp
};

数据看起来像:

class Data
{
public:
    Data ();

    IAnalyzer* Analyzer;
};

在你的控制器类中的某个地方,你可能有类似以下的代码:

void main ()
{
    Data*  data = new Data ();
    data->Analyzer = new DataAnalyzer (data);
}

现在,数据独立存在(就其而言,我不知道IAnalyzer需要数据的引用),只有DataAnalyzer依赖于数据。如果您想继续进行,可以继续删除DataAnalyzer对数据的依赖性,但为了简单地打破相互依赖关系,这应该已足够。

警告:我没有对这段代码进行编译测试,因此可能需要进行一些小的调整才能正确编译和运行。

祝你好运!

如果你真的想让B :: foo成为内联,你可以在B.h中进行实现,但我不建议这样做。

B.h:无法翻译,因为它没有明确定义或上下文。请提供更多细节。

#ifndef B_H_
#define B_H_

// Forward declaration of A.
class A;

class B
{
private:
    A& a;

public:
    B(A& a) : a(a) {}

    void foo();
};

// Include definition of A after definition of B.
#include "A.h"

inline void B::foo()
{
    a.bar();
}

#endif /*B_H_*/

我不确定"A.h"是什么意思,因此无法准确地翻译。如果您可以提供更多上下文或信息,我可以帮助您翻译。

// Include definition of B before definition of A.
// This must be done before the ifndef A_H_ include sentry,
// otherwise A.h cannot be included without including A.h first.
#include "B.h"

#ifndef A_H_
#define A_H_

class A
{
private:
    B b;

public:
    A() : b(*this) {}

    void bar() {}
};

#endif /*A_H_*/

在B.h中,你同时包括A.h并向前声明A。

您需要将B.h分成B.h和B.cpp,或者删除前向声明。

附言:您还有循环依赖。A.h包含B.h,反之亦然。不过您的守卫已经捕捉到了这个问题;)

补充到其他答案中(循环引用,这是正确的答案),如果您来自C#/Java,请了解C ++不同之处在于文件按顺序解析(而不是作为整体考虑)。因此,您需要小心确保在实际包含文件的顺序(和/或将功能分开到.cpp文件中)中定义了所有内容,然后再使用它。





相关问题
热门标签