jpo*_*o38 7 c++ operator-overloading comparison-operators
这是一个非常简单的类层次结构:
class A
{
public:
A( int _a ) : a( _a ) {}
virtual bool operator==( const A& right ) const
{
return a == right.a;
}
virtual bool operator!=( const A& right ) const
{
return !( *this == right );
}
int a;
};
class B : public A
{
public:
B( int _a, int _b ) : A( _a ), b( _b ) {}
virtual bool operator==( const B& right ) const
{
return A::operator==( right ) && b == right.b;
}
int b;
};
Run Code Online (Sandbox Code Playgroud)
如您所见,operator!=在基类中定义.因为我很懒,所以我不想在所有派生类中复制这么简单的代码.
Unfortunatley,这段代码:
A a4(4), a5(5), a4bis(4);
assert( a4 == a4bis );
assert( a4 != a5 );
B b1(4,5), b2(4,6);
assert( !(b1 == b2) );
assert( b1 != b2 ); // fails because B::operator== is not called!
Run Code Online (Sandbox Code Playgroud)
b1 != b2返回false,因为它执行A::operator!=哪个调用A::operator==而不是B::operator==(即使运算符是虚拟的,因为派生类版本参数不同,它们在vtable中没有链接).
那么对于类层次结构来说,最好的地址是什么?=运算符的通用方式?
一种解决方案是在每个类中重复它,B然后将:
virtual bool operator!=( const B& right ) const
{
return !( *this == right );
}
Run Code Online (Sandbox Code Playgroud)
但是当你有很多课程时,这是一种痛苦......我有30 ....
另一种解决方案是采用通用模板方法:
template <class T>
bool operator!=( const T& left, const T& right )
{
return !( left == right );
}
Run Code Online (Sandbox Code Playgroud)
但是这会绕过任何!=类定义的任何运算符....所以如果一个声明它的方式不同(或者如果一个声明==自己调用!=它,它最终将会产生无限循环......),这可能会有风险.所以我觉得这个解决方案非常不安全....除非我们可以限制模板用于从我们层次结构的顶层类派生的所有类(A在我的例子中)....但我不认为这是可行的.
注意:我还没有使用C++ 11 ...抱歉.
你的功能B......
virtual bool operator==( const B& right ) const
Run Code Online (Sandbox Code Playgroud)
......不不重写的功能A...
virtual bool operator==( const A& right ) const
Run Code Online (Sandbox Code Playgroud)
...因为参数类型不同.(只有协变返回类型才允许存在差异.)
如果你纠正了这个,那么你就可以选择如何将B对象与其他A和A衍生对象进行比较,例如:
bool operator==( const A& right ) const override
{
if (A::operator==( right ))
if (typeid(*this) == typeid(right))
return b == static_cast<const B&>(right).b;
return false;
}
Run Code Online (Sandbox Code Playgroud)
请注意,使用typeid上面的比较意味着只有B对象将比较相等:任何B将比较不等于任何B衍生对象.这可能是也可能不是你想要的.
通过实现B::operator==,现有!=实现将正确包装operator==.正如Jarod42所观察到的A::operator==那样,当你的左侧值A只是A右侧对象的切片进行比较时,你的表现并不健全......你可能更喜欢:
virtual bool operator==(const A& right) const
{
return a == right.a && typeid(*this) == typeid(right);
}
Run Code Online (Sandbox Code Playgroud)
这具有与上述相同的问题B::operator==:例如,A将比较不等于未引入其他数据成员的派生对象.
像这样的事情怎么样?
class A {
protected :
virtual bool equals(const A& right) const {
return (a == right.a);
}
public :
A(int _a) : a(_a) { }
bool operator==(const A& right) const {
return this->equals(right);
}
bool operator!=(const A& right) const {
return !(this->equals(right));
}
int a;
};
class B : public A {
protected :
virtual bool equals(const A& right) const {
if (const B* bp = dynamic_cast<const B*>(&right)) {
return A::equals(right) && (b == bp->b);
}
return false;
}
public :
B(int _a, int _b) : A(_a), b(_b) { }
int b;
};
Run Code Online (Sandbox Code Playgroud)
将比较逻辑移至单独的(虚拟)函数equals,并从基类中定义的operator==和调用该函数。operator!=
不需要在派生类中重新定义运算符。要更改派生类中的比较,只需覆盖equals.
请注意,dynamic_cast上面代码中的 用来确保运行时类型是执行比较的有效类型。IE。对于B::equals,它用于确保是righta B- 这是必要的,因为否则right就没有b成员。
| 归档时间: |
|
| 查看次数: |
398 次 |
| 最近记录: |