the "this" pointer in classes accessing vector elements - c++

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.

Related

Using or not using new for creation of a class in another

I have been solving a question, Dijkstra's Algorithm, in C++. I've implemented it using adjacency list.
So I have a class for a node, a class for a minHeap, and a class for the Graph.
class node
{
int vertex,weight;
node *next;
friend class Graph;
friend class minHeap;
public:
node();
node(int,int);
};
node::node(){
vertex=weight=0;
next=0;
}
node::node(int v,int wt){
vertex=v;
weight=wt;
next=0;
}
Do I define the minHeap class this way (without a friend function) and create an object in the getDijkSP() function normally, which allows me to use the object only in that function?
class minHeap
{
node *heap;
int heapSize,capacity,*pos;
public:
minHeap(int);
void addElement(node);
node extractMin();
void minHeapify(int);
void decreaseKey(int,int);
};
minHeap::minHeap(int cap){
heap=new node[capacity=cap];
heapSize=-1;
pos=new int[cap]();
} //eliminating other methods
class Graph
{
node **adjList;
int v;
bool *visited;
public:
Graph(int);
void addEdge(int,int,int);
void removeEdge(int,int);
bool existsEdge(int,int);
void getDijkSP();
};
Graph::Graph(int vertices){
adjList=new node*[v=vertices];
for(int i=0;i<v;i++)
adjList[i]=NULL;
}
void Graph::getDijkSP(){
minHeap hp(v); //here
hp.addElement(node(0,0));
for(int i=1;i<v;i++)
hp.addElement(node(i,INT_MAX));
while(!hp.isempty()){
node temp=hp.extractMin();
cout<<temp.vertex<<" "<<temp.weight<<endl;
for(node *current=adjList[temp.vertex];current;current=current->next)
hp.decreaseKey(current->vertex,current->weight+temp.weight);
}
}
(OR) Do I define the minHeap class with a friend function, so that I can create an object of the minHeap class using the new keyword? (And this helps me define the minHeap object in the scope of the Graph class, so that I can use it in all of its functions for other capabilities as well.)
class minHeap
{
node *heap;
int heapSize,capacity,*pos;
friend class Graph; //say like this
public:
minHeap(int);
void addElement(node);
node extractMin();
void minHeapify(int);
void decreaseKey(int,int);
};
minHeap::minHeap(int cap){
heap=new node[capacity=cap]();
heapSize=-1;
pos=new int[cap]();
}
class Graph
{
node **adjList;
int v;
bool *visited;
minHeap *hp; //and do this
public:
Graph(int);
void addEdge(int,int,int);
void removeEdge(int,int);
bool existsEdge(int,int);
void getDijkSP();
};
Graph::Graph(int vertices){
adjList=new node*[v=vertices];
for(int i=0;i<v;i++)
adjList[i]=NULL;
hp=new minHeap(v); //dynamic allocation
}
void Graph::getDijkSP(){
hp->addElement(node(0,0));
for(int i=1;i<v;i++)
hp->addElement(node(i,INT_MAX));
while(!hp->isempty()){
node temp=hp->extractMin();
cout<<temp.vertex<<" "<<temp.weight<<endl;
for(node *current=adjList[temp.vertex];current;current=current->next)
hp->decreaseKey(current->vertex,current->weight+temp.weight);
}
}
I have read this and a few other articles, but specifically want to know the advantages, disadvantages and the appropriateness of both the methods for such similar kinds of questions.
I've provided the constructors for the classes for better clarity.
Short answer would be NO. I would suggest you to read up on smart pointers and rewrite this whole mess. In C++ there is no real reason to use manual allocation in so simple project as this ever.
Also instead of assigning 0 or NULL to a pointer use nullptr, which is C++ symbol only for null pointers unlike the previous mentioned C values that are actually just a int 0 which may cause some unintentional errors.
Edit in response to your comment:
So I've decided to rewrite your code using actual modern C++ instead of this C code with simple classes. In your whole example there are almost no pointers or dynamic allocations needed. I wasn't absolutely sure who exactly should own the actual nodes so from the example I assumed that the MinHeap should. Also I didn't get the point of MinHeap::pos and Graph::visited from what I could see. I can explain any part of that code in more detail, just ask which.
Here is the code:
class Node {
// Only friend class required if you insist on keeping members of Node private.
// If they aren't meant to change, consider declaring them as public and const.
template <unsigned Size> friend class Graph;
public:
Node(int v, int wt) : vertex(v), weight(wt) {}
private:
// Default values written in here right after declarations
// There is no need for a default constructor. You never call it anyway.
int vertex;
int weight;
Node* next = nullptr;
};
// Template parameter because of internal use of std::array.
// If the capacity shouldn't be constant, use std::vector and remove template.
template <unsigned Capacity>
class MinHeap {
public:
// No constructor needed
// ---------------------
// One small tip: write parameter names in function declarations
// even if they aren't needed there for better readability of your code.
void addElement(Node n) { /* impl */ }
Node extractMin() { /* impl */ }
unsigned capacity() { return Capacity; }
bool isEmpty() { return heap.isEmpty(); }
private:
// Default values written in here right after declarations
int heapSize = -1;
std::array<Node, Capacity> heap;
};
// Template parameter because of internal use of std::array.
// If the vertex count shouldn't be constant, use std::vector and remove template.
template <unsigned Vertices>
class Graph {
public:
// No constructor needed
// ---------------------
void getDjikSP() {
hp.addElement({0, 0});
for (unsigned i = 1; i < hp.capacity(); ++i)
hp.addElement({0, INT_MAX});
while (!hp.isEmpty()) {
Node tmp = hp.extractMin();
std::cout << tmp.vertex << " " << tmp.weight << std::endl;
for (Node* current = adjList[tmp.vertex]; current != nullptr; current = current->next)
hp.decreaseKey(current->vertex, current->weight + tmp.weight);
}
}
private:
// Default values written in here right after declarations
std::array<Node*, Vertices> adjList;
MinHeap<Vertices> hp;
};
There is still a lot of space for improvements of this code, for example the MinHeaP::extractMin should maybe return Node&& if it is removed from the heap or const Node& if it should return a reference to the top, etc. To address all the problems and inefficiencies this can still have I would need to see the full code with all functions.

