给定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.");
更多推荐
检测方法是否已被覆盖
发布评论