C++;:将此指针传递给另一个类 我是C++新手,但我在java方面有一些经验。 在编写代码时,我偶然发现了一个让我困惑的错误。 以下是我的代码(简化,但错误相同):

C++;:将此指针传递给另一个类 我是C++新手,但我在java方面有一些经验。 在编写代码时,我偶然发现了一个让我困惑的错误。 以下是我的代码(简化,但错误相同):,c++,pointers,parameter-passing,this,member,C++,Pointers,Parameter Passing,This,Member,A.h: #pragma once #include "B.h" class A { public: A(); void foo(); void sayHello(); B b; }; #include "A.h" #include <iostream> A::A() {} void A::foo() { b.bar(this); } void A::sayHello() { std::cout << "Hell

A.h:

#pragma once
#include "B.h"
class A
{
public:
    A();
    void foo();
    void sayHello();
    B b;
 };
#include "A.h"
#include <iostream>    
A::A() {}
void A::foo() {
    b.bar(this);
}
void A::sayHello() {
    std::cout << "Hello" << std::endl;
}
#pragma once
#include "A.h"
class B
{
public:
    B();
    void bar(A *a);
};
#include "B.h"
B::B(){}
void B::bar(A *a) {
    a->sayHello();
}
A.cpp:

#pragma once
#include "B.h"
class A
{
public:
    A();
    void foo();
    void sayHello();
    B b;
 };
#include "A.h"
#include <iostream>    
A::A() {}
void A::foo() {
    b.bar(this);
}
void A::sayHello() {
    std::cout << "Hello" << std::endl;
}
#pragma once
#include "A.h"
class B
{
public:
    B();
    void bar(A *a);
};
#include "B.h"
B::B(){}
void B::bar(A *a) {
    a->sayHello();
}
B.cpp:

#pragma once
#include "B.h"
class A
{
public:
    A();
    void foo();
    void sayHello();
    B b;
 };
#include "A.h"
#include <iostream>    
A::A() {}
void A::foo() {
    b.bar(this);
}
void A::sayHello() {
    std::cout << "Hello" << std::endl;
}
#pragma once
#include "A.h"
class B
{
public:
    B();
    void bar(A *a);
};
#include "B.h"
B::B(){}
void B::bar(A *a) {
    a->sayHello();
}
我想把一个对象的指针传递给B中的bar函数,这样我就可以修改和访问a在bar中的字段。奇怪的是,当我通过另一个类的实例调用foo时,我会遇到以下错误:

1>------ Build started: Project: Test, Configuration: Debug Win32 ------
1>  main.cpp
1>d:\stuff\visual studio 2015\projects\test\test\b.h(7): error C2061: syntax error: identifier 'A'
1>  B.cpp
1>d:\stuff\visual studio 2015\projects\test\test\a.h(9): error C3646: 'b': unknown override specifier
1>d:\stuff\visual studio 2015\projects\test\test\a.h(9): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>  A.cpp
1>d:\stuff\visual studio 2015\projects\test\test\b.h(7): error C2061: syntax error: identifier 'A'
1>d:\stuff\visual studio 2015\projects\test\test\a.cpp(5): error C2660: 'B::bar': function does not take 1 arguments
1>  Generating Code...
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
如果我在B.h中不包含A.h,并且不向bar函数传递任何内容,那么代码就可以正常工作


我试着用谷歌搜索什么会导致这些错误,但我无法自己解决这个问题,因为我不明白是什么导致了这些错误。我做错了什么?

在A.h的头文件中,您有:

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

B.h的头文件中,您有:

#include "B.h"
#include "A.h"
您有一个循环include,其中
a
B
的定义相互依赖


一个简单的解决方案是在定义
B类时使用:

  • 将文件B.h中的
    #include“A.h”
    行替换为
    B类
  • 添加
    #在B.cpp的开头包含“A.h”

  • 但是请注意,您不能对
    class A
    使用向前声明,原因是您有
    class b
    b
    值作为
    class A
    的成员变量:

    #pragma once
    #include "B.h"
    class A
    {
    public:
        A();
        void foo();
        void sayHello();
        B b;             /// I mean this line here more specifically
     };
    

    编译器需要知道类B的定义,才能确定类A的正确大小。这就是为什么必须将
    #包括“B.h”
    放在A.h的开头

    两个标题都相互引用。编译器只能首先计算一个类,而不能解析另一个头中对该类的引用。这一错误并不明显,但“once”pragma使一个标题包含如您所期望的那样不发生

    如果B.h头文件不需要知道关于A类的实现细节(在本例中不需要知道),则不要将A.h文件包含在B.h中。相反,请将bar()的函数声明更改为如下所示:

    bar( class A *a );
    
    编译器可以从中生成代码,将指针传递到对象,而不知道a的内部内容。它不需要a.h头

    然后在B.cpp中的B.h头文件之后包含A.h头文件


    我对此进行了测试,它对我很有效。

    让我们看看B.cpp,看看includes会发生什么:

    #include "B.h"
    
    B::B(){}
    void B::bar(A *a) {
        a->sayHello();
    }
    
    将B.h粘贴在include的位置,我们得到:

    #include "A.h"
    
    class B
    {
    public:
        B();
        void bar(A *a);
    };
    
    
    B::B(){}
    void B::bar(A *a) {
        a->sayHello();
    }
    
    然后将A.h替换为其包括:

    #include "B.h"
    class A
    {
    public:
        A();
        void foo();
        void sayHello();
        B b;
     };
    
    class B
    {
    public:
        B();
        void bar(A *a);
    };
    
    
    B::B(){}
    void B::bar(A *a) {
        a->sayHello();
    }
    
    这里我们停下来是因为
    pragma once
    阻止了B.h.的重新纳入

    我们可以看到,在类
    A
    的定义中,我们有
    B,但尚未定义类
    B
    。卡布姆<如果没有
    B
    ,则无法定义代码>A
    ,并且尚未定义
    B

    A
    的大小必须为
    B
    才能满足
    B
    ,因此它需要
    B
    的完整定义
    B
    只需要知道
    A
    存在,因为它只需要一个指向
    A
    的指针即可满足
    无效条(A*A)。所以

    A.h

    #pragma once
    #include "B.h"
    class A
    {
    public:
        A();
        void foo();
        void sayHello();
        B b;
    };
    
    #pragma once
    
    class A; // forward definition of class A
    class B
    {
    public:
        B();
        void bar(A *a);
    };
    
    A.cpp

    #include "A.h"
    #include <iostream>    
    A::A() {}
    void A::foo() {
        b.bar(this);
    }
    void A::sayHello() {
        std::cout << "Hello" << std::endl;
    }
    
    #include "A.h"
    B::B(){}
    void B::bar(A *a) {
        a->sayHello();
    }
    
    B.cpp

    #include "A.h"
    #include <iostream>    
    A::A() {}
    void A::foo() {
        b.bar(this);
    }
    void A::sayHello() {
        std::cout << "Hello" << std::endl;
    }
    
    #include "A.h"
    B::B(){}
    void B::bar(A *a) {
        a->sayHello();
    }
    
    请执行以下更改:

    B.h:-正向声明
    A

    #pragma once
    // #include "A.h"
    class A;
    //^^^^^^
    
    class B {
    public:
        B();
        void bar(A *a);
    };
    
    B.cpp
    #包括“A.h”


    就是这样。

    查找循环包含和转发声明循环引用。更多信息:和这里:和这里:。TL;DR:其中一个头必须首先包含,因为它包含了另一个头,所以另一个头不能包含第一个头以获得它所需的定义,因为第一个头已经包含。我从来没有想过只在文件顶部声明其中一个类,而不是在函数定义中将其声明为类。它看起来比我想到的要干净一点,因为它不需要每次使用时都定义它。谢谢!这对我有用。我还不知道远期申报:)在B.h.一开始使用a远期申报对我来说很有效。这和像你一样申报酒吧有什么区别?哪一个是最佳实践?我不认为我上面所做的和其他建议之间有什么有意义的区别。如果你想避免为其中的一个以上额外键入内容,他们的方式会更好。谢谢你详细解释为什么会发生这种情况。我现在更明白了:)@mrlux谢谢你给我机会用简短但有意义的标题写下这个答案。顺便提一下,这是一个很好的问题。