ano*_*non 63 c++ inheritance forward-declaration
我知道我能做到:
class Foo;
Run Code Online (Sandbox Code Playgroud)
但是我可以将一个类声明为继承自另一个类,例如:
class Bar {};
class Foo: public Bar;
Run Code Online (Sandbox Code Playgroud)
示例用例是共变量引用返回类型.
// somewhere.h
class RA {}
class RB : public RA {}
Run Code Online (Sandbox Code Playgroud)
...然后在另一个不包含somewhere.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(); //
}
Run Code Online (Sandbox Code Playgroud)
唯一的信息编译器应该需要处理的声明,RB* B:Foo()
即RB
具有RA
作为公共基类.现在显然你需要somewhere.h如果你打算从中做任何类型的反引用返回值Foo
.但是,如果某些客户端从不调用Foo
,那么它们没有理由包含somewhere.h,这可能会显着加快编译速度.
Joe*_*Joe 42
前向声明仅对告诉编译器具有该名称的类确实存在并将在其他地方声明和定义非常有用.在编译器需要有关类的上下文信息的任何情况下都不能使用它,编译器也没有任何用处来告诉它只有一点关于类.(通常,在没有其他上下文的情况下引用该类时,您只能使用前向声明,例如作为参数或返回值.)
因此,你不能转发任何情况下宣布吧,你再使用它来帮助申报富,而且平了没有意义有一个向前声明包含基类 - 这是什么告诉你,除了没有?
Jon*_*vis 40
前向声明是声明,而不是定义.所以,任何需要声明类的东西(比如指向该类的指针)只需要前向声明.但是,任何需要定义的东西 - 即需要知道类的实际结构 - 都不适用于前向声明.
派生类肯定需要知道父类的结构,而不仅仅是父元素的存在,因此前向声明是不够的.
小智 19
不,即使您只处理指针,也无法转发声明继承.处理指针之间的转换时,编译器有时必须知道类的详细信息才能正确进行转换.这是多重继承的情况.(特殊情况下,层次结构的某些部分仅使用单一继承,但这不是语言的一部分.)
考虑以下微不足道的案例:
#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);
}
Run Code Online (Sandbox Code Playgroud)
我收到的输出(使用32位visual studio 2010)是:
A: 0018F748, B: 0018F74C, C: 0018F748
Run Code Online (Sandbox Code Playgroud)
因此,对于多重继承,在相关指针之间进行转换时,编译器必须插入一些指针算法才能使转换正确.
这就是为什么即使你只处理指针,也不能转发声明继承.
至于为什么它会有用,当你想要使用共变量返回类型而不是使用强制转换时,它会改善编译时间.例如,这将无法编译:
class RA;
class A { public: virtual RA *fooRet(); };
class RB;
class B : public A { public: virtual RB *fooRet(); };
Run Code Online (Sandbox Code Playgroud)
但这会:
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(); };
Run Code Online (Sandbox Code Playgroud)
当你有B类对象(不是指针或引用)时,这很有用.在这种情况下,编译器足够智能以使用直接函数调用,并且您可以直接使用RB*的返回类型而无需强制转换.在这种情况下,通常我继续进行返回类型RA*并对返回值进行静态转换.