检测方法是否已被覆盖 [英] Detect whether a method has been overridden

查看:92
本文介绍了检测方法是否已被覆盖的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给定C ++基类指针,有没有办法检测某个虚拟方法是否已被覆盖?

Given a C++ base class pointer, is there a way to detect whether a certain virtual method has been overridden?

我正在写一种英语的口译员.我有一个基类来代表各种值类型的专门化值.这是一个简化的示例:

I'm writing an interpreter for a little language. I have a base class to represent values with specializations for the various value types. Here's a simplified example:

class Value {
  public:
    virtual bool CanBeString() const { return false; }
    virtual std::string GetAsString() const {
      throw std::logic_error("Value cannot be represented as a string.");
    }

    virtual bool CanBeInt() const { return false; }
    virtual int GetAsInt() const {
      throw std::logic_error("Value cannot be represented as an int.");
    }
};

class StringValue : public Value {
  public:
    bool CanBeString() const override { return true; }
    std::string GetAsString() const override { return m_string; }
  private:
    std::string m_string;
};

class IntValue : public Value {
   public:
     // Even though this is an integer, it can be represented as a string.
     bool CanBeString() const override { return true; }
     std::string GetAsString() const override { /* return string rep of m_int */ }

     bool CanBeInt() const override { return true; }
     int GetAsInt() const override { return m_int; }
   private:
     int m_int;
};

解释器使用指向Value的指针,并在运行时进行类型检查.假设解释器具有一个值,并且它需要在该值上执行仅适用于int的操作.它将首先检查pValue->CanBeInt().如果为true,则解释器继续pValue->GetAsInt()并进行处理.如果该值与int不兼容,则报告类型错误.

The interpreter works with pointers to Values and does type-checking at runtime. Suppose the interpreter has a value and it needs to execute an operation on it that applies only to ints. It will first check pValue->CanBeInt(). If true, the interpreter proceeds with pValue->GetAsInt() and does the processing. If the value is not compatible with an int, it reports a type error.

GetAsXxx的基本实现不应执行.如果执行一个,则说明解释器中存在错误(它忘记首先检查类型).这些throw语句是要通知我修复解释器.我不想因为正在解释的代码中的类型错误而抛出异常.

The base implementations of GetAsXxx should never be executed. If one is executed, it means there's a bug in the interpreter (it forgot to check the type first). Those throw statements are to signal me to fix the interpreter; I do not want to throw an exception because of a type error in the code that's being interpreted.

为了使向系统中添加新类型更容易(并且更不容易出错),我一直在尝试确定是否有一种方法可以消除派生类重写CanBeXxx的需要.能够检测相应的GetAsXxx方法是否已被覆盖.

In order to make it easier (and less error prone) to add new types to the system, I've been trying to determine if there's a way to eliminate the need for the derived classes to override the CanBeXxx by being able to detect if the corresponding GetAsXxx method has been overridden.

我的具体想法是将CanBeXxx方法更改为基类中定义的非虚拟方法,这些方法试图将GetAsXxx方法的成员函数指针与Value::GetAsXxx的成员函数指针进行比较.如:

My specific idea was to change the CanBeXxx methods to non-virtual ones defined in the base class that try to compare the member function pointer for the GetAsXxx method to the one for Value::GetAsXxx. As in:

bool CanBeInt() const { return &GetAsInt != &Value::GetAsInt; }

A,这不会编译,因为显然您无法获得已绑定方法的成员函数指针.这个想法或其他方法是否有变体,可以考虑到这一点?

Alas, this doesn't compile because apparently you can't get a member function pointer for a method that's already bound. Is there a variation on this idea or another approach that would allow for this little slice of reflection?

推荐答案

将成员方法指针分开进行比较是特定于编译器的,因为不同的编译器对方法指针的处理方式也不同.但是,您可以考虑采用另一种设计.它不会完全消除问题,但会对其进行一些简化,同时仍提供了将来添加更多类型的灵活性:

Pulling apart member method pointers to do comparisons is compiler-specific, as different compilers handle method pointers differently. However, there is an alternative design you might consider. It won't completely eliminate the problem, but it will simplify it a little, while still providing flexibility to add more types in the future:

const unsigned int CanBeInt = 1;
const unsigned int CanBeString = 2;
...

class Value {
  private:
    unsigned int flags;
  public:
    Value(unsigned int aflags) : flags(aflags) {}

    unsigned int GetFlags() const { return flags; }

    inline bool CanBeString() const { return (flags & CanBeString); }
    virtual std::string GetAsString() const {
      throw std::logic_error("Value cannot be represented as a string.");
    }

    inline bool CanBeInt() const { return (flags & CanBeInt); }
    virtual int GetAsInt() const {
      throw std::logic_error("Value cannot be represented as an int.");
    }
};

class StringValue : public Value {
  public:
    StringValue() : Value(CanBeString) {}
    std::string GetAsString() const override { return m_string; }
  private:
    std::string m_string;
};

class IntValue : public Value {
   public:
     // Even though this is an integer, it can be represented as a string.
     IntValue() : Value(CanBeInt | CanBeString) {}
     std::string GetAsString() const override { /* return string rep of m_int */ }
     int GetAsInt() const override { return m_int; }
   private:
     int m_int;
};

if (pValue->CanBeInt()) {
    int val = pValue->GetAsInt();
    ...
}


if (pValue->GetFlags() & CanBeInt) {
    int val = pValue->GetAsInt();
    ...
}

if (pValue->CanBeString()) {
   std::string val = pValue->GetAsString();
   ...
}

if (pValue->GetFlags() & CanBeString) {
   std::string val = pValue->GetAsString();
   ...
}

另一个建议,例如@Beta建议:

Another option, like @Beta suggested:

class Value {
  public:
    virtual bool GetAsString(std::string &) const { return false; }
    virtual bool GetAsInt(int &) const { return false; }
};

class StringValue : public Value {
  public:
    bool GetAsString(std::string &value) const override { value = m_string; return true; }
  private:
    std::string m_string;
};

class IntValue : public Value {
   public:
     // Even though this is an integer, it can be represented as a string.
     bool GetAsString(std::string &value) const override { value = ...; return true; }
     bool GetAsInt(int &value) const override { value = m_int; return true; }
   private:
     int m_int;
};

std::string val;
if (!pValue->GetAsString(val))
   throw std::logic_error("Value cannot be represented as a string.");

int val;
if (!pValue->GetAsInt(val))
   throw std::logic_error("Value cannot be represented as a int.");

这篇关于检测方法是否已被覆盖的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