【问题标题】:C++ At runtime check whether function signature exists?C++ 在运行时检查函数签名是否存在?
【发布时间】:2013-12-27 09:14:18
【问题描述】:

目前的情况是这样的:我正在经历一些代码重构

如果你看图像,目前的情况是我有一个虚拟方法setData(int ID); 现在我们想把它改成虚拟方法setData(dataObj aObj);

但是这样做是一个漫长的过程,因为我们的foo 对象已被大量类继承。所以,我们要逐步进行代码修改。

因此,我需要做的是检查其中一个继承的类是否已实现 setData(dataObj aObj) 调用该类,否则调用另一个先前的函数签名 setData(int ID); 问题更加复杂,因为FOO 类之前提供了默认的setData(int ID),而不是所有从FOO 继承的类,因此可能/可能不需要实现setData,它们的实现确实有所不同疯狂地。

我已经看过了 How to Check if the function exists in C/C++ 不幸的是,这并不能回答我的问题。

在我看到人们使用模板的一些帖子中,这不是我的选择,因为这需要在运行时完成。其他选项似乎建议将 /mangling 技巧与 GCC 等联系起来。我需要将我的代码构建为独立于平台和编译器。所以这也不是一个选择。

还有更多建议,唯一可能的解决方案似乎是 https://stackoverflow.com/a/8814800/1376317 但我真的不确定如何在我的工作流程中实现这一点,或者这是否与我的问题有关。

【问题讨论】:

  • 你不能。相反,修复你过于复杂的设计(这很有趣;你自己提到过:“问题因为……而变得更加复杂”)。
  • 出于好奇:运行时必须发生这种情况的原因是什么?
  • 我看到的那个 mspaint 恐怖吗?只是为了您自己的理智,请查看inkscape 以获取此类图表。至少,在您意识到最终图像中的文字太小后,您几乎可以立即调整它们的大小。
  • 另外,为了确保您没有遇到xy problem,请提供一些关于您实际尝试做的事情以及为什么选择这个特定(不可能的)解决方案的详细信息。
  • IDaObj 从哪里来的 Init 方法?

标签: c++ rtti


【解决方案1】:

你可以这样做:

class Foo
{
public:
    // Old interface
    virtual void setData(int ID) { /* Old default implementation */ }

    // New interface
    virtual void setData(dataObj aObj) { /* New default implementation */ }

    void init() {
        if (useOldInterface()) {
            setData(ID);
        } else {
            setData(aObj);
        }
    }

private:
    // temporary method to be removed once all derived classes return false.
    virtual bool useOldInterface() const { return true; }
};

并通过添加逐步更改派生类

virtual bool useOldInterface() const override { return false; }

和适当的void setData(dataObj aObj)

【讨论】:

  • 我不是设计模式方面的专家。但是是否有一些设计模式、委托、函子方法可以让我更优雅地做到这一点,或者不触及派生类?从我所看到的一开始,这很可能是不可能的。 @Jarod42,如果没有其他问题,我可能会接受这个答案。似乎是在派生类部分进行最少增量代码更改的唯一选择,以完成我正在尝试的事情。
  • @thassan:如果你已经有一个Visitor,你可以使用它。否则,您可以为每个派生类使用ifdynamic_cast 级联,但它不太优雅,但不会触及层次结构。
【解决方案2】:

如果修改 dataObj 类是一种选择,并且创建和销毁 dataObj 对象不是太昂贵,那么您可以考虑以下。我不是特别喜欢它,但就短期黑客而言,我见过更糟糕的......

class dataObj
{
int x;
public:
    int getID(void) const { 
        std::cout << "dataObj::getID " << std::endl;
        return x;
    }
    dataObj() : x(0){}
    ~dataObj(){}

};
class Foo
{
public:
    // Old interface
    virtual void setData(int ID) {
        /* Old default implementation */
        std::cout << "Foo::setData int" << std::endl;
    }

    // New interface
    virtual void setData(const dataObj& aObj) {
        /* New default implementation */
        std::cout << "Foo::setData dataObj" << std::endl;
        setData(aObj.getID());
    }

};

class A : public Foo
{
public:
    virtual void setData(int ID) {
        /* Old default implementation */
        std::cout << "A:: setData int" << std::endl;
    }

};

class B : public Foo
{
public:
    virtual void setData(const dataObj& aObj) {
        /* Old default implementation */
        std::cout << "B:: setData dataObj" << std::endl;
    }

};

int main(int argc, char* argv[])
{
    A a;
    B b;
    dataObj d;
    Foo* pa, * pb;
    pa = &a;
    pb = &b;
    pa->setData(d);
    pb->setData(d);
return 0;
}

【讨论】:

  • 谢谢,但这不完全是我的情况。如果我看看你提出的建议,你现在的 A 类也继承了 setData(dataObj) 以前它曾经覆盖 setData(int ID) 和 .现在可以通过继承调用setData(dataObj)。但对我来说,这根本不是一个选择。如果我们之前必须为继承自 Foo 的类 A 重写 setData(int data),这意味着类 A 需要特殊处理,即使现在也需要重写 setData(dataObj),因为它需要特殊处理。跨度>
  • 所以这种从base获取默认行为的方法是行不通的,
猜你喜欢
  • 1970-01-01
  • 2010-10-05
  • 2018-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-26
  • 2017-10-11
相关资源
最近更新 更多