究竟有什么区别?似乎这些术语可以在某种程度上互换使用,但是阅读 Objective-c 的维基百科条目时,我遇到了:
除了 C 的过程式编程风格之外,C++ 还直接支持某些形式的面向对象编程、泛型编程和元编程。
参考 C++。那么显然他们是不同的?
究竟有什么区别?似乎这些术语可以在某种程度上互换使用,但是阅读 Objective-c 的维基百科条目时,我遇到了:
除了 C 的过程式编程风格之外,C++ 还直接支持某些形式的面向对象编程、泛型编程和元编程。
参考 C++。那么显然他们是不同的?
正如其他几个答案中已经提到的那样,C++ 中的区别可能会令人困惑,因为通用编程和(静态/编译时)元编程都是使用模板完成的。更让你困惑的是,C++ 中的通用编程实际上使用元编程来提高效率,即模板专业化从通用程序生成专门的(快速)程序。
还要注意,正如每个 Lisp 程序员都知道的那样,代码和数据是同一个东西,所以真的没有“元编程”这样的东西,它只是编程。同样,这在 C++ 中有点难以看到,因为您实际上使用两种完全不同的编程语言进行编程(C++,一种 C 系列中的命令式、过程式、面向对象的语言)和元编程(模板,一种纯函数式的“意外” " 介于纯 lambda 演算和 Haskell 之间的语言,语法丑陋,因为它实际上从未打算成为一种编程语言。)
许多其他语言在编程和元编程中都使用相同的语言(例如 Lisp、Template Haskell、Converge、Smalltalk、Newspeak、Ruby、Ioke、Seph)。
从广义上讲,元编程意味着编写产生其他程序的程序。例如,C++ 中的模板仅在实例化时才产生实际代码。可以将模板解释为将类型作为输入并生成实际函数/类作为输出的程序。预处理器是另一种元编程。元编程的另一个虚构示例:读取 XML 并根据 XML 生成一些 SQL 脚本的程序。同样,一般来说,元程序是产生另一个程序的程序,而通用编程是关于参数化(通常与其他类型)类型(包括函数)的。
在考虑对此答案的评论后进行编辑
我粗略地将元编程定义为“编写程序来编写程序”,而泛型编程定义为“使用语言特性来编写函数、类等。根据参数或成员的数据类型进行参数化”。
根据这个标准,C++ 模板对于通用编程(想想vector
、list
... sort
)和元编程(想想 Boost 和例如 Spirit)都是有用的。此外,我认为 C++ 中的通用编程(即编译时多态性)是通过元编程(即从模板代码生成代码)完成的。
泛型编程通常是指可以处理多种类型的函数。例如,一个排序函数,它可以对一组可比对象进行排序,而不是一个排序函数来排序一个整数数组,另一个排序函数来排序一个字符串向量。
元编程是指以编程方式检查、修改或创建类、模块或函数。
最好看看其他语言,因为在 C++ 中,一个特性同时支持通用编程和元编程。(模板非常强大)。
在 Scheme / Lisp 中,您可以更改代码的语法。人们可能知道 Scheme 是“带有很多括号的前缀语言”,但它也有非常强大的元编程技术(Hygenic Macros)。特别是可以创建try/catch ,甚至可以将语法操作到一个点(例如不想再写前缀代码,这里是一个前缀到中缀转换器:http: //github.com /marcomaggi/nausicaa)。这是通过元编程实现的,即编写代码的代码编写代码。这对于尝试新的编程范式很有用(AMB 算子在非确定性编程中扮演着重要角色。我希望 AMB 在未来 5 年左右成为主流......)
在 Java / C# 中,您可以通过泛型进行泛型编程。您可以编写一个支持许多其他类的类型的泛型类。例如,在 Java 中,您可以使用 Vector 创建整数向量。或者 Vector 如果您希望它特定于您自己的类。
奇怪的是,C++ 模板是为通用编程而设计的。然而,由于一些技巧,C++ 模板本身是图灵完备的。使用这些技巧,可以通过元编程向 C++ 语言添加新功能。它令人费解,但它有效。这是一个通过模板向 C++ 添加多个调度的示例。http://www.eptacom.net/pubblicazioni/pub_eng/mdisp.html。比较典型的例子是编译时的斐波那契:http ://blog.emptycrate.com/node/271
通用编程是一种非常简单的元编码形式,尽管通常不是运行时的。它更像是 C 语言中的预处理器,并且在大多数用例和基本实现中与模板编程有关。
你会经常发现在类型化语言中,你会创建一些只有类型不同的东西的实现。在诸如 Java 之类的语言中,这可能特别痛苦,因为每个类和接口都定义了一个新类型。
您可以通过将它们转换为字符串文字然后将类名替换为要插入的变量来生成这些类。
在运行时使用泛型的地方有点不同,在那种情况下,它只是变量编程,使用变量进行编程。
设想的方法很简单,获取文件,比较它们并将任何不同的东西变成变量。现在您只有一个可重复使用的文件。您只需要指定不同之处,因此 name 变量。
泛型是如何产生的,并非所有东西都可以像您期望的变量类型或强制转换类型那样变成可变的。通常会有很多文件重复,其中唯一可变的就是变量类型。这是一个非常常见的重复来源。尽管有一些方法可以绕过它或减轻它,但它们并不是特别方便。泛型作为一种变量变量出现,允许使变量类型成为变量。因为变量类型通常在编程语言中表达,现在可以在运行时指定,它也被认为是元编码,尽管这是一个非常简单的情况。
在您需要的地方没有可变性的效果是展开您的变量,也就是说,您被迫而不是拥有一个变量来为每个可能的实现实现将是变量值。
正如你可以想象的那样,这是相当昂贵的。这在使用任何类型的重用对象存储库时都很常见。这些将接受任何对象,但在大多数情况下,人们只想处理一种类型的 objdct。如果您放入一个扩展 Object 的 Shop 对象,然后想要检索它,则存储对象上的方法签名将仅返回 Object,但您的代码将需要一个 Shop 对象。除非您将其重新投入商店,否则这将破坏对象降级的编译。这引发了另一个难题,因为没有泛型就无法检查兼容性并确保您存储的对象是 Shop 类。
Java 避免元编程,并尝试使用 OOP 的多态性原则来保持语言简单,而不是制作灵活的代码。然而,通过经验已经出现了一些紧迫和反复出现的问题,并且通过添加最小的元编程设施来解决。Java 不想成为一种元编程语言,但会谨慎地从那里导入概念来解决最棘手的问题。
除了特殊情况、反射、OOP 多态性等之外,提供 lavage 元编码工具的编程语言比避免使用元编码工具的编程语言效率更高。然而,生成不可理解、可维护和无错误的代码通常还需要更多的技能和专业知识. 由于 C++ 被编译为本机,因此 C++ 的这种语言通常也会有性能损失。