【问题标题】:C++ Overloaded Operators with Classes带有类的 C++ 重载运算符
【发布时间】:2015-10-17 20:58:01
【问题描述】:

对于这个程序,我想创建一个 SET 类,它包含一组数学上的正数并且没有重复。创建 SET 类后,我为 + 和 * 创建了重载运算符,以将两个集合相加并分别找到两个集合的相交数。然而,在我开始对我的代码进行测试后,我注意到 + 和 * 重载运算符不适用于包含数字的两个集合,除非我创建了一个新的 SET 来输出数据。例如我必须这样做:

SET set3 = set1 + set2;
cout << set3;

而不是只能做:

cout << set1 + set2;

只有当两个集合都是空的或者一个集合被填充而另一个是空的时,我才能输出上面的代码。我不确定我做错了什么,所以无法输出两个填充集。我把我的代码分成三个文件。 这是头文件:

//CSCI 205
//Brett Milinski
//Assignment 2 - The Set Class
//This problem wants us to create a set class to hold a mathematical set of    integers and can later be manipulated to implement the Sieve of Eratosthenes method for computing prime numbers

    #ifndef SET_H
    #define SET_H
    #include<iostream>
    using namespace std;

    class SET
    {
    private: int a[50];
             int length;
             const int SIZE = 50;

    public: SET();
            SET(int a, int b);
            void print(ostream &os);
            void insert(int x);
            void erase(int x);
            int searchList(int a[], int length, int x);
            int addSearchList(int a[], int length, int x);
            friend SET& operator+(SET& a, SET& b);
            friend SET& operator*(SET& a, SET& b);
            friend ostream& operator<<(ostream& os, SET& a);
            SET& sieveOfEratosthenes(int n);
    };
    #endif

这里是定义方法的 set.cpp 文件:

//CSCI 205
//Brett Milinski
//Assignment 2 - The Set Class
//This problem wants us to create a set class to hold a mathematical set of integers and can later be manipulated to implement the Sieve of Eratosthenes method for computing prime numbers

#include"set.h"
#include<iostream>
using namespace std;

SET::SET() //default constructor
{
    length = 0;
}

SET::SET(int start, int end) //overloaded constructor
{
    length = end - start + 1; //end of range of numbers to be input

    if (length <= SIZE) //range isn't too big for the array
    {
        for (int x = 0; x < length; x++)
        {
            a[x] = start;
            start++;
        }
    }
}

void SET::insert(int x) //function to insert numbers from the array
{
    bool inserted = false;

    for (int i = 0; i < length; i++) //check to see if the value is already in the set, if so, don't add
    {
        if (a[i] == x)
        {
            inserted = true;
            cout << "Sorry, the SET already contains that number." << endl;
        }
    }

    if (inserted == false) //the SET does not contain the number that is trying to be inserted
    {
        int check = addSearchList(a, length, x); //check the position of where to add the value

        if (length == SIZE) //check to see if the array is already full
        {
            cout << "You cannot add anymore elements to this array because it is full." << endl;
        }
        else if (check == length) //check to see if it is added at the end
        {
            length++; //make the array one size bigger to make room for the addition
            a[length - 1] = x; //add the value to the end
        }
        else
        {
            length++; //make the array one size bigger to make room for the addition
            for (int i = length - 1; i >= check; i--) //start at the bottom and move up towards where the new value should be
            {
                a[i] = a[i - 1]; //ripple down
            }
            a[check] = x; //add in the new value
        }
    }

}

void SET::erase(int x) //function to erase numbers from the array
{
    int check = searchList(a, length, x); //check to see what the position is

    if (length == 0) //check to see if the array is empty before deleting anything
    {
        cout << "The array is empty and therefore nothing can be deleted from the elements." << endl;
    }
    else if (check != -1) //check to see if the value is found
    {
        for (int x = check; x < length - 1; x++)
        {
            a[x] = a[x + 1]; //ripples every element up
        }
        length--; //makes the array one size smaller to accomadate the deletion
    }
    else
    {
        cout << "The value entered is not in the array." << endl; //the value being checked for does not exist
    }

}

