Hi, I know asking for help with homework is usually frowned upon here, but considering the fact that it's already complete and turned in, I just wanted to see if anyone a little more proficient than myself had any suggestions/critiques of the way I wrote this. It's basically just teaching you how to overload operators to handle different class objects. Ours were just class Set and it basically emulated an unordered set. The requirements were to create the class, add member functions to add ints to the Set, remove ints from the set, and overload the operators & and | to create a union or intersection between the two sets.
Thanks in advance for any insights. It's one of those things where I wrote the code, it works, but it felt like it was too easy and I was cutting corners somewhere but can't quite identify where. I'm a CIS major so I want to actually learn the "right" way to do things, not just write code that "works." Probably a good idea as I am planning on coding for a living.
#include "set.h"
#include <iostream>
#include <string>
#include <vector>
Set::Set()
{
//default (empty) constructor
}
/*
* Default constructor with name parameter
* @param name - name of number set
*/
Set::Set(std::string name)
{
this->name = name;
//uncomment next line to indicate object creation in ostream
//std::cout << "Created number set " << name << "!" << std::endl;
}
/*
* Returns the private data member std::string name;
* @param void
* @return name : name of number set (set by default)
* constructor with string parameter
*/
std::string Set::get_name()
{
return name;
}
bool Set::num_present(int newNum, std::vector<int> set)
{
bool found = false;
for(int i = 0; i < set.size(); i++)
{
if(set[i] == newNum)
{
found = true;
}
if(found)
{
break;
}
}
return found;
}
/*
* Function to add number to set
* @param newNum - new number to add to the set vector
*/
void Set::add(int newNum)
{
if(!num_present(newNum, num_set))
{
num_set.push_back(newNum);
}
}
/*
* Removes a number from Set object
* @param rNum - integer to remove from set vector
*/
void Set::remove(int rNum)
{
for(int i = 0; i < num_set.size(); i++)
{
if(num_set[i] == rNum)
{
num_set.erase(num_set.begin() + i);
}
}
}
/* Retrieves a the number set as a vector for the Set object
* @param void
* @return o_set - Usable vector
*/
std::vector<int> Set::get_set()
{
returnthis->num_set;
}
/*
* Prints the selected number set object to the console.
* the "Old Fashioned Way" of printing out the set without
* operator overloading. Can be slightly modified
* to actually serve as overload function. Kept here
* as a redundancy just in case.
* @param void
* @return void
*/
void Set::print()
{
std::cout << "\"" << name << "\" is as follows: {";
for(int i = 0; i < num_set.size(); i++)
{
//avoid placing a comma after the last number in the set
if(i == num_set.size() - 1)
{
std::cout << num_set[i];
} else {
std::cout << num_set[i] << ", ";
}
}
std::cout << "}" << std::endl;
}
#include <iostream>
#include "set.h"
/*
* Overload the output stream operator to accept
* Set objects
* @param out : ostream reference
* @param set : Set object reference
* @return out: ostream object passed by reference
*/
std::ostream& operator<<(std::ostream& out, Set set)
{
std::vector<int> buff = set.get_set();
out << "{";
for(int i = 0; i < buff.size(); i++)
{
//avoid placing a comma after the last number in the set
if(i == buff.size() - 1)
{
out << buff[i];
} else {
out << buff[i] << ", ";
}
}
out << "}" << std::endl;
return out;
}
/*
* Overload the | operator to produce
* a union of two sets and return
* a new, combined Set object
* @param result : newly generated unified set
* @param first : first Set object
* @param second: second Set object
* @return result : third, unified set object
*/
Set operator|(Set& first, Set& second)
{
Set result;
std::vector<int> x = first.get_set();
std::vector<int> y = second.get_set();
/*
* Merge set vectors into one that can be more easily
* worked with.
*/
std::vector<int> temp = x;
temp.insert(temp.end(), y.begin(), y.end());
//Iterate through temp array to populate result Set object
for(int i = 0; i < temp.size(); i++)
{
result.add(temp[i]);
}
return result;
}
/* Overloads the & operator to produce a new Set object
* that contains an intersection of the two original Set
* objects
*/
Set operator&(Set& first, Set& second)
{
Set result;
std::vector<int> x = first.get_set();
std::vector<int> y = second.get_set();
std::vector<int> temp;
for(int i = 0; i < x.size(); i++)
{
for(int j = 0; j < y.size(); j++)
{
if(x[i] == y[j])
{
temp.push_back(x[i]);
}
}
}
//loop through temp array to populate Set object
for(int i = 0; i < temp.size(); i++)
{
result.add(temp[i]);
}
return result;
}
int main()
{
Set a("A");
Set b("B");
Set c("C");
a.add(1);
a.add(2);
a.add(5);
a.add(7);
a.add(7);
a.add(7);
a.add(3);
a.add(1);
a.add(420);
b.add(3);
b.add(7);
b.add(69);
b.add(9);
b.add(5);
b.add(5);
b.add(22);
b.add(22);
b.add(3);
c.add(22);
c.add(7);
c.add(5);
c.add(9);
c.add(73);
c.add(69);
c.add(69);
c.add(69);
c.add(420);
c.add(69);
std::cout << "Set " << a.get_name() << ": " << a;
std::cout << "Set " << b.get_name() << ": " << b;
std::cout << "Set " << c.get_name() << ": " << c;
std::cout << "\nUnion of " << a.get_name() << " and " << b.get_name() << ": " << (a|b);
std::cout << "Union of " << b.get_name() << " and " << c.get_name() << ": " << (b|c);
std::cout << "Union of " << a.get_name() << " and " << c.get_name() << ": " << (a|c);
std::cout << "\nIntersection of " << a.get_name() << " and " << b.get_name() << ": " << (a&b);
std::cout << "Intersection of " << b.get_name() << " and " << c.get_name() << ": " << (b&c);
std::cout << "Intersection of " << a.get_name() << " and " << c.get_name() << ": " << (a&c);
//test out void Set::remove(int)
a.remove(7);
a.remove(420);
b.remove(420);
std::cout << "\nSet " << a.get_name() << " with '7' and '420' removed: " << a << std::endl;
std::cout << "Set " << b.get_name() << " with '420' removed: " << b << std::endl;
return 0;
}
Not only that the values are unique they are also ordered in a std::set.
Particularly your operator& might not generate correct result because the values are not ordered.
#ifndef SET_H
#define SET_H
#include <iostream>
#include <vector>
#include <string>
class Set
{
public:
Set() = default; // No implementation required
Set(const std::string&); // Do not unnecessaryly copy data
void add(int);
void remove(int);
void print();
const std::vector<int>& get_set() const; // Do not copy + const correctness
const std::string& get_name() const; // Do not copy + const correctness
bool num_present(int, std::vector<int>); // This is not a member function. Consider make it static
private:
std::vector<int> num_set;
std::string name;
};
#endif
I would suggest to put the prototypes of the operators in set.h and the implementation in set.cpp.
- Pass std::string, std::vector et al as const ref rather than by value so a copy is not done. Eg
1 2 3 4 5 6 7 8 9 10
bool Set::num_present(int newNum, const std::vector<int>& set)
{
bool found {};
for (size_t i {}; !found && i < set.size(); ++i)
if (set[i] == newNum)
found = true;
return found;
}
Also see other changes.
But why is vector passed at all - shouldn't this use the class vector?
1 2 3 4 5 6 7 8 9 10
bool Set::num_present(int newNum)
{
bool found {};
for (size_t i {}; !found && i < num_set.size(); ++i)
if (num_set[i] == newNum)
found = true;
return found;
}
- For a constructor, use initialisation if possible rather than assignment. Eg:
Not only that the values are unique they are also ordered in a std::set.
Particularly your operator& might not generate correct result because the values are not ordered.
Yes, I am aware that the standard library contains unordered and ordered sets. That was not the purpose of this assignment. The object was to overload the ostream operator, the &, and | to handle custom objects. Number sets were just a convenient way to demonstrate this principle that my teacher used as his worked example during lecture. This was the prompt for the assignment, verbatim:
Define a class Set that stores a finite set of integers. (In a set, the order of elements does not matter, and every element can occur at most once.) Supply add and remove member functions to add and remove set elements. Overload the | and & operators to compute the union and intersection of the set, and the
<< operator to send the set contents to a stream.
I would suggest to put the prototypes of the operators in set.h and the implementation in set.cpp.
We were specifically asked to not write these as member functions and to include them inline in main.cpp
Also thank you seeplus, I will have to implement a couple of those suggestions