java什么声明时放前面_什么时候可以使用前向声明?

我正在寻找何时允许在另一个类的头文件中对一个类进行前向声明的定义:

我是否可以针对基类,作为成员持有的类,通过引用传递给成员函数的类等进行此操作?

#1楼

Lakos区分类用法

仅名称中 (对于此声明,前向声明已足够)和

in-size (需要为其定义类)。

我从未见过它的发音更简洁:)

#2楼

我将其作为一个单独的答案而不是仅仅作为评论,是因为我不同意Luc Touraille的回答,这不是基于合法性,而是基于强大的软件和错误解释的危险。

具体来说,我对您的界面用户希望了解的隐含合同有疑问。

如果您要返回或接受引用类型,那么您只是说它们可以通过指针或引用传递,而这些指针或引用又只能通过前向声明来知道。

当您返回不完整的类型时, X f2(); 那么您说您的呼叫者必须具有X的完整类型规范。他们需要它才能在呼叫站点创建LHS或临时对象。

同样,如果您接受不完整的类型,则调用者必须构造了作为参数的对象。 即使该对象作为另一个不完整类型从函数中返回,调用站点也需要完整的声明。 即:

class X; // forward for two legal declarations

X returnsX();

void XAcceptor(X);

XAcepptor( returnsX() ); // X declaration needs to be known here

我认为有一个重要的原则,即标头应提供足够的信息以使用它,而不必依赖其他标头。 这意味着在使用标头声明的任何函数时,标头应该能够包含在编译单元中,而不会引起编译器错误。

除了

如果外部的依赖是期望的行为。 与其使用条件编译,不如使用有据可查的要求,让它们提供自己的标头声明X。这是使用#ifdefs的替代方法,并且是引入模拟或其他变体的有用方法。

重要的区别是某些模板技术,其中明确不要求您实例化它们,只是提到了某人不会对我说鬼话。

#3楼

到目前为止,没有一个答案描述何时可以使用类模板的前向声明。 所以,就到这里。

可以将类模板转发声明为:

template struct X;

按照接受的答案的结构,

这是您可以做的和不能做的。

使用不完整的类型可以做什么:

声明一个成员是另一个类模板中不完整类型的指针或引用:template class Foo { X* ptr; X& ref; };

声明一个成员为其不完整实例之一的指针或引用:class Foo { X* ptr; X& ref; };

声明接受/返回不完整类型的函数模板或成员函数模板:template void f1(X); template X f2();

声明接受或返回其不完整实例之一的函数或成员函数:void f1(X); X f2();

定义接受/返回不完整类型的指针/引用的函数模板或成员函数模板(但不使用其成员):template void f3(X*, X&) {} template X& f4(X& in) { return in; } template X* f5(X* in) { return in; }

定义接受/返回对其不完整实例之一的指针/引用的函数或方法(但不使用其成员):void f3(X*, X&) {} X& f4(X& in) { return in; } X* f5(X* in) { return in; }

将其用作另一个模板类的基类template class Foo : X {} // OK as long as X is defined before // Foo is instantiated. Foo a1; // Compiler error. template struct X {}; Foo a2; // OK since X is now defined.

使用它来声明另一个类模板的成员:template class Foo { X m; // OK as long as X is defined before // Foo is instantiated. }; Foo a1; // Compiler error. template struct X {}; Foo a2; // OK since X is now defined.

使用此类型定义功能模板或方法template void f1(X x) {} // OK if X is defined before calling f1 template X f2(){return X(); } // OK if X is defined before calling f2 void test1() { f1(X()); // Compiler error f2(); // Compiler error } template struct X {}; void test2() { f1(X()); // OK since X is defined now f2(); // OK since X is defined now }

不完整类型不能做的事情:

将其实例化之一用作基类class Foo : X {} // compiler error!

使用其实例化之一来声明一个成员:class Foo { X m; // compiler error! };

使用其实例化之一定义函数或方法void f1(X x) {} // compiler error! X f2() {return X(); } // compiler error!

使用其实例化之一的方法或字段,实际上试图取消引用具有不完整类型的变量class Foo { X* m; void method() { m->someMethod(); // compiler error! int i = m->someField; // compiler error! } };

创建类模板的显式实例化template struct X;

#4楼

我只想添加一个重要的事情,您可以使用Luc Touraille的答案中未提到的转发类来做。

使用不完整的类型可以做什么:

定义接受/返回不完整类型的指针/引用并将该指针/引用转发给另一个函数的函数或方法。

void f6(X*) {}

void f7(X&) {}

void f8(X* x_ptr, X& x_ref) { f6(x_ptr); f7(x_ref); }

一个模块可以通过一个前向声明的类的对象传递给另一个模块。

#5楼

只要不需要定义(例如指针和引用),就可以避免使用前向声明。 这就是为什么大多数情况下您会在标头中看到它们的原因,而实现文件通常会提取相应定义的标头。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值