【问题标题】:How can I implement metaclasses in C++?如何在 C++ 中实现元类?
【发布时间】:2010-10-19 06:01:25
【问题描述】:

我已经阅读了一些关于元类是什么的文章,但我想知道它们是否可以在 C++ 中实现。

我知道 Qt 库正在使用 MetaObjects,但它使用 C++ 的扩展来实现它。我想知道是否可以直接在 C++ 中使用。

谢谢。

【问题讨论】:

    标签: c++ metaclass


    【解决方案1】:

    C++ 没有对元类的内置支持(不是以 Python/Objective-C 方式),但是您可以手动模仿元类的行为。基础非常简单,您可以创建一个生命周期更长的额外类(单例、静态对象或Construct On First Use Idiom),它能够创建和操作它的相应类。 (在 Objective-C 中,元类通常包含“静态”成员变量、内存分配/释放例程等)。

    Qt 所做的是,他们采用了元类的概念并对其进行了修改,以便它们可以支持某种形式的反射(以及不支持它的系统上的 RTTI)。实现这一点需要大量的宏魔法或自定义编译器(例如他们选择使用的)。

    一般来说,常规元类提供的大部分功能已经由 C++ 语言提供;只是形式不同。实际上,您需要元对象的唯一原因是用于反射目的,如this document 中所述,在 C++ 中实现反射有多种不同的方法。

    除此之外,如果您真的设置在 Objective-C 风格的元类系统上,我不知道有任何库可以做到这一点,但很可能有。另一方面,自己滚动也不应该那么困难。

    【讨论】:

      【解决方案2】:

      Gamma 等人的“设计模式”一书中的一些模式与元类概念具有相似的特征。例如,“策略”模式允许您在创建时自定义对象行为。信封成语是另一个紧密的匹配。不过,也不允许您自定义类的接口。

      在 COM 中,IDispatch 接口允许在运行时向对象动态添加方法/属性。不过,这意味着放弃标准的 c++ 方法调用。每个调用都通过相同的方法,该方法将索引或字符串键放入用户维护的方法/属性表中,并且所有参数都必须作为对象数组传递。

      使用这两种技术,您可以获得元类的灵活性,但由于没有语法优势或运行时/编译器帮助,这要困难得多。

      戴夫

      【讨论】:

        【解决方案3】:

        如果元类的工作定义是“一个实例化本身就是类的语言实体”,那么 generics 就是 C++ 中的元类:

        #include <iostream>
        using namespace std;
        
        template <typename T>
        class Meta {
        public:
            Meta(const T&init) : mData(init) {}
        // ...
        private:
            T mData;
        
        };
        
        int main(int, char **) {
          cout << "The size of Meta<double> is " << sizeof(Meta<double>) << endl ;
          return 0;
        }
        

        在倒数第二行中使用 Meta 迫使编译器实例化 Meta 类; sizeof 运算符对 Meta 进行操作,从而证明这不仅仅是语义糖,而且该类已被实例化。即使没有实例化 Meta 类型的对象,程序也是完整的。

        【讨论】:

          【解决方案4】:

          可以创建元类,但 C++ 不是这样,它是基于静态编译时的实现,而不是运行时灵活性。

          无论如何,这取决于您是想要带有方法的元类还是只带有数据的元类,数据类可以使用 boost::any 之类的 Boost 构造来实现,如果您想要带有方法的类,您可以使用 boost: :bind 将方法绑定到对象,或者您可以使用单入口点接口(如 COM 对象)自行实现它们。

          然而,“真正的”C++ 方式是使用泛型,因此它可以在编译时确定,以获得最佳性能。

          说实话,我见过的系统很少,尽管我见过一些真正需要运行时灵活性的系统,在大多数情况下,对象在同一个类中诞生和消亡,或者至少足以度过其 95% 的生命周期一旦他们从他们的工厂出来,作为一个单一的班级。

          因此,在许多情况下,人们会发现自己为运行时元类付出了太多。当然,有一种观点认为这可以提供更好的开发人员性能,但在许多情况下,每行代码在硬件上运行的时间是编写它所花费的时间的几亿倍。因此,您可以将编译时和运行时类视为预付费用或永久租用。我个人喜欢预先付款。

          【讨论】:

            【解决方案5】:

            怕不是……至少不是天生的。

            拥有一个元类通常需要一个代表类的运行时对象,就像 Java 中的情况一样。

            在 C++ 中,类没有运行时表示。它们的表现形式出现在虚拟桌子之类的东西中。但在许多方面,它们像 C 函数一样运行,所有 OOP 几乎就像胶水代码一样运行。

            话虽如此,您可能希望使用其他语言的元类来实现许多面向对象的 OOP 模式。您还可以“模拟”您自己的对象系统。

            【讨论】:

              【解决方案6】:

              您可能想看看这篇博文。

              https://herbsutter.com/2017/07/26/metaclasses-thoughts-on-generative-c/

              元类可能会进入 C++,但还需要一段时间。

              【讨论】:

                猜你喜欢
                • 2011-10-18
                • 2012-02-20
                • 2013-08-20
                • 2012-03-05
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-01-20
                相关资源
                最近更新 更多