void SET::print(ostream &os) //function to output the values of the array
{
    os << "The contents of the set are:" << endl;
    for (int x = 0; x < length; x++)
    {
        os << a[x] << " ";
    }
    os << endl;
}

int SET::searchList(int a[], int length, int x) //a search for the erase function
{
    int index = 0;               // Used as a subscript to search array 
    int position = -1;           // Used to record position of search value 
    bool found = false;          // Flag to indicate if the value was found 

    while (index < length && a[index] <= x && !found)
    {
        if (a[index] == x) // If the value is found
        {
            found = true;          // Set the flag 
            position = index;      // Record the value's subscript 
        }
        index++;                  // Go to the next element 
    }
    return position;             // Return the position, or -1
}

int SET::addSearchList(int a[], int length, int x) //a search for the insert function
{
    int index = 0;               // Used as a subscript to search array 
    int position = -1;           // Used to record position of search value 

    while (index < length && a[index] <= x)
    {
        index++;                  // Go to the next element 
    }
    if (index == length) //all the values were smaller than the number trying to be added
    {
        position = length; //position is at the end of the array
    }
    else
    {
        position = index; //found where to add the new element
    }
    return position;             // Return the position, or currentSize 
}

//calls the print function to print to the output stream
ostream& operator<<(ostream& os, SET& a)
{
    a.print(os);
    return os;
}

//join the two sets together
SET& operator+(SET& a, SET& b)
{
    SET added;//empty set to add to

    if (a.length == 0 && b.length != 0) //for empty sets
    {
        return b;
    }
    else if (b.length == 0 && a.length != 0) //for empty sets
    {
        return a;
    }
    else
    {
        for (int x = 0; x < a.length; x++) //add in the elements from the first set
        {
            added.insert(a.a[x]);
            cout << added.a[x] << endl;
        }

        for (int x = 0; x < b.length; x++) //add in the elements from the second set
        {
            added.insert(b.a[x]);
            cout << b.a[x] << endl;
        }

        return added; //returns the added set
    }
}

//find what the two sets have in common
SET& operator*(SET& a, SET& b)
{
    int shortestLength = 0;
    SET inCommon;

    if (a.length < b.length) //find the shortest length
    {
        shortestLength = a.length;
    }
    else
    {
        shortestLength = b.length;
    }

    //search through and find the highest common number between the sets
        for (int x = 0; x < shortestLength; x++)
        {
            for (int i = 0; i < shortestLength; i++)
            {
                if (a.a[i] == b.a[x]) //see if it shares it and has it in common
                {
                    inCommon.insert(a.a[i]); //put in the shared value
                }
            }
        }

        return inCommon; //return the common numbers
}

这里是测试之前定义的不同方法的 setTest.cpp:

//CSCI 205
//Brett Milinski
//Assignment 2 - The Set Class
//This problem wants us to create a set class to hold a mathematical set of integers and can later be manipulated to implement the Sieve of Eratosthenes method for computing prime numbers

#include"set.h"
#include<iostream>
using namespace std;

