简体   繁体   中英

C++ Overloaded Operators with Classes

For this program, I wanted to create a SET class that contains a mathematical set of positive numbers and no duplicates. After I had created the SET class, I created overloaded operators for + and * to add two sets together and to find the intersecting numbers of two sets respectively. However after I started doing testing for my code, I noticed that the + and * overloaded operators did not work on two sets containing numbers unless I created a new SET to output the data. For example I had to do:

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

Rather than being able to just do:

cout << set1 + set2;

I was able to output the above code only if both sets were empty or if 1 set was filled and the other was empty. I'm not sure what I am doing wrong to make it so two filled sets cannot be output. I broke my code up into three files. Here is the header file:

//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

Here is the set.cpp file that defines the methods:

//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
}

Here is the setTest.cpp that tests the different methods previously defined:

//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;
}

I'm not sure why I am not able to do what I want, thanks in advance for any help to my problem!

The two functions

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

return a reference to a temporary object:

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

    // ...

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

These temporary objects ( added and inCommon ) are typically allocated on the stack by the compiler and "disappear" when control flow leaves the function they are defined in, and you end up with dangling references. That's a very nasty bug.

To fix this problem make sure to return these objects by value instead of by reference. All that is needed is to change the return types like so:

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

Aside from the issues mentioned by @WhiteViking , your declaration of

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

should be

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

since otherwise you will not be able to bind rvalues (ie temporary objects) to the parameter a . And in your code, in the line std::cout << set1 + set2; , the second argument of operator<< is the rvalue set1 + set2 , which can only bind to a rvalue reference or a const reference. Once you implement these changes you'll be able to use std::cout << set1 + set2; without any more issues.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM