为什么C ++没有反射?

时间:2008-12-11 12:52:02

标签: c++ reflection

这是一个有点离奇的问题。我的目标是理解语言设计决策并确定C ++中反射的可能性。

  1. 为什么C ++语言委员会不会在语言中实现反思?对于不在虚拟机上运行的语言(如java),反射是否太难了?

  2. 如果有人要为C ++实现反思,那么挑战会是什么?

  3. 我想反射的使用是众所周知的:编辑器可以更容易编写,程序代码更小,可以为单元测试生成模拟等等。但如果你也可以对反射的使用发表评论那就太好了。

14 个答案:

答案 0 :(得分:606)

答案 1 :(得分:38)

Reflection需要一些有关类型的元数据存储在可以查询的地方。由于C ++编译为本机机器代码并且由于优化而经历了大量更改,因此在编译过程中应用程序的高级视图几乎丢失,因此,无法在运行时查询它们。 Java和.NET在虚拟机的二进制代码中使用非常高级别的表示,使得这种反射水平成为可能。但是,在某些C ++实现中,有一种称为运行时类型信息(RTTI)的东西可以被认为是反射的精简版本。

答案 2 :(得分:15)

所有语言都不应该尝试合并其他语言的每个功能。

C ++本质上是一个非常非常复杂的宏汇编程序。它不是(传统意义上的)高级语言,如C#,Java,Objective-C,Smalltalk等。

