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;
}
Related
I was asked to make a project on the phonebook using BST in c++. So I have made class "BstDetails" which has all the relevant information needed and made another class "PhoneBook" where I implement the insert, deletion, etc functions. "Phonebook" is actually also the friend class of "BstDetails". So in class "PhoneBook", I call the function "create" to make a new entry in the phonebook. I dynamically create object but I am confused about how will I actually assign input data to entries of the object. Can someone guide me?
#include<iostream>
#include<string>
using namespace std;
class BstDetails{
private:
string name;
long number;
BstDetails* left;
BstDetails* right;
friend class PhoneBook;
public:
BstDetails(){
left=NULL;
right=NULL;
}
};
class PhoneBook{
private:
BstDetails* root;
public:
PhoneBook(){
root=NULL;
}
void create(BstDetails name , BstDetails number){
if(root==NULL){
BstDetails* data=new BstDetails();
}
}
};
BstDetails constructor should be passed name and number
public:
BstDetails(const std::string& n, long num) :
left(nullptr),
right(nullptr)
name(n),
number(num)
{
}
Your create method on phonebook takes similar parameters and returns a BstDetails
BstDetails* create(const std::string& name, long number){
return new BstDetails(name, number);
}
So create is just a thin wrapper around new, so you may consider not needing that helper function.
But you could build up a create method such as this the following that creates a node and inserts into the tree
void create(const std::string& name, long number) {
BstDetails* node = new BstDetails(name, number);
BstDetails** ppParent = &root;
BstDetails* parent = *ppParent;
while (parent) {
ppParent = (node->name < parent->name) ? &(parent->left) : &(parent->right);
parent = *ppParent;
}
*ppParent = node;
}
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.
I would like to get some help with my current project as I struggle to understand what exactly went wrong in my program. I believe the problem is with my constructor. When I call member function it behaves as I haven't initialized my class members.
Here is my class:
class BankList {
public:
// constructor
BankList();
BankList(int size);
bool isEmpty() const;
int size() const;
void insertBankEntry(std::string account, std::string level, std::string lName, std::string fName, float value); // add a single entry to the list
void insertBankData(std::string fileName); // populate list data from the file
void deleteBankEntry(std::string key); // delete a single entry
void findBankEntry(std::string key) const; // Find and display one element using key
void checkBankEntry(std::string account);
void printHashBankData() const; // List data in hash table sequence
void printHashKeyBankData() const; // List data in key sequence (sorted)
void printTreeBankData() const; // Print indented tree
void writeBankData(); // Write data to a file
void outputHashStatistic() const; // print hash stats
private:
HashList* hashlist;
Tree* tree;
int count; // number of records
int hashSize;
};
Here are my constructors:
BankList::BankList()
{
HashList* hashlist = new HashList();
Tree* tree = new Tree();
count = 0;
hashSize = 0;
}
BankList::BankList(int size)
{
HashList* hashlist = new HashList(size);
Tree* tree = new Tree();
count = 0;
hashSize = size;
}
The function I am trying to call:
void BankList::insertBankEntry(string account, string level, string lName, string fName, float value) // add a single entry to the list
{
BankCustomer* customer = new BankCustomer(account, level, lName, fName, value);
hashlist->insert(customer);
tree->Insert(customer);
count++;
}
However, it does work if I place this code in my function.
if (!tree || !hashlist)
{
tree = new Tree();
hashlist = new HashList();
}
main:
int size = getSize();
BankList* list = new BankList(size);
list->insertBankEntry("123412341234", "Gold", "Jonhson", "Steve", 1234.45);
Thanks in advance!
In the constructors you are hiding the member variables (by declaring variables with the same name as the members) hence your member variables remain un-initialized
HashList* hashlist = new HashList(); // hiding the member variable this->hashlist
Tree* tree = new Tree(); // hiding the member variable this->tree
Just use
hashlist = new HashList();
tree = new Tree();
inside the constructors.
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.