你只需要声明
RB
而不带
: public RA
(哦,还需要在类定义的末尾添加
;
)即可:
class RA;
class A {
public:
virtual RA* Foo();
};
class RB;
class B {
public:
virtual RB* Foo();
};
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
必须调用b
的拷贝构造函数,但是该函数还没有被定义。最后:
struct B;
struct A
{
B b;
};
在这里,我们使用默认构造函数隐式定义了
A
,该构造函数调用其成员
b
的默认构造函数,但后者尚未被定义。我认为你明白了。
因此,就用户1332054所描述的更一般的问题而言,我实在不明白为什么不能在继承的虚函数中使用指向未定义类的指针。
然而更广泛地说,我认为通过定义而非只声明类来使其更加困难。以下是一个示例,在其中您可以在定义任何类之前就使用库中的类来执行DoCleverStuff
:
class RA;
class RB;
class A;
class B;
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>
template<class T>
typename std::enable_if<is_type_A<T>::value, RA *>::type
DoCleverStuff (T & t)
{
return t.fooRet();
}
template<class T>
typename std::enable_if<is_type_B<T>::value, RB *>::type
DoCleverStuff (T & t)
{
return t.fooRet();
}
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 ()
{
A a;
RA * ra = DoCleverStuff(a);
B b;
RB * rb = DoCleverStuff(b);
delete ra;
delete rb;
return 0;
}