How can I make a tree with n number of child nodes?

Usually they have only two, but I need to make an object were there are a random number of pointers.
To represent this image enter image description here
Using what I know I made this:
struct tree{
string name;
list<struct pointer> pointers,
tree(int x){
name= x;
pnext=null;
}
} root1;
struct pointer{
struct tree *pnext;
};
A tree or object with a list of pointers and the structure for the pointers, but I doesn´t seem right.
How can I make a tree with a random number of pointers?
(I should say what is wrong with but I don´t een know were to start, sorry)
try this:
#include <vector>
struct person {
string name;
vector<person> children;
person(string iName, vector<person> iChildren) {
name = iName;
children = iChildren;
}
}
This way, each person has a name, and a vector with all of it's children in it.

From Vector to Linked List C++

I am pretty new with C++ and I wanted to make sure that I have set up my linked list currently. The information was stored in a vector before, but I was assigned to change it to a linked list. The information stored is CandidateInfo, here is the original code. Have I set my list up correctly?
struct CandidateInfo {
std::string name;
int votesInThisState;
int delegatesWonInThisState; };
std::vector<CandidateInfo> stateCandidates;
And here is my attempet. Suggestions welcomed.
template <typename StatePrimary>
struct CandidateInfo
{
std::string name;
int votesInThisState;
int delegatesWonInThisState;
StatePrimary state;
CandidateInfo<StatePrimary>* next;
CandidateInfo()
{
next = 0;
}
CandidateInfo
(const StatePrimary& c,
CandidateInfo<StatePrimary>* nxt =0)
: state(c), next(nxt)
{}
};
template <typename StatePrimary>
struct CandidateInfoHeader
{
CandidateInfo<StatePrimary>* first;
CandidateInfoHeader();
};
I would have put this as a comment, but I don't have enough reputation yet. Is there a reason you're not using a std::list? That way you could use the code in the first snippet you posted, i.e.:
struct CandidateInfo {
std::string name;
int votesInThisState;
int delegatesWonInThisState; };
std::list<CandidateInfo> stateCandidates;
(Note the change from vector to list in the last line)
std::list is an STL implementation of a doubly linked list.

