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

Posted

技术标签:

【中文标题】C ++:将this指针传递给另一个类【英文标题】:C++: passing the this pointer to another class 【发布时间】:2016-07-20 14:52:00 【问题描述】:

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

啊:

#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函数,这样我就可以修改了并访问 abar 中的字段。奇怪的是,当我通过另一个类的 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 并且我没有将任何内容传递给 bar 函数,则代码可以正常工作。

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

【问题讨论】:

寻找cyclic includesforward declaration 循环引用。更多在这里:***.com/questions/625799/… 和这里:***.com/questions/17865286/c-circular-include 和这里:en.wikipedia.org/wiki/Circular_dependency。 TL;DR:必须首先包含一个标头,因为它包含另一个标头,所以另一个标头不能包含第一个以获得它需要的定义,因为第一个标头已经包含在内。 【参考方案1】:

A.h的头文件中,你有:

#include "B.h"

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

#include "A.h"

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


一个简单的解决方案是在class B的定义中使用forward declaration:

    将文件 B.h 中的行 #include "A.h" 替换为 class B;B.cpp开头添加#include "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
 ;

编译器需要知道class B 的定义才能确定A 类的正确大小。这就是为什么您必须将#include "B.h" 放在A.h 开头的原因。

【讨论】:

我从没想过只在文件顶部声明这样的类之一,而不是在函数定义中将其声明为类。它看起来比我想出的要干净一些,因为它不需要每次使用时都定义。 谢谢!这对我有用。我还不知道前向声明:)【参考方案2】:

两个标题相互引用。只有一个实际上可以由编译器首先评估,并且一个无法解析对另一个头中的类的引用。错误并不明显,但“once”#pragma 正在使标题包含之一没有按您预期的那样发生。

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

bar( class A *a );

编译器可以由此构建代码,将指针传递给 A 对象,而无需了解 A 内部的任何内容。它不需要 A.h 标头。

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

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

【讨论】:

在 B.h. 开头使用 A 的前向声明对我有用。那和像你一样声明 bar 有什么区别?哪个是最佳做法? 我认为我上面所做的与其他建议之间没有有意义的区别。如果您想避免对其中一个以上的额外输入,他们的方法会更好。【参考方案3】:

让我们看一下 B.cpp 并观察 include 会发生什么:

#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:

#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还没有定义。卡布姆。没有B 就无法定义A 并且尚未定义B

A必须有B的大小才能满足B b;,所以它需要B的完整定义。 B 只需要知道A 的存在,因为它只需要一个指向A 的指针就可以满足void bar(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();

【讨论】:

感谢您详细解释为什么会发生这种情况。我现在理解得更好了:) @mrlux 感谢您给我机会用简短但有意义的标题来写这个答案。顺便说一句,问题的结构很好。【参考方案4】:

做这些改变:

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();

就是这样。

【讨论】:

以上是关于C ++:将this指针传递给另一个类的主要内容,如果未能解决你的问题,请参考以下文章

c ++:将指针传递给基类时访问派生类方法?

如何将“this”指针传递给 C++ WinAPI 线程?

将 C++/CLI 类方法作为 C 函数指针传递

C 传递和指针

C ++将指向子函数的指针传递回父类

一个c++虚函数与this指针的问题