C++ 运算符重载 2 个独立类成员的类对象

C++ Operator overloading class object for 2 separate class members

本文关键字:成员 对象 独立 运算符 重载 C++      更新时间:2023-10-16

假设我有一个类

class Car
{
public:
...
friend operator<(const Car&car1, const Car&car2){
return car1.getYear() < car2.getYear()
}
private:
int year;
double price;
string brand;
};

如果我想根据价格比较汽车,我如何使同一操作员超载?我必须创建两个 Car 对象,对于第一个汽车对象,我想使用年份进行比较,对于第二个汽车对象,我想使用其价格进行比较。

谢谢!

如果你的类有一个 price,那么你不需要编写重载运算符。你可以简单地说:

Car c1, c2;
// stuff
if ( c1.Price() < c2.Price() ) {
// do something
}

同样,你可能不需要在原始帖子中写重载;你可以使用getter。请注意,我并不是说getter是好主意。

如果我想根据价格比较汽车,我如何使同一操作员超载?

最好避免这种做法。相反,请使用两个不同的函子类。让调用代码选择他们要使用的函子。

struct CompareByYear
{
bool operator()(Car const& car1, Car const& car2)
{
return (car1.getYear() < car2.getYear());
}
};
struct CompareByPrice
{
bool operator()(Car const& car1, Car const& car2)
{
return (car1.getPrice() < car2.getPrice());
}
};

这种方法起初可能看起来很奇怪,但它非常简单,特别是如果你有多种方法来比较一个类的内部数据类型成员。

class Car {
public:
enum Comparetor {
BY_YEAR = 0,
BY_PRICE = 1,
};
private:    
int   _year;
float _price;
std::string _make;
public:
Car() :
_year( 0 ),
_price( 0 ),
_make( "" ) 
{}
Car( int year, float price, const std::string& make ) :
_year( year ),
_price( price ),
_make( make ) 
{}
int yearOf() const {
return _year;
}
float priceOf() const {
return _price;
}
std::string makeOf() const {
return _make;
}
bool compareByLT( Car::Comparetor comp, Car& car2 ) {
switch ( comp ) {
case BY_YEAR: {
return _year < car2._year;
break;
}
case BY_PRICE: {
return _price < car2._price;
break;
}
}
}
};   
int main() {    
Car car1( 2017, 24785.0f, "Ford Mustang" );
Car car2( 2018, 21579.0f, "Hyundai Elantra" );
if ( car1.compareByLT( Car::BY_YEAR, car2 ) ) {
std::cout << car1.makeOf() << " is older than " << car2.makeOf()
<< " by " << car2.yearOf() - car1.yearOf() << " year" << std::endl;
} else {
std::cout << car2.makeOf() << " is older than " << car1.makeOf()
<< " by " << car1.yearOf() - car1.yearOf() << " year" << std::endl;
}
if ( car1.compareByLT( Car::BY_PRICE, car2 ) ) {
std::cout << car1.makeOf() << " is cheaper than " << car2.makeOf()
<< " by $" << car2.priceOf() - car1.priceOf() << std::endl;
} else {
std::cout << car2.makeOf() << " is cheaper than " << car1.makeOf()
<< " by $" << car1.priceOf() - car2.priceOf() << std::endl;
}
_getch(); // #include <conio.h> prevent debugging console on Windows in Visual Studio from closing.
return 0;
}

由于歧义,您尝试执行的方法将不起作用。这意味着如果您尝试定义 2 个不同的运算符,编译器如何确定使用哪个overload,这些运算符采用相同的 2 个相同对象,这意味着它们的声明/定义/签名完全相同。它不知道如何区分你的意思。我应该按price还是year比较...?并且操作员不能接受另一个参数来知道是哪一个。

如果由于某种原因,由于某种继承或数据结构机制,您拥有的代码库要求您必须定义运算符......然后,只能为其中 1 个值(成员类型)重载运算符。您将不得不选择使用最有意义的一种。然后对于其他数据,您必须编写函数或方法来执行此操作。我在这里简单地展示的是,您可以将类内部数据的所有比较汇总到单个函数中,调用方必须传递要比较的枚举类型。

或者正如其他人所说;如果你有访问方法来检索私有成员,那么如果它们是内置的类型,或者是已经为它们定义了运算符的类型,你可以简单地通过它们进行比较。

上面当前类的后续:好的,我们现在有一个比较小于的比较函数,我们现在想对大于做同样的事情。与其像我们之前那样完全写出大于版本,不如像这样简化第二种方法:

bool compareByGT( Car::Comparetor comp, Car& car2 ) {
return !( compareByLT( comp, car2 ) );
}

这节省了大量不必要的代码输入,最大限度地减少了错误;但是你的第一个函数必须是100%无错误的,才能使第二个函数准确可靠。


现在,如果您尝试这样做:为类本身定义operator<(),并在类外定义一个友元版本,如下所示:

{
// Internal: Belongs to class
bool operator<( const Car& other ) {
_year < other._year;
}
// Friend of this class
friend bool operator<( const Car& car1, const Car& car2 );
};
bool operator<( const Car& car1, const Car2& car2 ) {
return car1._price < car2.price;
}

你认为会发生什么?

好吧,当您使用比较运算符时,这非常简单:

if ( car1 < car2 ) {
// Do something...
} else { 
// Do something else...
}

它将解析为使用属于该类的那个。

现在,如果您注释掉属于类的那个,保持代码中其他地方的 if 语句相同,代码不会中断,当您通过调试器编译、构建和再次运行它时,它应该可以毫无问题地执行,但是此时它将通过朋友版本进行比较。