检测方法是否已被覆盖 [英] Detect whether a method has been overridden
问题描述
给定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 Value
s 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屋!