【问题标题】:How can I iterate through unknown object methods in C++?如何遍历 C++ 中的未知对象方法?
【发布时间】:2020-06-25 07:51:17
【问题描述】:

假设我有课

类基类 {
  上市:
    基类();
    ~BaseClass();
    
    无效 runAllMethods();
};

和子类

类子类:公共基类{
  上市:
    子类();
    〜子类();

    // 任意方法
    无效方法1();
    无效方法2();
    ...
};

假设我然后创建对象

子类 myObject = SubClass();

如何在BaseClass中写入runAllMethods(),使其可以运行自己的所有方法,包括SubClass中定义的方法(例如methods1()、method2()等)?换句话说,如何让超类在不知道子类方法名称的情况下访问子类中的方法?

【问题讨论】:

  • 你不能。 C++ 尚不具备其他语言所使用的反射功能。要么覆盖子类中的runAllMethods,要么以另一种方式收集“所有方法”(例如,函数指针的std::vector)。
  • 在您的问题中显示一些minimal reproducible example。你的程序在做什么?您已经拥有几百万行 C++ 代码?在什么操作系统和编译器上? 请edit您的问题进行改进
  • Meta:你为什么要运行你一无所知的方法(参数、返回值、功能)?尤其是所有的方法?

标签: c++ methods


【解决方案1】:

如何在 C++ 中遍历未知对象方法?

据我所知,这是不可能的。通过阅读n3337(C++11 标准)进行检查。

一种可能的方法是生成运行所有这些的 C++ 代码。

您可以使用一些元编程方法(例如Qt 使用它的moc,它会生成C++ 代码),或者您可以使用由build automation 工具驱动的一些预处理器(例如GPP)。 GNU autoconf 可能会鼓舞人心。

如果您使用 GCC 编译 C++ 代码,请考虑使用 plugins 对其进行扩展。

您可以考虑一些X-macro 技巧。

如果您的operating system 有plugins,您可以在运行时生成它们然后加载它们。在 Linux 上,请参阅 dlopen(3) 和 dlsym(3) 和 C++ dlopen mini howto 和 How to write shared libraries。

在某些操作系统上,您可以使用 JIT compilation 技术在运行时生成机器代码,例如 GCC libgccjit 可以帮助您。或者使用asmjit

注意 C++11 中的 lambda expressions。也许它们可能有用(除了其他方法)。

考虑使用其他编程语言(例如 Common Lisp;它是 homoiconic,但 C++ 不是)并使用巧妙的实现(例如 SBCL)。

考虑在你的 C++ 程序中嵌入一些解​​释器,可能是Lua 或Guile 或Python。然后,解释的脚本是您程序的一些输入,并且可以运行您与之交互的任何代码。阅读Dragon Book。

【讨论】:

    【解决方案2】:

    几乎可以使用virtual keyword。看这个例子:

    #include <iostream>
    
    using std::cout;
    using std::endl;
    
    class BaseClass {
      public:
        BaseClass() {}
        virtual ~BaseClass() {}
    
        void method1() { cout << "in superclass" << endl; }
    
        virtual void runAllMethods()
        {
            method1();
        }
    };
    
    class SubClass : public BaseClass {
      public:
        SubClass() {}
        virtual ~SubClass() {}
    
        void method2() { cout << "in subclass" << endl; }
        
        virtual void runAllMethods()
        {
            BaseClass::runAllMethods();
            method2();
        }
    };
    
    int main()
    {
        BaseClass* obj = new SubClass;
        obj->runAllMethods();
        delete obj;
    }
    

    输出:

    in superclass
    in subclass
    

    这会从子类调用runAllMethods方法,然后再调用子类方法和超类runAllMethods。
    如果您需要稍微不同的架构,最好说明以后使用它的代码应该是什么样子。

    实际操作中:http://cpp.sh/2mvvy

    编辑:如果您想在这里增加一些安全性,请在子类中使用override:

    virtual void runAllMethods() override
    

    如果方法实际上没有覆盖,这会警告你(比如如果你有一个参数并且你在超类而不是在子类中更改它的类型,导致方法具有不同的签名,因此不会覆盖.)

    【讨论】:

    • virtual 在您重写时派生类中的方法是多余的。如果不覆盖,添加 override 会使其成为 错误。
    • @TedLyngmo 你认为这是不好的风格吗?如果你这样做,我不介意编辑。我的想法是仍然表明runAllMethods 将由儿童实现,因为在问题中听起来可能存在比两个类更长的链。有人派生SubClass。出于这个原因,如果我创建了final 类,我只会删除virtual。但我想听听其他人对此有何看法,并且再次欢迎您随时编辑。
    • 我个人更喜欢忽略它而只使用override,但我不确定我是否会称之为糟糕的风格。也许有点:-) 不管继承有多深,它都会是virtual,即使你把它排除在外:demo
    • 这如何回答 OP 的问题?
    • @BasileStarynkevitch 看到其他答案和 cmets,我认为他们过度解释了 OP 想要什么。他们正在寻求复杂的反射方式等,而OP很容易只是想要某种结构,在其中执行一系列处理方法。我的代码可以做到这一点。不过,我可能对他想要的东西有误。让我们等待他的答复。无论如何,我的回答确实回答了这个问题,因为超类中的方法访问子类中的方法。以最简单的方式。无论如何,以后都可以删除我的答案。
    猜你喜欢
    • 1970-01-01
    • 2015-06-13
    • 2014-07-06
    • 1970-01-01
    • 2012-09-12
    • 1970-01-01
    • 2023-03-04
    • 2012-04-15
    • 1970-01-01
    相关资源
    最近更新 更多