在C ++中,是否有可能将一个类声明为从另一个类inheritance的类?

我知道我可以这样做:

class Foo; 

但我可以转发声明一个类从另一个inheritance,如:

 class Bar {}; class Foo: public Bar; 

一个示例用例将是co-variant引用返回types。

 // somewhere.h class RA {} class RB : public RA {} 

…然后在另一个不包含some.h的头文件中

 // other.h class RA; class A { public: virtual RA* Foo(); // this only needs the forward deceleration } class RB : public RA; // invalid but... class B { public: virtual RB* Foo(); // } 

编译器处理声明RB* B:Foo()所需的唯一信息是RBRA作为公共基类。 现在显然你需要somewhere.h,如果你打算对Foo的返回值进行任何解引用。 但是,如果有些客户端永远不会调用Foo ,那么他们没有理由包含某个可能会显着加速编译的地方。

一个前向声明只有在告诉编译器这个名称的类确实存在并且将在其他地方被声明和定义时才是真正有用的。 在编译器需要关于类的上下文信息的情况下,你不能使用它,编译器也不能仅仅告诉它关于类的一些信息。 (一般来说,只有在引用那个没有其他上下文的类时,才能使用forward声明,例如作为参数或返回值。)

因此,在任何你使用它来声明Foo的情况下,你都不能转发declare Bar,并且它的平坦化没有任何意义,因为它有一个包含基类的前向声明 – 这个告诉你什么没有?

前向声明是声明,而不是定义。 因此,任何需要声明类的东西(比如指向这个类的指针)只需要前向声明。 然而,任何需要定义的东西(即需要知道类的实际结构)都不适用于前向声明。

派生类肯定需要知道父类的结构,而不仅仅是父类的存在,所以前向声明是不够的。

不,不可能转发声明inheritance,即使只处理指针也是如此。 处理指针之间的转换时,编译器有时需要知道类的详细信息才能正确执行转换。 这是多重inheritance的情况。 (您可以特殊情况下只使用单一inheritance的层次结构的某些部分,但这不是该语言的一部分。)

考虑下面这个微不足道的例子:

 #include <stdio.h> class A { int x; }; class B { int y; }; class C: public A, public B { int z; }; void main() { C c; A *pa = &c; B *pb = &c; C *pc = &c; printf("A: %p, B: %p, C: %p\n", pa, pb, pc); } 

我收到的输出(使用32位Visual Studio 2010)是:

 A: 0018F748, B: 0018F74C, C: 0018F748 

因此,对于多重inheritance,在相关指针之间进行转换时,编译器必须插入一些指针算术来获得正确的转换。

这就是为什么,即使你只处理指针,你也不能转发声明inheritance。

至于为什么它是有用的,当你想要使用co-variant返回types而不是使用强制转换时,它会提高编译时间。 例如,这将不会编译:

 class RA; class A { public: virtual RA *fooRet(); }; class RB; class B : public A { public: virtual RB *fooRet(); }; 

但是这将会:

 class RA; class A { public: virtual RA *fooRet(); }; class RA { int x; }; class RB : public RA{ int y; }; class B : public A { public: virtual RB *fooRet(); }; 

当你有typesB的对象(不是指针或引用)时,这很有用。 在这种情况下,编译器足够聪明,可以直接使用函数调用,并且可以直接使用RB *的返回types而不需要强制转换。 在这种情况下,通常我会继续并返回typesRA *,并对返回值进行静态转换。

我不认为这是有用的。 考虑一下:你已经定义了一个类,Bar:

 class Bar { public: void frob(); }; 

现在你声明一个Foo类:

 class Foo; 

你可以用Foo做的是构造一个指向它的指针。 现在,假设您添加了FooBar派生的信息:

 class Foo: public Bar; 

你现在可以做什么,你以前做不到? 我认为你所能做的就是接受一个指向Foo的指针,并将它转换成指向Bar的指针,然后使用该指针。

 void frob(Foo* f) { Bar *b = (Bar)f; b->frob(); } 

但是,您必须在别处生成指针,所以您可以接受指向Bar的指针。

 void frob(Bar* b) { b->frob(); }