我在QT开发了一个c ++项目。我正在运行的问题是我希望有一个基类,我的所有属性类都继承,以便我可以将它们全部存储在一起。现在我有:
class AbstractProperty
{
public:
AbstractProperty(QString propertyName);
virtual QString toString() const = 0;
virtual QString getName() = 0;
virtual void fromString(QString str) = 0;
virtual int toInteger() = 0;
virtual bool operator==(const AbstractProperty &rightHand) = 0;
virtual bool operator!=(const AbstractProperty &rightHand) = 0;
virtual bool operator<(const AbstractProperty &rightHand) = 0;
virtual bool operator>(const AbstractProperty &rightHand) = 0;
virtual bool operator>=(const AbstractProperty &rightHand) = 0;
virtual bool operator<=(const AbstractProperty &rightHand) = 0;
protected:
QString name;
};
然后我实现了PropertyFloat和PropertyString等类,并基于假设只有字符串与字符串进行比较等来为比较器运算符提供实现。但是问题是如果我做了
,就不会抛出编译时错误 if(propertyfloat a < propertystring b)
但是我对每个派生类的运算符的实现依赖于它们都是相同的派生类。所以我的问题是我无法弄清楚如何实现一个属性结构,以便我可以让它们都从一些基类型继承,但像我上面的代码会抛出编译时错误。
关于如何做到这一点的任何想法?对于熟悉QT的人,我尝试使用QVariant的实现,但是QVariant没有运算符&lt;和&gt;仅在其某些派生类中定义,因此它无法解决。
我的最终目标是能够一般性地引用属性。我有一个元素类,它包含一个属性的hashmap,字符串'name'作为键,AbstractProperty作为值。我希望能够对这些属性进行一般操作。即如果我想获得给定其字符串名称的属性的最大值和最小值,我有完全通用的方法,它将从每个元素中提取相关的AbstactProperty并找到max / min,无论类型是什么。所以属性虽然最初被声明为PropertyFloat / PropertyString,但它们将被统一保存。
答案 0 :(得分:5)
如果不是让比较运算符的成员成为全局函数,那该怎样呢?
如果您这样做,那么您可以为每个给定类型创建一个运算符,并控制哪些类型可以相互比较:
bool operator==(const PropertyFloat &leftHand, const PropertyFloat &rightHand);
bool operator==(const PropertyString &leftHand, const PropertyString &rightHand);
编译器会在你这样做的时候抱怨:
if(propertyfloat a == propertystring b)
现在,为了访问比较所需的私有数据,使这些全局函数成为派生类的“朋友”。
答案 1 :(得分:2)
我的一个设计中遇到了类似的问题,直到我对它进行了冥想。我意识到在Base类中使用比较运算符是错误的。正如您所知,基类中的比较方法是比较后代类的任何组合。这是糟糕的业力。
更好的方法是在后代类中定义比较运算符。这将有助于编译器阻止人们使用不同类型的运算符。这样做的副作用是无法通过取消引用指向基类的指针来比较对象(这将是一件好事)。
另一个有用的工具是Boost比较模板。寻找equality_comparable
。
答案 2 :(得分:1)
另一种解决方案是使用Curiously Recurring Template Pattern。这允许模板化的类基于派生类定义比较运算符。
示例:强>
template <class Descendant>
struct Numeric_Field
{
Descendant m_value;
bool operator==(const Descendant& d)
{
return m_value == d.value;
}
bool operator!=(const Descendant& d)
{
return !(*this == d);
}
bool operator< (const Descendant& d)
{
return m_value < d.m_value;
}
bool operator<=(const Descendant& d)
{
return (*this < d) || (*this == d);
}
bool operator> (const Descendant& d)
{
return !(*this <= d);
}
bool operator>=(const Descendant& d)
{
return !(*this < d);
}
protected:
Numeric_Field(const Descendant& new_value = 0)
: m_value(new_value)
{ ;}
};
通过使用纯虚拟保护的setter和getter替换m_value
,可以使这更加通用:
template <class Descendant_Type>
struct Numeric_Field_2
{
virtual const Descendant_Type get_value(void) const = 0;
virtual void set_value(const Descendant& new_value) = 0;
bool operator==(const Descendant_Type& dt)
{
return get_value() == dt.get_value();
}
bool operator< (const Descendant_Type& dt)
{
return get_value() < dt.get_value();
}
};
此时,您可以在需要进行比较的地方传递指向Numeric_Field
的指针。我相信这只是一个打字器。