C++ 重载 == 比较来自不同类的对象

Posted

技术标签:

【中文标题】C++ 重载 == 比较来自不同类的对象【英文标题】:C++ Overloading == to compare objects from different classes 【发布时间】:2019-04-03 01:35:48 【问题描述】:

对于实验室,我必须重载 + 运算符来添加来自同一类的对象,并重载 == 运算符来比较来自两个 不同 类的对象。重载 == 运算符的函数给我带来了很多麻烦(可能是因为我正在使用它来比较不同类的对象区域)。我一直在不懈地寻找解决方案,并且我尝试了所有发现的建议都没有成功,所以我不得不使用我的特定代码来询问:

// OBJECTIVES:
// Add areas of 2 circles
// Add areas of 2 rectangles
// Compare areas of a circle and a rectangle

#include <iostream>
using namespace std;

// **********************Header*********************
class circle

    friend bool operator==(const circle& ,
                           const circle&);
    friend circle operator+(const circle& , 
                            const circle&);
public:
    double radius, area;
    void calcArea();
;

class rect

    friend bool operator==(const rect& , 
                           const rect&);
    friend rect operator+(const rect& , 
                          const rect&);
public:
    double length, width, area;
    void calcArea();
;

void displayMenu();
// **************************************************

// **********************Program*********************
int main()

    int selection; // variable for menu selection

    circle firstCircle; // objects from circle class
    circle secondCircle;

    rect firstRect; // objects from rect class
    rect secondRect;

    do 
        displayMenu();
        cin >> selection;
        cout << endl;

        if (selection == 1) // add area of 2 circles
        
            firstCircle.calcArea();
            secondCircle.calcArea();
            circle thirdCircle = firstCircle + secondCircle;

            cout << "The sum of your two circles is: " ;
            cout << thirdCircle.area;
            cout << endl;
        

        else if (selection == 2) // add area of 2 rectangles
        
            firstRect.calcArea();
            secondRect.calcArea();
            rect thirdRect = firstRect + secondRect;

            cout << "The sum of your two rectangles is: " ;
            cout << thirdRect.area;
            cout << endl;

        

        else if (selection == 3) // compare areas of a circle and a rectangle
        
            firstCircle.calcArea();
            firstRect.calcArea();

            if (firstCircle.area == firstRect.area)
            
                cout << "The area of your circle is equal to that of your rectangle." << endl;
            
            else
            
                cout << "The area of your circle is not equal to that of your rectangle." << endl;
            
        

        else if (selection == 4) // exit program
        
            return 0;
        

        else
        
            cout << "Please enter a valid selection.";
            cout << endl;
            continue;
        
     while (1);

    return 0;

// **************************************************

// ******************Implementation******************
void circle::calcArea() // compute circle area

    cout << "Enter a radius: ";
    cin >> radius;

    area = 3.14159265359 * radius * radius;


void rect::calcArea() // compute rectangle area

    cout << "Enter a length: ";
    cin >> length;
    cout << "Enter a width: ";
    cin >> width;

    area = length * width;


bool operator==(const circle& firstCircle, // compare areas of objects
                const rect& firstRect)  // from different classes

    return (firstCircle.area == firstRect.area && 
            firstCircle.area == firstRect.area);


circle operator+ (const circle& firstCircle, // overload + for circle class
                    const circle& secondCircle)

    circle circleSum;

    circleSum.radius = firstCircle.radius + secondCircle.radius;
    circleSum.area = firstCircle.area + secondCircle.area;

    return circleSum;


rect operator+ (const rect& firstRect, // overload + for rect class
                    const rect& secondRect)

    rect rectSum;

    rectSum.length = firstRect.length + secondRect.length;
    rectSum.width = firstRect.width + secondRect.width;
    rectSum.area = firstRect.area + secondRect.area;

    return rectSum;


void displayMenu() // menu options

    cout << endl;
    cout << "What would you like to do?" << endl;
    cout << "1. Add the area of 2 circles."<< endl;
    cout << "2. Add the area of 2 rectangles."<< endl;
    cout << "3. Compare the area of a circle and a rectangle."<< endl;
    cout << "4. Exit.";

// **************************************************

现在,我没有使用重载的 == 来比较矩形和圆形区域,因为这样会出现很多编译器错误。如果你们能提供任何帮助我将firstCircle.area == firstRect.area 更改为firstCircle == firstRect,我们将不胜感激。

【问题讨论】:

看起来至少有一个问题是在代码中声明重载 == 运算符之前使用它。在 main 上方添加声明(您仍然可以在 main 函数代码块之后定义它)。 我建议您需要考虑继承。 Circle 和 Rectangle 都是有面积的形状(提示 Circle 和 Rectangle 继承自 Shape 类。 帮助阅读:What are the basic rules and idioms for operator overloading? 建议:当询问堆栈溢出问题时,备份您的程序,然后删除与问题无关的所有内容。如果问题不是关于菜单的,菜单就会出现。如果问题不是关于operator ++ 就可以了。你想要的只是main 和你遇到问题的东西。谁知道呢,如果没有额外的噪音,您可能会自己找出问题所在! 战术要点:为什么一个名为calcArea的方法接受输入?听起来应该是计算面积。一个函数应该做一件事,而且只做一件事。如果它做了两件事,它实际上就没那么有用了。例如,您无法计算现有圆的面积。你必须再次在半径范围内喂食,这有点愚蠢。 【参考方案1】:

有多种方法可以编写您想要的比较运算符。最简单的方法,无需干预您的类代码,只需实现几个非成员运算符:

bool operator==(const circle& c, const rect& r)  return r.area == c.area; 
bool operator==(const rect& r, const circle& c)  return c.area == r.area; 

您可以将它们放在main 函数上方的源文件中,或者放在单独的头文件中。请注意,他们不需要成为circlerect 的朋友,因为area 成员是公开的。

另一种方法是编写成员函数,但首先我们需要修复您现有的比较运算符:

class circle

public:
    bool operator==(const circle& other) const  return area == other.area; 

    // ...skipped...
;

它与您的版本有何不同以及为什么不同?

    这是一个比较thisother的成员函数,只接受一个参数。 从circle 类外部调用是公开的 它是 const 限定的,因为它只需要查找类数据而无需修改。

const 限定符还允许您像这样比较 const 对象:

const circle c1 = getSomeCircle();
const circle& c2 = otherCircle;
c1 == c2; // Note: statement has no effect, despite it's syntax is correct.
c2 == c1;

非 const 限定的比较将无法编译。总而言之,这是在 C++ 中编写比较运算符最惯用的方式。

最后,让我们在矩形比较中添加圆形:

class rect;

class circle

public:
    bool operator==(const circle& other) const  return area == other.area; 
    bool operator==(const rect&) const;

    // ...skipped...
;

class circle  /* class definition skipped */ ;

bool operator==(const rect& r) const  return area == r.area; 

首先我们在这里声明了rect 类。当类被声明但未定义时(即前向声明),我们可以使用指针和引用它的实例,但不能使用实例本身。我们不能使用实例的原因之一是类大小在定义之前是未知的。

然后我们声明成员operator==接受对前向声明类的引用,最后在rect定义之后我们可以实现操作符。

rectcircle 的比较可以以同样的方式实现。

【讨论】:

值得注意的是,比较doubles 是否相等会变得非常讨厌because doubles and double arithmetic is imprecise。通常你需要an epsilon。 @user4581301 当然可以。我只是在答案中跳过了这个话题,因为它对于 C++ 初学者来说已经足够大了。 不用担心。该说明更适合他们和追随者,因为当您没有预料到它时,这真是令人讨厌的惊喜。从来没有一个新人这样做过。【参考方案2】:

运算符重载可以像下面这样重载。

#include <iostream>
using namespace std;

class rect;

class circle

    friend bool operator==(const circle&,
        const circle&);
    //friend circle operator+(const circle&,
    //  const circle&);
public:
    double radius, area;
    //void calcArea();
public:
    friend bool operator == (const circle&, const rect&);
    double getArea()const  return area; 
;

class rect

    friend bool operator==(const rect&,
        const rect&);
    //friend rect operator+(const rect&,
    //  const rect&);
public:
    double length, width, area;
    //void calcArea();
public:
    friend bool operator == (const rect&, const circle&);
    double getArea() const return area; 
;

int main(int argc, char *argv[]) 
    circle c;
    rect r;
    if (c == r) 
        cout << "It was a miracle a random circle is equal to a random rectangle in size!!!" << endl;
    
    return 0;


bool operator == (const circle &c1, const circle &c2) 
    return c1.getArea() == c2.getArea();


bool operator == (const rect &r1, const rect &r2) 
    return r1.getArea() == r2.getArea();


bool operator == (const circle &c, const rect &r) 
    return c.getArea() == r.getArea();


bool operator == (const rect &r, const circle &c) 
    return c.getArea() == r.getArea();

【讨论】:

注意:如果circlerect 派生自shape,并且shape 有一个getArea 方法,那么您可以bool operator == (const shape &amp;a, const shape &amp;b) return a.getArea() == b.getArea();

以上是关于C++ 重载 == 比较来自不同类的对象的主要内容,如果未能解决你的问题,请参考以下文章

c++重载覆盖和隐藏

操作符重载

重载运算符+ C++

在 C++ 中重载比较运算符会导致“无效运算符<”

虚函数与重载函数的区别

[ C++ ] C++类与对象(中) 类中6个默认成员函数 -- 运算符重载