8.4.2 实现对比较运算符的完全支持(1)
有了前面实现的operator<()运算符函数,我们仍然有许多事情不能做。用CBox对象指定问题的解决方案可能涉及像下面这样的语句:
- if(aBox < 20.0)
- // Do something...
函数不会处理这里的表达式。如果试图使用比较CBox对象与数值的表达式,那么将得到一条错误消息。为了支持该功能,需要编写另一个版本的operator<()函数作为重载函数。
要支持刚刚看到的表达式类型非常容易。类内的成员函数定义如下所示:
- // Function to compare a CBox object with a constant
- bool CBox::operator<(const double& value) const
- {
- return this->Volume() < value;
- }
<运算符的右操作数对应于这里的函数形参。作为左操作数的CBox对象是由隐式指针this传递的。没有比这更简单的事情了,不是吗?但使用<运算符处理CBox对象仍然存在问题。我们希望写出下面这样的语句:
- if(20.0 < aBox)
- // do something...
有人可能认为,实现接受double类型右实参的operator>()运算符函数,然后相应重写上面这条语句,同样可以完成相同的功能,这么说非常正确。实际上无论如何,实现>运算符都是比较CBox对象所必需的。但是,在实现对某种对象类型的支持时,不应该人为地限制在表达式中使用这种对象的方式。对象的使用应该尽可能自然。现在的问题是如何来做。
成员运算符函数总是以左边的实参作为指针this。因为本例中左边的实参是double类型,所以不能以成员函数的形式实现该运算符。剩下的只有两种选择:普通函数或友元函数。因为不需要访问CBox类的private成员,所以该函数不必是友元函数。这样可以将左操作数属于double类型的重载<运算符实现为普通函数,如下所示:
- // Function comparing a constant with a CBox object
- inline bool operator<(const double& value, const CBox& aBox)
- {
- return value < aBox.Volume();
- }
如前所述,普通函数(就这一点而论也包括友元函数)使用直接成员选择运算符和对象名访问对象的公有成员。成员函数Volume()是公有的,因此这里使用该函数没有问题。
如果CBox类没有公有函数Volume(),可以直接将运算符函数声明为能够直接访问私有数据成员的友元函数,或者提供一组返回私有数据成员数值的成员函数,然后在普通函数中使用这些函数来实现比较功能。
还有另一种方式。我们需要用到>、>=、<=和!=运算符。读者可以自己实现这些运算符,也可以使用标准库所提供的。Utility头文件为运算符函数定义了一组模板,如下所示:
- template <class T> bool operator!=(const T& x, const T& y); // Requires ==
- template <class T> bool operator>(const T& x, const T& y); // Requires <
- template <class T> bool operator<=(const T& x, const T& y); // Requires <
- template <class T> bool operator>=(const T& x, const T& y); // Requires <
这些模板会给任意类创建比较运算符函数。上面的注释说明必须实现operator<()和operator==(),这些模板才能用于类。这些模板在std::rel_ops名称空间中定义,所以可以在源文件中使用下面的using指令启用这些模板:
- using namespace std::rel_ops;
有了上述指令,就可以对类自由运用这4个附加的运算符函数。下面就试一试。
试一试:完成>比较运算符的完全重载
可以在示例中将这些放在一起以说明实际的工作过程:
- // Ex8_04.cpp
- // Implementing the comparison operators
- #include <iostream> // For stream I/O
- #include <utility> // For operator overload templates
- using std::cout;
- using std::endl;
- using namespace std::rel_ops;
- class CBox // Class definition at global scope
- {
- public:
- // Constructor definition
- explicit CBox(double lv = 1.0, double wv = 1.0, double hv = 1.0):
- m_Length(lv), m_Width(wv), m_Height(hv)
- {
- cout << endl << "Constructor called.";
- }
- // Function to calculate the volume of a box
- double Volume() const
- {
- return m_Length*m_Width*m_Height;
- }
- // Operator function for 'less than' that
- // compares volumes of CBox objects.
- bool operator<(const CBox& aBox) const
- {
- return this->Volume() < aBox.Volume();
- }
- // 'Less than' operator function to compare a CBox object volume with a constant
- bool operator<(const double& value) const
- {
- return this->Volume() < value;
- }
- // 'Greater than' function to compare a CBox object volume with a constant
- bool operator>(const double& value) const
- {
- return this->Volume() > value;
- }
- // Overloaded equality operator
- bool operator==(const CBox& aBox) const
- {
- return this->Volume() == aBox.Volume();
- }
- // Destructor definition
- ~CBox()
- { cout << "Destructor called." << endl;}
- private:
- double m_Length; // Length of a box in inches
- double m_Width; // Width of a box in inches
- double m_Height; // Height of a box in inches
- };
- // Function comparing a constant with a CBox object
- inline bool operator<(const double& value, const CBox& aBox)
- {
- return value < aBox.Volume();
- }
- int main()
- {
- CBox smallBox(4.0, 2.0, 1.0);
- CBox mediumBox(10.0, 4.0, 2.0);
- CBox otherBox(2.0, 1.0, 4.0);
- if(mediumBox != smallBox)
- cout << endl << "mediumBox is not equal to smallBox";
- if(mediumBox > smallBox)
- cout << endl << "mediumBox is bigger than smallBox";
- else
- cout << endl << "mediumBox is not bigger than smallBox";
- if(otherBox >= smallBox)
- cout << endl << "otherBox is greater than or equal to smallBox";
- else
- cout << endl << "otherBox is smaller than smallBox";
- if(otherBox >= mediumBox)
- cout << endl << "otherBox is greater than or equal to mediumBox";
- else
- cout << endl << "otherBox is smaller than mediumBox";
- if(mediumBox > 50.0)
- cout << endl << "mediumBox capacity is more than 50";
- else
- cout << endl << "mediumBox capacity is not more than 50";
- if(10.0 < smallBox)
- cout << endl << "smallBox capacity is more than 10";
- else
- cout << endl << "smallBox capacity is not more than 10";
- cout << endl;
- return 0;
- }