C++;:将此指针传递给另一个类 我是C++新手,但我在java方面有一些经验。 在编写代码时,我偶然发现了一个让我困惑的错误。 以下是我的代码(简化,但错误相同):
A.h: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
#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谢谢你给我机会用简短但有意义的标题写下这个答案。顺便提一下,这是一个很好的问题。