繁体   English   中英

检测方法是否已被覆盖

[英]Detect whether a method has been overridden

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

背景

我正在为一种小语言写翻译。 我有一个基类来表示各种值类型的专门化值。 这是一个简化的示例:

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不兼容,则报告类型错误。

GetAsXxx的基本实现不应执行。 如果执行一个,则意味着解释器中存在错误(它忘记了首先检查类型)。 这些throw语句是要通知我修复解释器。 不想扔,因为这是被解释代码中的错误类型的异常。

动机

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

我尝试过的

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

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

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

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

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建议:

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.");

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM