I was looking at some tutorials on how to make an unordered_set for a class/struct. I found this easy-to-understand code (as a Java developer) which does the trick:
#include <iostream>
#include <unordered_set>
using namespace std;
struct Node{
int val;
bool operator==(const Node& n) const{
return (this->val == n.val);
}
};
class HashFunction{
public:
size_t operator()(const Node& n) const{
return n.val;
}
};
int main(){
Node n1 = { 1 }, n2 = { 2 },
n3 = { 3 }, n4 = { 4 };
unordered_set<Node, HashFunction> us;
us.insert(n1);
us.insert(n2);
us.insert(n3);
us.insert(n4);
for (auto node : us){
cout << node.val << " ";
}
cout << endl;
return 0;
}
I was wondering if we can make the struct Node
a class, make the int val
a private field and add unordered_set<Node, HashFunction> neighbours
as a field to the Node
class.
If not, what is a good practice to keep classes/structs well-encapsulated and have sets/maps fields for classes?
There are a few questions here, so I'll try to answer them in order:
can make the
struct Node
a class
Yes, struct
and class
only differ in their default permissions (in struct
things are public
unless stated otherwise, in class
they are private
)
So this is identical code to what you wrote:
class Node{
public:
int val;
bool operator==(const Node& n) const{
return (this->val == n.val);
}
};
make the
int val
a private field and addunordered_set<Node, HashFunction> neighbours
as a field to theNode
class
Yes, you can. The easiest way I can think of to make that transition from the code that you wrote is to make HashFunction
be a sub-class of Node
.
For example:
class Node {
class HashFunction {
public:
size_t operator()(const Node& n) const{
return n.val;
}
};
public:
Node(int _val) : val(_val) {}
bool operator==(const Node& n) const{
return (this->val == n.val);
}
// More methods here
private:
int val;
unordered_set<Node, HashFunction> neighbours;
};
If not, what is a good practice to keep classes/structs well-encapsulated and have sets/maps fields for classes?
I guess that is somewhat of a mute question in this case - but the general answer is to expose only the minimum required interface. For example, right now HushFunction
is aware of the internal content of Node
. in order to increase encapsulation we could have added a hush
method to Node
and have HushFunction
invoke that method. This way if the content of Node
changes, nothing outside of Node
needs to be aware of it.