C ++:将this指针传递给另一个类

时间:2016-03-31 23:20:24

标签: c++ pointers parameter-passing this member

我是C ++的新手,但我确实有一些Java经验。 编码时,我偶然发现了一个让我感到困惑的错误。 这是我的代码(简化,但错误是相同的):

A.H:

#pragma once
#include "B.h"
class A
{
public:
    A();
    void foo();
    void sayHello();
    B b;
 };

A.cpp:

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

B.h:

#pragma once
#include "A.h"
class B
{
public:
    B();
    void bar(A *a);
};

B.cpp:

#include "B.h"
B::B(){}
void B::bar(A *a) {
    a->sayHello();
}

我想将 a 对象的指针传递给 B 中的 bar 函数,以便我能够修改和访问 的字段。奇怪的是,当我通过另一个类的 A 实例调用 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 ==========

如果我不在 Bh 中包含 Ah 并且我没有将任何内容传递给功能。

我试图谷歌可能会导致这些错误,但我自己无法解决问题,因为我不明白导致这些错误的原因。我做错了什么?

4 个答案:

答案 0 :(得分:2)

A.h 的标题文件中,您有:

#include "B.h"

B.h 的标题文件中,您有:

#include "A.h"

您有一个循环包含,其中AB的定义相互依赖。

一个简单的解决方案是在class B

的定义中使用forward declaration
  1. 将文件 B.h 中的行#include "A.h"替换为class B;
  2. B.cpp
  3. 的开头添加#include "A.h"

    请注意,您不能使用class A的远期声明,原因是您b的值class 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
     };
    

    编译器需要知道class B的定义才能确定A类的正确大小。这就是为什么你必须把#include "B.h"放在 Ah的开头< / strong>即可。

答案 1 :(得分:2)

让我们看看B.cpp并观察包含的内容:

#include "B.h"

B::B(){}
void B::bar(A *a) {
    a->sayHello();
}

用B.h粘贴代替我们获得的包含:

#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。 KABOOM。如果没有A,则无法定义B,而B尚未定义。

A的大小必须B才能满足B b;,因此需要B的完整定义。 B只需知道A存在,因为它只需要指向A的指针即可满足void bar(A *a);。所以......

<强> A.H

#pragma once
#include "B.h"
class A
{
public:
    A();
    void foo();
    void sayHello();
    B b;
};

<强> A.cpp

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

<强> B.h

#pragma once

class A; // forward definition of class A
class B
{
public:
    B();
    void bar(A *a);
};

<强> B.cpp

#include "A.h"
B::B(){}
void B::bar(A *a) {
    a->sayHello();
}

答案 2 :(得分:1)

两个标头都互相引用。实际上,编译器只能实际评估一个,并且无法解析另一个头中对该类的引用。这个错误并不明显,但是&#34;一次&#34; #pragma正在使其中一个标题包含不按预期发生。

如果B.h头文件不需要知道关于A类的实现细节,在这种情况下它不是,那么不要在B.h中包含A.h文件。相反,将bar()的函数声明更改为:

bar( class A *a );

编译器可以从中构建代码,该代码将指针传递给A对象,而不知道A内部的内容。它不需要A.h头。

然后在B.cpp。

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

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

答案 3 :(得分:0)

进行以下更改:

B.h : - 转发声明A

#pragma once
// #include "A.h"
class A;
//^^^^^^

class B {
public:
    B();
    void bar(A *a);
};

B.cpp #include "A.h"

//#include "B.h"
#include "A.h"
//^^^^^^^^^^^^

B::B(){}
void B::bar(A *a) {
    a->sayHello();
}

就是这样。