打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
请谨慎实现operator==操作符函数
在c++中,==操作符是很有用的,但是它的实现也并非想象中的那样容易。本文将围绕一个简单的c++例子程序展开讨论,以便寻求一个简单的解决方法。
在开始讲述等于操作符之前,我们先了解一下涉及的类定义。第一个类是一个一维点定义,很简单。一个构造器和析构器,一个operator==操作符。
Definition of Class Point1D
class Point1D
{
protected:
int xPos;
public:
Point1D( int x = 0 )
: xPos( x )
{
}
virtual ~Point1D()
{
}
inline bool operator==( const Point1D &rhs )
{
return xPos == rhs.xPos;
}
};
第二个类是Piont2D,它是一个二维点,y轴被使用来确认相应位置。
class Point2D : public Point1D
{
protected:
int yPos;
public:
Point2D( int x = 0, int y = 0 )
: Point1D( x ), yPos( y )
{
}
virtual ~Point2D()
{
}
inline bool operator==( const Point2D &rhs )
{
return (this == &rhs) || (xPos == rhs.xPos && yPos == rhs.yPos);
}
};
从上面来看,两个类好像都定义的很好,真的是这样吗?让我运行一下看看结果吧。
#include <iostream>
using namespace std;
int main( void )
{
Point1D p1d( 10 );
Point2D p2d( 10, 20 );
Point2D p2d2( 10, 30 );
Point1D *pp2d1 = &p2d;
Point1D *pp2d2 = &p2d2;
if ( p1d == p2d )
cout << "P1D is equal to P2D" << endl;
else
cout << "P1D is unequal to P2D" << endl;
if ( *pp2d1 == *pp2d2 )
cout << "P2D is equal to P2D2" << endl;
else
cout << "P2D is unequal to P2D2" << endl;
return 0;
}
Result:
P1D is equal to P2D
P2D is equal to P2D2
WOW,居然P1D与P2D是一样,P2D与P2D2也是一样。显然是一个错误!错误的原因在于我们错误的实现了Point1D的operator==操作符。它没有对它的子类进行有效的检查。此外,即使Point2D也重载了==操作符,也没有使P2D与P2D2能够正确的比较。其实,在多态的环境中,对于Point2D的操作符的重载往往是没有用处的,上面就是一个很好的例子。
我们现在遇到的问题是:
1)如何在Point1D中有效的对它的子类进行检查呢?
2)如何实现子类中的操作符比较函数?
对于1),我们没有办法判断,因为父类的实现代码中是无法预测子类的。有人可能会说为什么不把Point1D中的operator==声明为virtual类型,然后在子类中重置呢?它的实现代码可能类似于这样:
virtual bool operator==( const Point1D &rhs )
{
const Point2D *pp2d = dynamic_cast<const Point2D *>( &rhs );
if ( pp2d == NULL )
return false;
if ( this == pp2d )
return true;
return xPos == pp2d->xPos && yPos == pp2d->yPos;
}
到现在为止看上去好像是一个很好的主意,这样可以在使用==的时候时候清楚的识别子父类。真的是这样吗?请看下面测试结果J.
#include <iostream>
using namespace std;
int main( void )
{
Point1D p1d( 10 );
Point2D p2d( 10, 20 );
Point2D p2d2( 10, 30 );
Point1D *pp2d1 = &p2d;
Point1D *pp2d2 = &p2d2;
if ( p1d == p2d )
cout << "P1D is equal to P2D" << endl;
else
cout << "P1D is unequal to P2D" << endl;
if ( p2d == p1d )
cout << "P2D is equal to P1D" << endl;
else
cout << "P2D is unequal to P1D" << endl;
if ( *pp2d1 == *pp2d2 )
cout << "P2D is equal to P2D2" << endl;
else
cout << "P2D is unequal to P2D2" << endl;
return 0;
}
Result:
P1D is equal to P2D
P2D is unequal to P1D
P2D is unequal to P2D2
对于Point2D之间的比较我们很好的解决了,但是对于P1D和P2D之间的比较居然出现了戏剧性的自相矛盾!仔细研究代码后,我们发现问题还是出在Point1D的==操作符上,我们依然没有能够合适的识别子父类。如何解决呢?对于A=B成立的话,我们一定可以获得B=A也成立,所以我们在做Point1D的==操作符的时候,一定要做两次判断等于判断,即A == B && B == A. 请看下列代码.
virtual bool operator==( const Point1D &rhs )
{
return xPos == rhs.xPos && *const_cast<Point1D *>( &rhs ) == *this;
}
Ok,让我们再次运行测试代码把。
Result:
P1D is unequal to P2D
P2D is unequal to P1D
P2D is unequal to P2D2
非常好,好象我们把问题解决了,是吗?Point1D的问题解决了,但是Point2D呢?它也存在这样的问题,我的天,这样蹩脚的代码还要在Point2D中重写一次!我简直要发疯了!难道日后所有的子类都要这样吗?!!!有没有解决方法?不要太着急,我们可以很简单的处理它。请看下面完整代码.
#include <iostream>
using namespace std;
class Point1D
{
protected:
int xPos;
virtual bool equalTo( const Point1D &rhs ) const
{
return xPos == rhs.xPos;
}
public:
Point1D( int x = 0 )
: xPos( x )
{
}
virtual ~Point1D()
{
}
inline bool operator==( const Point1D &rhs )
{
return equalTo( rhs ) && rhs.equalTo( *this );
}
};
class Point2D : public Point1D
{
protected:
int yPos;
virtual bool equalTo( const Point1D &rhs ) const
{
const Point2D *pp2d = dynamic_cast<const Point2D *>( &rhs );
if ( pp2d == NULL )
return false;
if ( this == pp2d )
return true;
return yPos == pp2d->yPos && Point1D::equalTo( rhs );
}
public:
Point2D( int x = 0, int y = 0 )
: Point1D( x ), yPos( y )
{
}
virtual ~Point2D()
{
}
};
int main( void )
{
Point1D p1d( 10 );
Point2D p2d( 10, 20 );
Point2D p2d2( 10, 30 );
Point1D *pp2d1 = &p2d;
Point1D *pp2d2 = &p2d2;
if ( p1d == p2d )
cout << "P1D is equal to P2D" << endl;
else
cout << "P1D is unequal to P2D" << endl;
if ( p2d == p1d )
cout << "P2D is equal to P1D" << endl;
else
cout << "P2D is unequal to P1D" << endl;
if ( *pp2d1 == *pp2d2 )
cout << "P2D is equal to P2D2" << endl;
else
cout << "P2D is unequal to P2D2" << endl;
return 0;
}
Result:
P1D is unequal to P2D
P2D is unequal to P1D
P2D is unequal to P2D2
我们使用了equalTo函数来完成了A==B&&B==A的双向比较,在equalTo中,实现的方法和以前的完全一致,不关心比较的对象是否是父子关系。对于子类,我们仅仅重置equalTo方法就能够正确地实现了operator==方法,相当的出色,不是吗?!J
这样做的好处主要体现在以下几点:
1)能够在子类中正确地实现operator==方法,只要重置对应的equalTo就可以了。
2)operator==没有使用virtual修饰,WOW,长出了一口气,对于它的很多注意点终于可以解脱了。
3)也无需为蹩脚的virtual operator==感到伤心了,因为毕竟那样做并非是真正意义上的子类==操作符。Point2D中的操作符参数应该是Point2D,而非Point1D,难道不是吗J!
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
const使用详解
C++ 引用计数技术及智能指针的简单实现
c++ RTTI(运行时类型识别)
C++中智能指针的设计和使用
构造函数初始化和赋值的区别
第三章 class
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服