2012-08-16 185 views
0

代码如下所示:派生类错误:未定义类型

class B {/*something*/}; 

class D1: public B { 
public: 
void set() = 0; 
friend int D2::get(D1&); 
private: 
int a; 
} 
class D2: public B { 
public: 
int get(D1& d) {return d.a;} 
} 

我已经包含在这两个派生类的.h文件("D1.h" and "D2.h"),也有 “D2.h” 在D1,D2中"D1.h""B.h" .. 。但不断收到编译错误:

...\D2.h ... use of undefined type D1 

那么我在做什么错了?谢谢。

回答

2

您创建了一个圆形夹杂:你包括D1.hD2.h,你还包括D2.hD1.h。循环包容从未起作用,从未达到任何目的。

你的循环包含是类定义之间循环依赖的直接后果。在你的代码中,这两个类的定义都是相互引用的,要求这两个类的类型都是完整的(要完全定义)。这意味着无论你做什么,你的代码都是无法编译的。您需要打破类定义之间的循环依赖关系。

在你的情况下,可以通过以下方式来完成。

保持D1.h不变,即将D2.h保持为D1.h,并保持类D1的定义原样。

然而,包括D1.hD2.h而是引入D1预先声明为D2.h

class D1; 

变化D2的定义

class D2: public B { 
public: 
    int get(D1& d); 
}; 

注意:不要试图去定义方法get正确定义类D2。你必须搬迁D2::get定义一些其他的地方,那里的D1完整定义也是可见的(就像D2.cpp例如,其中应包括D1.hD2.h

int D2::get(D1& d) 
{ 
    return d.a; 
} 

就是这样。通过这种方式定义D2::get的副作用是它变为非内联。如果你真的想保持它内联,你必须把它定义为

inline int D2::get(D1& d) 
{ 
    return d.a; 
} 

,并确保它是某种只包括D1完整定义。例如,您可以将它放在第三个头文件(D2_aux.h或类似的东西)中,并记住在之后包括它D1.h

当然,尝试解决此问题的更好方法是重新考虑整个设计。你真的需要D1内的朋友声明吗?也许你应该以某种方式重新设计你的代码,以消除这个朋友声明的需要,从而消除这种依赖性。


或者,您也可以通过改变D1.h并保持D2.h不变解决。然而,跟着你将有一个更彻底的和宽松的

friend class D2; 

,以取代“细粒度” friend声明

friend int D2::get(D1&); 

D1.h去除D2.h列入该路径。

前朋友声明要求类D2是完整的,这实际上是创建“不可破坏”的依赖关系。后面的声明不需要D2是完整的。

+0

感谢man ...'get()'的定义其实是最初的问题(但是不知道,那么我在这两个类中都包含了.h文件)。从来没有想到这一点。 – scarably 2012-08-16 16:20:54

+0

不,实际上......我可以通过在D2内部创建'int get_d1(){return a}'和'int get(D1&x)'{{return x.get_d1();}'来重新设计代码。 。但我认为第一个版本更好? – scarably 2012-08-16 16:36:08

+0

stefaneli31:是的,这就是我所说的“重新思考设计”和“不需要朋友声明”。 – AnT 2012-08-16 16:42:36

0

如果D1的定义取决于D2和D2的定义取决于D1,那么你就需要转发参考类:

class B; 
class D1; 
class D2; 
0

在点是代码提到D2没有发生过任何事情说什么D2是(编译器不希望弄清楚)。所以你需要通过在D1的定义开始之前加上class D2;来告诉编译器什么是D2

+0

您不能“转发声明”类类型以便稍后在引用其成员的朋友声明中使用它们。在这种朋友声明中使用的类类型必须是* complete *。在D1类定义之前添加一个前向声明'class D2;'不会使D1中的朋友声明有效。出于这个原因,解决这种情况(不重新设计类关系)的唯一方法是在'D2'之前转发'D1',而不是相反。 – AnT 2012-08-16 16:31:19

+0

@安德烈 - 你说得对。我没有仔细看。有关声明是'D2 :: get(D1&)',编译器知道该成员的唯一方法是看完整个类。请注意,如果你想让整个班级成为朋友,你**不需要完整的定义。只需转发声明类即可,或者即时提及它('朋友类X'),尽管如果您不了解名称注入规则,后者可能会给您带来不可思议的错误。 – 2012-08-16 16:38:43