在C++中使用前向声明的错误

在C++中使用前向声明的错误

问题描述:

我想在C++中编写一个简单的程序,我有2个类,并且都可以访问对方的函数。这是我最后想要做的事情的一个简化,那就是创建一个包含棋类和棋子类的游戏。我可以在java中做到这一点,但我现在遇到了一些问题,试图在C++中做同样的事情。我的代码如下:在C++中使用前向声明的错误

#include <iostream> 
class B; 
class A { 
    public: 
      void sync(B obj){ 
        b = obj; 
      } 
      void print(){ 
        std::cout << "Hello from class A" << std::endl; 
      } 
      void printBoth(){ 
        std::cout << "Hello from class A" << std::endl; 
        b.print(); 
      } 
    private: 
      B b; 
}; 

class B { 
    public: 
      B(A obj){ 
        a = obj; 
      } 
      void print(){ 
        std::cout << "Hello from class B" << std::endl; 
      } 
      void printBoth(){ 
        std::cout << "Hello from class B" << std::endl; 
        a.print(); 
      } 
    private: 
      A a; 
}; 

int main(){ 
    A a; 
    B b(a); 
    a.sync(b); 
    a.printBoth(); 
    std::cout << std::endl; 
    b.printBoth(); 
    return 0; 
} 

当我试着使用g++ example.cpp编译此,我收到5个错误:

example.cpp:20:5: error: field ‘b’ has incomplete type 
B b; 
^ 
example.cpp: In member function ‘void A::sync(B)’: 
example.cpp:7:8: error: ‘obj’ has incomplete type 
void sync(B obj){ 
    ^
example.cpp:3:7: error: forward declaration of ‘class B’ 
class B; 
^
example.cpp:8:4: error: ‘b’ was not declared in this scope 
b = obj; 
^ 
example.cpp: In member function ‘void A::printBoth()’: 
example.cpp:17:4: error: ‘b’ was not declared in this scope 
b.print(); 
^ 

我从来没有使用前置声明带班,所以我道歉,如果我的思念显而易见的东西。任何帮助表示赞赏,我提前感谢你。

+2

系绳向前声明,考虑一下:'A'有一个正式成员'B'。因此,如果没有构建“B”,那么'A'就不可能存在(不知何故,稍后会有更多介绍)。现在,'B'有一个构造函数,它将一个完整的值'A'作为唯一参数。因此,只有存在“A”时才能存在“B”,直到存在“B”时才能存在“A”。简而言之,转发声明不是问题。设计本身被打破。我认为很快就会有一些*参考文献*,因为无论您是否知道,Java都是这样管理的。 – WhozCraig

+0

您应该使用'inheritance'而不是'aggregation'。 – has

+0

当正向声明时应该提供指针,以便编译器不应该计算B对象的大小。在你的示例中,编译器需要计算A中B对象的大小,编译器应该如何知道这一点? – user3655463

您的代码有两个问题。

让我们来看第一个问题。

下面是两个方法相互调用的例子。相当无意义,并导致无限循环,但是这显示了前向声明的一般原则,您可以使用它作为模板来修复您所显示的代码。

class A { 

public: 
    void foo(); 
}; 

class B { 

public: 
     void foo(); 
}; 

void A::foo() 
{ 
    B b; 

    b.foo(); 
} 

void B::foo() 
{ 
    A a; 

    a.foo(); 
}; 

现在,你的代码的第二个问题:

书面,类A包含B类,它包含A类的实例,它包含A类的实例,实例,其包含B类的一个实例,直到宇宙在一个巨大的黑洞中内爆。只要说,这不会编译。

C++对象与Java对象有根本的不同。他们以完全不同的方式工作。你可以用Java来做这件事,因为这个肮脏的小秘密就是Java中的所有对象都是真正的海市蜃楼,它们实际上是引用计数的指向实际对象的指针。在C++中,这样做的最接近的将是一个std::shared_ptr申报对象:

#include <memory> 

class A; 
class B; 

class A { 

    // ... 

    private: 
      std::shared_ptr<B> b; 
}; 

class B { 

    // ... 

    private: 
      std:shared_ptr<A> a; 
}; 

,这将是与你的代码所示的第二个问题。一般来说,在学习C++对象时,你几乎忘记了所有关于Java对象的知识。它们有着根本的不同,并且试图在你已经了解的Java对象和C++对象之间持续地绘制类比,只会导致混淆。

+0

谢谢你的帮助。我将尽力在将来关注java和C++之间的差异。我能够用一个传递给每个类的对象实际上使用第三个类来修复它,但我也会尝试这个。在更复杂的情况下,我的解决方案可能不太可取,但它在这里起作用。 – acn3

你总是可以尝试重新设计,即:

#include <iostream> 
#include "A.hpp" 

int main(){ 
    A a; 
    B b(a); 
    a.sync(b); 
    a.printBoth(); 
    std::cout << std::endl; 
    b.printBoth(); 
    return 0; 
} 

B.hpp:

class A; 

class B { 
    public: 
      B() {} 
      B(A obj); 
      void print(); 
      void printBoth(); 
    private: 
      A* a; 
}; 

B.cpp:

#include <iostream> 
#include "A.hpp" 

      B::B(A obj){                  
        a = new A(obj);               
      }                    
      void B::print(){                 
        std::cout << "Hello from class B" << std::endl;       
      }                    
      void B::printBoth(){                
        std::cout << "Hello from class B" << std::endl;       
        a->print();                
      } 

A.hpp:

#include "B.hpp" 

class A { 
    public: 
      void sync(B obj); 
      void print(); 
      void printBoth(); 
    private: 
      B b; 
}; 

A.cpp:

#include <iostream> 
#include "A.hpp" 
    void A::sync(B obj){ 
       b = obj; 
    } 
    void A::print(){ 
     std::cout << "Hello from class A" << std::endl; 
    } 
    void A::printBoth(){ 
     std::cout << "Hello from class A" << std::endl; 
     b.print(); 
    }