Add "this" to a vector on class instantiation in C++

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.

Accessing another classes member

I have the following
class book
{
friend class linkedList;
private:
class student
{
friend class book;
string name;
string number;
string gpa;
student *left;
student *right;
student(string name1, string number1, string gpa1,
student *left1 = NULL, student *right1 = NULL)
{
name = name1;
number = number1;
gpa = gpa1;
left = left1;
right = right1;
}
};
int count;
student *root;
ofstream recordBook;
void _add(student *&, string, string, string);
void _display_book(student *);
bool _search_for_name(string, string&, string&);
bool _edit_entry(string &name, string &edited_number);
void _del_person(student *&, string);
void _save(student *root);
void _del_Tree(student *);
public:
student *currentRoot;
book(void); //Constructor
~book(void);//Destructor
void add(string entry_name, string telephone_number, string gpa);
void display_book();
bool search_for_name(string find_name);
bool edit_entry(string entered_name, string edited_number);
void del_person(string entry_name);
void save();
void load_data();
};
class linkedList
{
friend class book;
int someInt;
struct node
{
public:
string key;
node *link;
node *link2;
} *pointer;
public:
student book::*currentRoot = &book::currentRoot;
linkedList();
~linkedList();
void append(string &str);
void del(string &str);
void display();
};
And I need to make a pointer to "student *currentRoot" from my linkedList classes function.
void linkedList::append(string &str)
{
node *q, *t;
if(pointer == NULL)
{
pointer = new node;
pointer->key = str;
pointer->link = NULL;
pointer->link2 = currentRoot;
someInt += 1;
}
else
{
q = pointer;
while(q->link != NULL)
{
q = q->link;
}
t = new node;
t->key = str;
t->link = NULL;
q->link = t;
someInt += 1;
}
}
In linkedList::append I need to make link2 point to where currentRoot is pointing to. How can I do this? (currentRoot is already set to point at a node in a binary tree. Just gotta get my hash table to also point there.) Thanks for any help.
In comments you said:
In the simplest terms I can think of... I am trying to get a pointer in one class to point to another pointer in a different class.
To answer that question: an inner class has no special relationship to the outer class. For example, a student instance within the book class has no direct way to access its “containing” class.
To do this you would have to pass a pointer to the containing book class into student’s constructor and store it in an instance variable within student.
However, this has a big caveat: when the student instance holds a pointer to the containing book class, that pointer could become invalid. For example, if you are storing book instances in a container like a std::vector, the vector may reallocate memory, invalidating any pointers to books held within the vector.
If you can guarantee that the book will not be stored in an STL container (or anywhere else where it can get moved) then this approach can work.
I would still reconsider the overall approach as having instances store pointers in this way seems fragile. There could be a composition-based approach that would work.
The use of friend is suspect.
Typical object-oriented programming dictates that a linked list container class should only deal with pointers to class objects, and should not know about or deal with anything within the class objects themselves.
If the contained class does need to expose information about itself (i.e., any of its members), it should provide public accessor functions for doing so.
I agree with what others commented about code, so I won't repeat it and just point to invalid syntax in your code:
public:
student book::*currentRoot = &book::currentRoot;
1) the pointer to member is not what you wanted, it should have been:
public:
book::student* book::*currentRoot;
2) you cannot assign to non-static member in class definition. It's only allowed for static members of integral type. But you can assign to it somewhere where you have an object:
void foo()
{
linkedList l;
l.currentRoot = &book::currentRoot;
}