int main()
{
    int dummy = 0;
    SET set1(1, 7); //overloaded constructor
    SET set2, set4; //default constructor
    SET set3(5, 10);
    SET set7(9, 11);

    //testing the functions of the SET class (overloaded constructor)
    cout << set1;
    cout << "Insert 5:" << endl;
    set1.insert(5); //try inserting to end
    cout << set1;
    cout << "Try insertering 5 again:" << endl;
    set1.insert(5); //try inserting a duplicate number
    cout << set1;
    cout << "Insert 0:" << endl;
    set1.insert(0); //try inserting to start
    cout << set1;
    cout << "Erase 3:" << endl;
    set1.erase(3); //try erasing from middle
    cout << set1;
    cout << "Insert 3:" << endl;
    set1.insert(3); //try inserting to the middle
    cout << set1;
    cout << "Erase 0:" << endl;
    set1.erase(0); //try erasing from the start
    cout << set1;
    cout << "Erase 5:" << endl;
    set1.erase(5); //try erasing from the end
    cout << set1;
    cout << "Erase 20 (shouldn't work because it isn't there):" << endl;
    set1.erase(20); //try erasing something that isn't there
    cout << set1;
    cout << "Add to the empty set (set2) and then erase from it:" << endl;
    set2.insert(1); //try adding to the empty set
    cout << set2;
    set2.erase(1); //try erasing from the now populated set
    cout << set2;

    //test second set (default constructor)
    cout << "This is the default constructor (an empty set, should contain no values)." << endl;
    cout << set2;

    //try adding two overlapping sets together
    cout << "Try adding two overlapping sets together:" << endl;
    cout << "The First Set:" << endl;
    cout << set1;
    cout << "The Other Set:" << endl;
    cout << set3;
    cout << "After adding the sets together together:" << endl;
    SET set5 = set1 + set3;
    cout << set5;

    //try adding two empty sets
    cout << "Try adding two empty sets together:" << endl;
    cout << "The First Set:" << endl;
    cout << set2;
    cout << "The Other Set:" << endl;
    cout << set4;
    cout << "After adding the sets together together:" << endl;
    cout << set2 + set4;

    //try adding one filled set and one empty set
    cout << "Try adding one filled set and one empty set together:" << endl;
    cout << "The First Set:" << endl;
    cout << set1;
    cout << "The Other Set:" << endl;
    cout << set2;
    cout << "After adding the sets together together:" << endl;
    cout << set1 + set2;

    //try adding two sets that don't overlap
    cout << "Try adding two sets that don't overlap:" << endl;
    cout << "The First Set:" << endl;
    cout << set1;
    cout << "The Other Set:" << endl;
    cout << set7;
    cout << "After adding the sets together together:" << endl;
    cout << set1 + set7;

    //find out what the sets have in common
    cout << "Find what the two sets have in common:" << endl;
    cout << "The First Set:" << endl;
    cout << set1;
    cout << "The Other Set:" << endl;
    cout << set3;
    SET set6 = set1 * set3;
    cout << "The number that the two sets have in common is contained in the set below (if 0, there is no common number unless it is 0)" << endl;
    cout << set6;


    cout << "Enter a dummy number:" << endl;
    cin >> dummy;
    return 0;
}

我不知道为什么我不能做我想做的事,提前感谢您对我的问题的任何帮助!

【问题讨论】:

  • 错误信息是什么?
  • 那是很多代码。您能否将其简化为一个演示您遇到的问题的最小示例?

标签: c++ class operators


【解决方案1】:

两个函数

SET& operator+(SET& a, SET& b);
SET& operator*(SET& a, SET& b);

返回一个临时对象的引用:

SET& operator+(SET& a, SET& b)
{
    SET added;

    // ...

    return added;  // <= temporary object returned via a reference - don't!!
}

这些临时对象(addedinCommon)通常由编译器在堆栈上分配,并在控制流离开定义它们的函数时“消失”,最终得到悬空引用。这是一个非常讨厌的错误。

要解决此问题,请确保按值而不是按引用返回这些对象。所需要的只是改变返回类型,如下所示:

SET operator+(SET& a, SET& b);
SET operator*(SET& a, SET& b);
^^^
no more references here

【讨论】:

  • 感谢您的意见。给我的作业表据说将它们作为参考,但我可以看到你所说的是正确的方法。我一定会和我的老师谈谈这件事,再次感谢!
【解决方案2】:

除了问题mentioned by @WhiteViking,你的声明

friend ostream& operator<<(ostream& os, SET& a);

应该是

friend ostream& operator<<(ostream& os, const SET& a);

否则您将无法将右值(即临时对象)绑定到参数a。在您的代码中,std::cout &lt;&lt; set1 + set2; 行中,operator&lt;&lt; 的第二个参数是右值set1 + set2,它只能绑定到右值引用或const 引用。实施这些更改后,您将能够使用 std::cout &lt;&lt; set1 + set2; 而不会出现任何问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-29
    • 1970-01-01
    • 2014-06-28
    • 1970-01-01
    • 2021-07-10
    • 1970-01-01
    • 2017-06-14
    相关资源
    最近更新 更多