为不同的工作提供不同的工具是很好的。如果我们只有锤子,那么所有的东西都会看起来像指甲等。有了脚本语言对某些工作很有用,反射的OO语言(Java,Obj-C,C#)对另一类工作很有用,而且超级 - 高效的裸机接近机器语言对于另一类作业(C ++,C,汇编程序)非常有用。

C ++在将Assembler技术扩展到令人难以置信的复杂度管理水平方面做得非常出色,并且抽象使得编程更大,更复杂的任务对人类来说更加可能。但对于那些从严格的高级角度(Lisp,Smalltalk,Java,C#)处理问题的人来说,它不一定是最适合的语言。如果您需要具有这些功能的语言来最好地实现问题的解决方案,那么感谢那些为我们所有人创建这些语言的人使用!

但C ++适用于那些无论出于何种原因需要在代码和底层机器操作之间建立强关联的人。无论是效率,编程设备驱动程序,还是与低级OS服务或其他任何内容的交互,C ++都更适合这些任务。

C#,Java,Objective-C都需​​要更大,更丰富的运行时系统来支持它们的执行。该运行时必须交付给相关系统 - 预先安装以支持软件的运行。并且必须为各种目标系统维护该层,由其他语言定制,以使其在该平台上运行。而那个中间层 - 主机操作系统和你的代码之间的自适应层 - 运行时,几乎总是用C或C ++这样的语言编写,效率是#1,可以预见地理解软件和硬件之间的确切交互可以很好理解,并操纵到最大的收益。

我喜欢Smalltalk,Objective-C,并且拥有带有反射,元数据,垃圾收集等的丰富运行时系统。可以编写出色的代码来利用这些功能!但这只是堆栈上的一个更高层,一层必须停留在较低层,它们本身必须最终位于操作系统和硬件上。我们总是需要一种最适合构建该层的语言:C ++ / C / Assembler。

附录:C ++ 11/14继续扩展C ++支持更高级别抽象和系统的能力。线程,同步,精确的内存模型,更精确的抽象机器定义使C ++开发人员能够实现许多高级抽象,其中一些高级语言曾经拥有独占域,同时继续提供接近 - 金属性能和出色的可预测性(即最小的运行时子系统)。对于那些想要它的人来说,也许在未来的C ++版本中有选择地启用反射工具 - 或者也许库会提供这样的运行时服务(现在可能有一个,或者在boost中有一个开头?)。

答案 3 :(得分:11)

如果您真的想了解围绕C ++的设计决策,请查找Ellis和Stroustrup的The Annotated C++ Reference Manual副本。它不是最新的标准,但它符合原始标准,并解释了事情的工作原理以及它们是如何实现的。

答案 4 :(得分:9)

对具有它的语言的反思是关于编译器愿意在目标代码中留下多少源代码以启用反射,以及有多少分析机制可用于解释反映的信息。除非编译器保留所有源代码,否则反射将限制其分析源代码的可用事实的能力。

C ++编译器不会保留任何东西(好吧,忽略RTTI),因此你不会在语言中得到。 (Java和C#编译器只保留类,方法名和返回类型,所以你得到一些反射数据,但你不能检查表达式或程序结构,这意味着即使在那些“反射启用”语言中你可以获得的信息非常稀少,因此你真的无法进行太多的分析。)

但是您可以在外部语言并获得完整的反射功能。关于reflection in C的另一个堆栈溢出讨论的答案讨论了这一点。

答案 5 :(得分:8)

Reflection can be and has been implemented in c++ before.

它不是原生的c ++功能,因为它的成本很高(内存和速度),默认情况下不应该由语言设置 - 语言是“默认的最大性能”。

因为你不应该为你不需要的东西买单,并且你自己说它在编辑器中比在其他应用程序中需要的更多,那么它应该只在你需要的地方实现,而不是“强制”到所有代码(您不需要在编辑器或其他类似应用程序中对所有数据进行反映。)

答案 6 :(得分:6)

C ++没有反射的原因是,这需要编译器将符号信息添加到目标文件中,例如类类型具有的成员,有关成员的信息,有关函数和所有内容的信息。这实际上会使包含文件无用,因为声明传送的信息将从那些目标文件(模块)中读取。在C ++中,类型定义可以在程序中多次出现,包括相应的头文件(前提是所有这些定义都相同),因此必须决定在何处放置有关该类型的信息,就像命名一个复杂在这里。由C ++编译器完成的积极优化可以优化数十个类模板实例化,这是另一个优点。这是可能的,但由于C ++与C兼容,这将成为一个尴尬的组合。

答案 7 :(得分:3)

在C ++中使用反射的情况很多,使用模板元编程等编译时结构无法充分解决。

N3340提出了丰富的指针,作为在C ++中引入反射的一种方式。除了你使用它之外,它解决了不支付功能的问题。

答案 8 :(得分:2)

如果C ++可以:

  • 变量名称,变量类型和const修饰符
  • 的类成员数据
  • 函数参数迭代器(仅位置而不是名称)
  • 函数名称,返回类型和const修饰符
  • 的类成员数据
  • 父类列表(与定义的顺序相同)
  • 模板成员和父类的数据;扩展模板(意味着实际类型可用于反射API,而不是'如何到达那里的'模板信息')

这足以在无类型数据处理的关键时刻创建非常易于使用的库,这在当今的Web和数据库应用程序中非常普遍 (所有的orms,消息机制,xml / json解析器,数据序列化等)。

例如,Q_PROPERTY宏支持的基本信息(Qt框架的一部分) http://qt.nokia.com/doc/4.5/properties.html扩展到覆盖类方法和e) - 对C ++和整个软件社区都非常有益。

当然,我所指的反思不会涵盖语义或更复杂的问题(如评论源代码行号,数据流分析等) - 但我认为这些都不需要成为语言标准的一部分

答案 9 :(得分:2)

根据Alistair Cockburn的说法,subtyping can't be guaranteed in a reflective environment

反射与潜在的打字系统更相关。在C ++中,你知道你有什么类型,你知道你可以用它做什么。

答案 10 :(得分:2)

反射可以是可选的,就像预处理器指令一样。像

这样的东西

#pragma enable reflection

这样我们可以充分利用这两个世界,没有反射就可以创建这个pragma库(没有讨论任何开销),那么单个开发人员是否想要速度或易用性将会成功。

答案 11 :(得分:1)

答案 12 :(得分:0)

这基本上是因为它是“可选的额外”。许多人选择C ++而不是像Java和C#这样的语言,这样他们就可以更好地控制编译器输出,例如:一个更小,更快的程序。

如果您选择添加反射,则various solutions available

答案 13 :(得分:0)

如果要将C ++用作数据库访问,Web会话处理/ http和GUI开发的语言,我认为C ++中的反思至关重要。缺乏反射会阻止ORM(如Hibernate或LINQ),XML和JSON解析器实现类,数据序列化和许多其他方面(最初无类型数据必须用于创建类的实例)。

可以使用在构建过程中可供软件开发人员使用的编译时开关 消除这种'你付出的代价'。

我的固件开发人员不需要反射来从串口读取数据 - 那就好了不要使用开关。但是作为一个想要继续使用C ++的数据库开发人员,我不断地使用一个可怕的,难以维护的代码,在数据成员和数据库结构之间映射数据。

Boost序列化和其他机制都没有真正解决反射问题 - 它必须由编译器完成 - 一旦完成,C ++将再次在学校中使用并用于处理数据处理的软件

对我来说,这个问题#1(和naitive线程原语是问题#2)。

免费获取贴纸的机会↓↓↓
豫ICP备18024241号-1