我在创建具有不同对象类型的某种形式的层次结构时遇到问题。我有一个类,其中包含另一个类的成员,如下所示:
class A
{
public:
A(){}
~A(){}
void addB(B* dep){
child = dep;
dep->addOwner(this);
}
void updateChild(){
child->printOwner();
}
void print(){
printf("Printing...");
}
private:
B* child;
};
这是B级:
class B
{
public:
void addOwner(A* owner){
ownerObject = owner;
}
//ISNT WORKING
void printOwner(){
ownerObject->print();
}
private:
A* ownerObject;
};
在类“A”之外调用“B”的函数工作正常但反之亦然会产生编译器错误,因为A未在B中定义。它实际上是通过使用包含和前向声明,但我猜测它是编译器无法解决的交叉引用问题。
有没有机会解决这个问题,还是应该重新考虑我的设计?
答案 0 :(得分:10)
你说你已经通过使用A
的前向声明解决了你的循环依赖问题,而不是包含定义A
的标题,所以你已经知道如何避免循环包含。但是,您应该知道what is possible and what is not with incomplete types(即已经声明的类型)。
在您的情况下,您尝试在具有不完整类型的对象上调用成员函数print
;编译器对此类型一无所知,除了它将在某个时刻定义,因此它不允许您这样做。解决方案是从printOwner
标头中删除B
成员函数的实现,并将其放入实现文件中:
//B.hpp
class A; // forward declaration
class B
{
public:
void addOwner(A* owner);
void printOwner() const; // I think this member function could be const
private:
A* ownerObject;
};
//B.cpp
#include "B.hpp"
#include "A.hpp" // here we "import" the definition of A
void B::addOwner(A * owner)
{
ownerObject = owner;
}
void B::printOwner() const
{
ownerObject->print(); //A is complete now, so we can use its member functions
}
您可以在A
标题中执行相同的操作。
答案 1 :(得分:2)
你可能应该重新考虑你的设计,因为一个愚蠢的亲子关系通常是一种代码气味。
但是,你可以让编译器开心:
#include <cstdlib>
#include <cstdio>
class A
{
public:
A(){}
~A(){}
void addB(class B* dep);
void updateChild();
void print(){
printf("Printing...");
}
private:
class B* child;
};
class B
{
public:
void addOwner(A* owner){
ownerObject = owner;
}
//ISNT WORKING
void printOwner(){
ownerObject->print();
}
private:
A* ownerObject;
};
void A::addB(class B* dep){
child = dep;
dep->addOwner(this);
}
void A::updateChild(){
child->printOwner();
}
int main()
{
return 0;
}
答案 2 :(得分:2)
您可以使用前向声明,定义类之外的成员函数,即
// A.h
class B;
class A { public:
void addB(B* dep); // don't define addB here.
...
};
// B.h
class A;
class B { public:
void addOwner(A* owner); // don't define addOwner here.
...
};
// A.cpp
#include "A.h"
#include "B.h"
void A::addB(B* dep) {
...
}
// B.cpp
// similar.
答案 3 :(得分:0)
您应该将B :: printOwner实现移动到.cpp文件。