您需要做的就是声明RB
没有: public RA
(哦,还要添加;
到类定义的末尾):
class RA;
class A {
public:
virtual RA* Foo();
};
class RB;
class B {
public:
virtual RB* Foo();
};
// client includes somewhere.h
class RA {};
class RB : public RA {};
int main ()
{
return 0;
}
但是,这并不能解决 user1332054 的回答中很好地描述的具体问题。
其他一些答案似乎表明了我想消除的一些误解:
即使我们知道不太可能包含定义,前向声明也很有用。这允许我们在我们的库中进行大量类型推断,使它们与许多其他已建立的库兼容,而不包括它们。包含不必要的库会导致过多的嵌套包含,这可能会增加编译时间。在适当的时候使您的代码兼容并尽可能少地包含是一种很好的做法。
通常,您可以使用指向仅已声明且未定义的类的指针来定义类。例子:
struct B;
struct A
{
B * b_;
B * foo ()
{
return b_;
}
B & foo (B * b)
{
return *b;
}
};
int main ()
{
return 0;
}
上面的编译很好,因为编译器不需要知道关于 B 的任何信息。
一个例子,它可能有点难以意识到编译器需要更多信息:
struct B;
struct A
{
B * foo ()
{
return new B;
}
};
上述问题是因为new B
调用了B::B()
尚未定义的构造函数。还:
struct B;
struct A
{
void foo (B b) {}
};
这里foo
必须调用 for 的复制构造函数b
,它还没有被定义。最后:
struct B;
struct A
{
B b;
};
这里我们隐式定义A
了默认构造函数,它调用了调用其成员的默认构造函数,b
尚未定义。我认为你说对了。
因此,关于 user1332054 描述的更普遍的问题,老实说,我不明白为什么不能在继承的虚函数中使用指向未定义类的指针。
不过,更广泛地说,我认为您通过定义类而不是仅声明它们来使自己变得更加困难。这是一个示例,在您完全DoCleverStuff
定义任何类之前,您可以在库中使用您的类:
// Just declare
class RA;
class RB;
class A;
class B;
// We'll need some type_traits, so we'll define them:
template <class T>
struct is_type_A
{
static constexpr bool value = false;
};
template <>
struct is_type_A <A>
{
static constexpr bool value = true;
};
template <class T>
struct is_type_B
{
static constexpr bool value = false;
};
template <>
struct is_type_B <B>
{
static constexpr bool value = true;
};
#include <type_traits>
// With forward declarations, templates and type_traits now we don't
// need the class definitions to prepare useful code:
template<class T>
typename std::enable_if<is_type_A<T>::value, RA *>::type
DoCleverStuff (T & t)
{
// specific to A
return t.fooRet();
}
template<class T>
typename std::enable_if<is_type_B<T>::value, RB *>::type
DoCleverStuff (T & t)
{
// specific to B
return t.fooRet();
}
// At some point the user *does* the include:
class RA
{
int x;
};
class RB : public RA
{
int y;
};
class A
{
public:
virtual RA * fooRet()
{
return new RA;
}
};
class B : public A
{
public:
virtual RB * fooRet()
{
return new RB;
}
};
int main ()
{
// example calls:
A a;
RA * ra = DoCleverStuff(a);
B b;
RB * rb = DoCleverStuff(b);
delete ra;
delete rb;
return 0;
}