I'm coming from a Python background, so forgive me on this one. Though I will provide the Python equivalent of what I'm looking for.
I'm creating a list of network nodes, so I wanted to create a class, "Node", that stores their MAC, IP address, and Hostnames, along with a function that prints them out prettily. The following is my code:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Node {
string MAC, IP, Hostname;
public:
void set_values(string M, string I, string H);
string list() {return "MAC: "+MAC+"\nIP: "+IP+"\nHostname: "+Hostname+"\n";}
};
void Node::set_values(string M, string I, string H) {
MAC = M;
IP = I;
Hostname = H;
}
int main(int argc, char* argv[])
{
Node firstnode;
firstnode.set_values("C0:FF:EE:C0:FF:EE","192.168.1.60","My-PC");
cout<<firstnode.list();
}
Which prints this out when I run it:
MAC: C0:FF:EE:C0:FF:EE
IP: 192.168.1.60
Hostname: My-PC
What I want is to have these objects automatically added to a vector called NodeList upon creation. For example, here is how I did that in Python:
RecordersList=[]
class Recorder:
def __init__(self, ARecorder, BRecorder, CRecorder):
self.ARecorder = ARecorder
self.BRecorder = BRecorder
self.CRecorder = CRecorder
RecordersList.append(self)
I tried a similar move, where I put the line:
vector<Node> NodeList; before the class declaration (and NodeList.push_back(this); as a Public function), and tried after the class declaration, but either way the compiler isn't aware of the Node class by the time the vector is declared, or vice versa the Node class isn't aware of the NodeList vector.
Is there a way to do this? It would be self-referencial class appending to an existing vector whose type is of that class.
Sure: declare and define a static member in the class, push the this pointer onto it:
class Foo; // forward declaration to make vector happy
class Foo {
private:
static std::vector<Foo *> store;
public:
Foo() { store.push_back(this); }
};
std::vector<Foo *> Foo::store;
Do it explicitly:
std::map<std::string, Node> map;
map[mac1] = Node(mac1,...);
map[mac2] = Node(mac2,...);
In my experience, this sort of design will often not end well due to having to manually manage memory in C++. this is a raw pointer to the object and it is not managed.
You can do this:
class Node; // forward declaration
std::vector<Node*> NodeList;
class Node
{
public:
Node()
{
NodeList.push_back(this); // pass a POINTER to this object
}
};
int main(int argc, char* argv[])
{
Node* node1 = new Node(); // allocated a Node
Node* node2 = new Node(); // allocated a Node
// ...
// deallocate ALL nodes
std::vector<Node*>::iterator it = NodeList.begin();
while (it != NodeList.end())
{
delete *it;
++it;
}
NodeList.clear();
}
The problem with this solution is if you have pointers pointing to indivual nodes. You could end up with dangling pointers and memory corruption.
And alternative solution is:
class Node
{
public:
Node();
};
std::vector<Node> NodeList;
Node::Node()
{
NodeList.push_back(*this); // pass a REFERENCE to this object
}
int main(int argc, char* argv[])
{
Node node1; // create a node
Node node2; // create a node
// ...
}
The problem with this alternative design is that each node passed to NodeList will be a new COPY of that node. So if you do:
int main(int argc, char* argv[])
{
Node node1; // NodeList[0] is logically equal to node1
node1.DoStuffThatModifiesTheContent();
// At this point, node1 is no longer a logical equivalent of NodeList[0]
}
A better design would involve creating a NodeManager class of some sort, and creating and accessing nodes through this manager, which would control the lifetime of all the node objects.
Related
I'm trying to speed up a python routine by writing it in C++, then using it using ctypes or cython.
I'm brand new to c++. I'm using Microsoft Visual C++ Express as it's free.
I plan to implement an expression tree, and a method to evaluate it in postfix order.
The problem I run into right away is:
class Node {
char *cargo;
Node left;
Node right;
};
I can't declare left or right as Node types.
No, because the object would be infinitely large (because every Node has as members two other Node objects, which each have as members two other Node objects, which each... well, you get the point).
You can, however, have a pointer to the class type as a member variable:
class Node {
char *cargo;
Node* left; // I'm not a Node; I'm just a pointer to a Node
Node* right; // Same here
};
Just for completeness, note that a class can contain a static instance of itself:
class A
{
static A a;
};
This is because static members are not actually stored in the class instances, so there is no recursion.
No, but it can have a reference or a pointer to itself:
class Node
{
Node *pnode;
Node &rnode;
};
Use a pointer, & better initialized:
class Node {
char * cargo = nullptr;
Node * left = nullptr;
Node * right = nullptr;
};
Modern C++
It is a better practice to use smart-pointers (unique_ptr, shared_ptr, etc.), instead of memory allocations by 'new':
#include <string>
#include <memory> // For 'std::unique_ptr'
class Node {
public:
std::string cargo;
std::unique_ptr<Node> left;
std::unique_ptr<Node> right;
};
int main()
{
auto bt = std::make_unique<Node>();
(*bt).cargo = "Coffee";
(*bt).left = std::make_unique<Node>();
}
I have created a graph.h, graph.cpp, and main.cpp
In my graphics.h I've created two private structures an Edge
and a Node, and I've declared Edge first above Node but an
Edge has a node member so I've forward declared the Node struct
but I'm running into issues saying a "Graph::Node*" is incompatible
with "Node *" this occurs in my graph.cpp AddEdgeByName(string,string,double)
function, why does this happen? On top of this I dont know why I had to declare in (graphics.cpp) the function Graph::Node * Graph::findByName(string name) like that I thought the way i originally tried to declare it like this
Node * Graph::findByName(string name) would work but it gave me an error.
Im trying to make a Directed weighted graph by the way.
#include <iostream>
#include <string>
#include <vector>
using std::cout;
using std::cin;
using std::endl;
using std::string;
using std::vector;
struct Node;
class Graph{
private:
typedef struct edge{
double edgeWeight;
Node *pointsTo;
edge(){}
edge(const edge & copyObject){
this->edgeWeight = copyObject.edgeWeight;
this->pointsTo = copyObject.pointsTo;
}
} Edge;
typedef struct node{
string name;
vector<Edge> myEdges;// list of outgoing edges for this node
node(string myName){
name = myName;
}
node(const node & copyObject){
this->name = copyObject.name;
this->myEdges = copyObject.myEdges;
}
// adds another edge to this node
void addEdge(Node *pointTo, double weight){
Edge newEdge;
newEdge.edgeWeight = weight;
newEdge.pointsTo =
newEdge.pointsTo = pointTo;
myEdges.push_back(newEdge);
}
} Node;
vector<Node*> graph; // vector containing all the nodes for the
//graph
public:
Graph();
// finds a node in the list of nodes for the graph, using the name
Node * findByName(string name);
void add(string name);
void addEdgeByName(string first, string second,double weight);
};
#endif
// this is graphics.cpp
#include "Graph.h"
Graph::Graph(){
}
Graph::Node * Graph::findByName(string name){
for(std::vector<Node*>::iterator it = graph.begin(); it != graph.end(); ++it){
if((*it)->name == name){
return *it;
}
}
return NULL;
}
void Graph::add(string name){
Node * newNode = new Node(name); // creates a new node with the given //name
graph.push_back(newNode); // adds this node to our list of nodes in the //graph
}
// this publicly accessible function adds edges to each of the strings
void Graph::addEdgeByName(string first, string second,double weight){
Node * firstNode = findByName(first);
Node * secondNode = findByName(second);
firstNode->addEdge(secondNode,weight);
secondNode->addEdge(firstNode,weight);
}
Regarding the public/private problem: You can't. Having the structure with private visibility means it is only usable within your code's functions.
Making it public would be one solution. Another option would be to not use nested classes at all. (Personally I don't like them).
You should avoid doing typedef struct edge {....} Edge; . Instead use struct Edge { .... }; . It gains nothing to give your struct two names.
Your forward declaration struct Node; declares a different struct to Graph::Node. Perhaps you meant for struct Node; to be inside the Graph definition. Then it would be a forward declaration of Graph::Node.
Finally, Graph:: is required in Graph::Node * Graph::findByName(string name) because the compiler reads from left to right, so if it sees Node * then it doesn't know what you are talking about yet. This problem can be avoided by using C++11 return type syntax:
auto Graph::findByName(string name) -> Node *
where the names in the -> part are looked up in the Graph scope, since the compiler has already seen that we are implementing a Graph member function.
Don't use typedef struct node { … } Node in C++. That's C.
Node is a structure inside Graph so you need to forward-declare it there, not outside it:
class Graph {
private:
struct Node;
struct Edge {
…
};
struct Node {
…
};
};
I have the following code:
class Node;
class Edge {
public:
//Edge(Node originnode,Node targetnode,int weight):OriginNode(originnode),TargetNode(targetnode),Weight(weight){};
//~Edge(){};
//Node getOriginNode() const { return OriginNode;};
//Node getTargetNode() const { return TargetNode;};
int getWeight() const { return Weight;};
Node OriginNode;
Node TargetNode;
int Weight;
};
class Node{
public:
std::string getName();
std::vector<Edge> getEdges();
};
when I am trying to compile the compiler claims that OriginNode and TargetNode have incomplete type. I have already forward declare the Node. How can I fix that?
You can't without providing a full definition of Node. You can alternatively declare pointers as members: Node* OriginNode.
I'd suggest you re-think your design though - does an Edge really have a Node. As in - does it have ownership over it? Can't a Node be shared between multiple edges? Also, Does a Node really contain multiple edges?
With boost::container you can change the order of the declarations because it support containers of incomplete types :
class Edge;
class Node{
public:
std::string getName();
boost::container::vector<Edge> getEdges();
};
class Edge {
public:
//Edge(Node originnode,Node targetnode,int weight):OriginNode(originnode),TargetNode(targetnode),Weight(weight){};
//~Edge(){};
//Node getOriginNode() const { return OriginNode;};
//Node getTargetNode() const { return TargetNode;};
int getWeight() const { return Weight;};
Node OriginNode;
Node TargetNode;
int Weight;
};
By the way, why do you want to return a value of the Edge vector when you get them from the Node and why do you store the value of the OriginNode and TargetNode inside the edge, you can use references or pointers instead (maybe I'm wrong, I don't know all your requirements).
You should reverse the order of declarations
class Edge;
class Node{
public:
std::string getName();
std::vector<Edge> getEdges();
};
class Edge {
public:
//Edge(Node originnode,Node targetnode,int weight):OriginNode(originnode),TargetNode(targetnode),Weight(weight){};
//~Edge(){};
//Node getOriginNode() const { return OriginNode;};
//Node getTargetNode() const { return TargetNode;};
int getWeight() const { return Weight;};
Node OriginNode;
Node TargetNode;
int Weight;
};
Nevertheless I consider that design of classes as very bad. Node is a primitive entity that should not contain a vector of Edge. Why should Node control the container?! The container is a more high -level generalization than Node. So it should be placed in a more high level compared with Node.
I have the following in an implementation file...
void ClientList::interestCompare(vector<string> intr)
{
for(int index = 0; index < intr.size(); index++)
{
this->interests[index];
}
}
and this in the specification file...
class ClientList
{
private:
// A structure for the list
struct ListNode
{
char gender;
string name;
string phone;
int numInterests; // The number of interests for the client
vector<string> interests; // list of interests
string match;
struct ListNode *next; // To point to the next node
};
//more stuff
...}
is it possible to use the "this" pointer to access the "interests" vector in the struct?
If so how.
As I have it now, I initialize a ListNode pointer to head in order to access the list. I'm just wondering if the "this" pointer can only access members of the class, or if they can access deeper ADT variables embedded in the class.
Does that question even make sense?
You only declared a ListNode type inside ClientList class which doesn't mean you have a instance of ClientList. As you hare using std::vector already, you could use std::vector or std::list instead of implementing another list
class ClientList
{
private:
// A structure for the list
struct Client
{
char gender;
std::string name;
std::string phone;
int numInterests; // The number of interests for the client
std::vector<string> interests; // list of interests
std::string match;
};
std::vector<Client> clients;
//more stuff
};
Edit:
If you want to compare two lists, use std::set_intersection, it requires two containers to be sorted in place.
void ClientList::FindClientHasCommonInterest(const vector<string>& intr)
{
for(auto client = clients.begin(); client != clients.end(); ++client)
{
std::vector<std::string> intereste_in_common;
std::set_intersection((*client).begin(), (*client).end(),
intr.begin(), intr.end(),
std::back_inserter(intereste_in_common));
if (intereste_in_common.size() >= 3)
{
// find one client
}
}
}
No, it's different between Java and C++ for nested class. C++ nested class is essentially the same as static nested class in Java. So, you have to use an instance of the nested struct to access its member.
I compiled the following cords with g++
#include <iostream>
#include <string>
using namespace std;
template<class T>
class Node<const char*>{
private:
string x_;
Node* next_;
public:
Node (const char* k, Node* next):next_(next),x_(k){}
string data(){return x_;}
Node *get_next(){return next_;}
};
$ g++ -c node01.cc
node01.cc:5: error: ‘Node’ is not a template
What's wrong?
I'm begginer for c++
You're mixing up declarations and instantiations. When you declare a template, you don't specify a type immediately after its name. Instead, declare it like this:
template<class T>
class Node {
private:
const T x_;
Node *next_;
public:
Node (const T& k, Node *next) : x_(k), next_(next) { }
const T& data(){return x_;}
Node *get_next(){return next_;}
};
Your original declaration also confuses string, const char *, and generic types that should be in terms of T. For a template like this, you probably want to let the user define the type of the member (x_). If you explicitly declare it as const char * or string, you're losing genericity by limiting what the user can use for T.
Notice that I changed the types of the instance variables, the parameters of the constructor and the return type of data() to be in terms of T, too.
When you actually instantiate a variable of the template type, you can provide a concrete type parameter, e.g.:
int main(int argc, const char **argv) {
Node<char*> *tail = new Node<char*>("tail", NULL);
Node<char*> *node = new Node<char*>("node", tail);
// do stuff to mynode and mytail
}
Whenever you write the template name Node outside the template declaration, it's not complete until you provide a value for the parameter T. If you just say Node, the compiler won't know what kind of node you wanted.
The above is a little verbose, so you might also simplify it with a typedef when you actually use it:
typedef Node<char*> StringNode;
int main(int argc, const char **argv) {
StringNode *tail = new StringNode("tail", NULL);
StringNode *node = new StringNode("node", tail);
// do stuff to mynode and mytail
}
Now you've built a linked list of two nodes. You can print out all the values in the list with something like this:
for (StringNode *n = node; n; n = n->get_next()) {
cout << n->data() << endl;
}
If all goes well, this will print out:
node
tail
Your class declaration should look like this:
template<class T>
class Node{
private:
T x_;
Node* next_;
public:
Node (const T& k, Node* next):next_(next),x_(k){}
T data(){return x_;}
Node *get_next(){return next_;}
};
Notice how I removed all references to string or const char * and replaced them with the generic type T. Your class, since it is templated, should not refer to any specific type but should do everything in terms of the generic T type.
The const char * is specified later when you declare a Node variable. Or it could be any other type, not just const char *. The point is, when you're declaring the Node class you just use the generic type T in the code without reference to any specific type. You specify a specific type only when you actually use a Node.
Node<const char *> stringNode("foo", NULL);
Node<int> intNode(5, NULL);
This has allowed us to have a single definition of the Node class but be able to use it to create both nodes where the data is a string and nodes where the data is an integer. Hooray templating!