I am trying to make a Linked List Container LLC and overload the << operator as a friend. It seems like no mater what I do it either prints the memory address or throws a segmentation fault. I dont totally understand c++ yet so it is probably something obvious.
in LLC.cpp
ostream& operator<<(ostream& os, const LLC* list){
Node *curr = list.first;
for(curr; curr != NULL; curr= curr -> next){
os << curr -> data << "\n";
}
return os;
}
int main(int argc, char *argv[]){
string arr [] = {"a","b","c","d","e","f"};
LLC* link = new LLC(arr);
cout<<"testing: ";
cout<<(link);
}
in LLC.h
struct Node {
std::string data;
Node *next;
};
class LLC {
private:
Node *first;
Node *last;
public:
int main(int argc, char *argv[]);
LLC(){
first=NULL;
last=NULL;
}
friend std::ostream& operator<<(std::ostream& os, const LLC*);
std::ostream already has an operator<< that takes a pointer (via void*) as input. That is why you get hex output. Your operator<< overload should be taking in the LLC object by const reference, not by const pointer, to avoid ambiguities.
You did not post enough code to demonstrate the segfault error, but I suspect it is because you are not managing your node instances correctly inside the list, so when your operator<< tries to access them, it encounters a bad pointer along the way and crashes.
Try something more like this:
LLC.h
#ifndef LLCH
#define LLCH
#include <iostream>
#include <string>
struct Node {
std::string data;
Node *next;
Node(const std::string& d);
};
class LLC {
private:
Node *first;
Node *last;
public:
LLC();
template<size_t N>
LLC(std::string (&arr)[N])
: first(NULL), last(NULL) {
for(size_t i = 0; i < N; ++i) {
addToBack(arr[i]);
}
}
// other constructors, destructor, etc...
void addToBack(const std::string &s);
// other methods ...
friend std::ostream& operator<<(std::ostream& os, const LLC& list);
// other operators ...
};
#endif
LLC.cpp
#include "LLC.h"
Node::Node(const std::string& d)
: data(d), next(NULL) {
}
LLC::LLC()
: first(NULL), last(NULL) {
}
// other constructors, destructor, etc...
void LLC::addToBack(const std::string &s) {
Node *n = new Node(s);
if (!first) first = n;
if (last) last->next = n;
last = n;
}
// other methods ...
std::ostream& operator<<(std::ostream& os, const LLC& list) {
for(Node *curr = list.first; curr != NULL; curr = curr->next) {
os << curr->data << "\n";
}
return os;
}
// other operators ...
Main.cpp
#include <iostream>
#include <string>
#include "LLC.h"
int main(int argc, char *argv[]) {
std::string arr[] = {"a", "b", "c", "d", "e", "f"};
LLC* link = new LLC(arr);
cout << "testing: " << *link;
delete link;
/* or simply:
LLC link(arr);
cout << "testing: " << link;
*/
return 0;
}
Related
I recently asked the question: Is ostream& operator<< better practice in a class than using std::cout? and got an excellent answer.
When I tried to implement the solution I got errors:
no operator "<<" matches these operands
and
binary '<<': no operator found which takes a right-hand operand of type 'LinkedList' (or there is no acceptable conversion)
The simplest solution in this case would be to add a std::ostream parameter to your display() method, eg:
LinkedList.h
#include <iostream>
#pragma once
class LinkedList
{
struct Node {
int data = 0;
Node* prev = nullptr;
Node* next = nullptr;
};
private:
Node* m_head;
public:
// CONSTRUCTOR
LinkedList();
// DESTRUCTOR
~LinkedList();
void display(std::ostream& out) const;
};
LinkedList.cpp
#include <iostream>
#include "LinkedList.h"
LinkedList::LinkedList() {
m_head = nullptr;
}
void LinkedList::display(std::ostream &out) const {
Node* curr = m_head;
while (curr) {
out << curr->data << " -> ";
curr = curr->next;
}
out << std::endl;
}
std::ostream& operator<<(std::ostream &out, const LinkedList &list) {
list.display(out);
return out;
}
Main.cpp (generates error)
#include <iostream>
#include "LinkedList.h"
int main() {
LinkedList list;
std::cout << list;
}
I got some help with this question but it was swiftly deleted...
Essentially the problem is that std::ostream& operator<<(std::ostream &out, const LinkedList &list) is not correctly advertised.
We need to add friend std::ostream& operator<<(std::ostream& output, const SortedList& list); to the LinkedList.h file within the LinkedList class
LinkedList.h
#include <iostream>
#pragma once
class LinkedList
{
struct Node {
int data = 0;
Node* next = nullptr;
};
private:
Node* m_head;
public:
// CONSTRUCTOR
LinkedList();
// DESTRUCTOR
~LinkedList();
void display(std::ostream& out) const;
friend std::ostream& operator<<(std::ostream& output, const LinkedList& list);
};
I have a linked list using a parent Node class and a child Node class (called Transaction). The linked list class (called Ledger) is using shared pointers to access the Node and Transaction class.
My goal is to use the << operator with a shared pointer of Node, called endPtr (the linked list uses a tail instead of a head, going from last to first), and traverse each Node instance and access the Transaction class variables of that parent Node and print them out.
This is my Node header file:
#pragma once
#include <memory>
#include <string>
#include <vector>
using namespace std;
class Node {
protected:
shared_ptr<Node> prev;
string nodeType;
public:
Node();
Node(shared_ptr<Node>);
shared_ptr<Node> getPrev() const;
void setPrev(shared_ptr<Node>);
string getType();
};
My Transaction header file that inherits from Node:
#pragma once
#include "Node.h"
class Transaction: public Node {
private:
string toName;
string fromName;
int amount;
public:
Transaction();
Transaction(string, string, int);
string getToName() const;
string getFromName() const;
int getAmount() const;
void setToName(string);
void setFromName(string);
void setAmount(int);
shared_ptr<Transaction> getPrev();
void setPrev(shared_ptr<Transaction>);
};
And this is the Ledger header and cpp files:
class Ledger {
private:
string toName;
string fromName;
int amount;
vector<pair<string, int>> ledgerVector;
shared_ptr<Node> endPtr;
int count = 0;
public:
Ledger();
Ledger& operator+=(Transaction);
Ledger& operator-=(shared_ptr<Transaction>);
void Add(Transaction);
friend ostream& operator<<(ostream& os, const Ledger&);
};
cpp:
Ledger& Ledger::operator+=(Transaction newTxn) {
shared_ptr<Transaction> newTransaction = make_shared<Transaction>(newTxn);
shared_ptr<Node> newPointer = make_shared<Node>(newTxn);
if (endPtr != nullptr) {
newPointer->setPrev(endPtr);
endPtr = newPointer;
}
else
endPtr = newPointer;
}
ostream& operator<<(ostream& os, const Ledger& ledger) {
weak_ptr<Node> newNode = ledger.endPtr;
auto node = newNode.lock();
while (node != nullptr) {
if (node->getType() == "TRANSACTION") {
shared_ptr<Transaction> transNode = make_shared<Transaction>(node.get());
string fromName = transNode->getFromName();
cout << fromName << endl;
}
node = node->getPrev();
}
}
Finally, main.cpp:
Transaction t1 = Transaction("Albert", "Bob", 100);
Transaction t2 = Transaction("James", "Alice", 50);
Ledger myLedger;
myLedger += t1;
myLedger += t2;
cout << myLedger;
As you can see in the += operator, that is how I'm adding new transaction nodes, by converting the Transaction into a smart pointer and then creating a Node smart pointer from the same Transaction. At which point, I've assigned it the endPtr of the Ledger class.
This is what the endPtr looks like, as seen through Node instances:
The endPtr has two Node instances, as attempted in the main(), but I have no idea if the content of the Transaction is stored in them as well, nor do I know how to access it.
I understand there is no reason to go about it this way, as it may not be optimal, but any guidance on accessing inherited class variables through a parent object instance while using smart pointers would be greatly appreciated.
Your Ledger's operator+= (and presumably Add()) and operator<< are implemented incorrectly. Try this instead:
class Ledger {
...
public:
...
Ledger& operator+=(const Transaction&);
...
void Add(const Transaction&);
friend ostream& operator<<(ostream& os, const Ledger&);
};
void Ledger::Add(const Transaction &newTxn)
{
auto newPointer = make_shared<Transaction>(newTxn);
newPointer->setPrev(endPtr);
endPtr = newPointer;
}
Ledger& Ledger::operator+=(const Transaction &newTxn) {
Add(newTxn);
return *this;
}
ostream& operator<<(ostream& os, const Ledger& ledger) {
auto node = ledger.endPtr;
while (node != nullptr) {
auto transNode = dynamic_pointer_cast<Transaction>(node);
if (transNode != nullptr) {
os << transNode->getFromName() << endl;
}
node = node->getPrev();
}
return os;
}
Many posts about const iterators (example), but none in the context of loops like:
for (const auto it: container) { ... }
When I started implementing, I was encouraged by the compiler's complaints about missing begin and end, hoping such complaints can guide me to fill in the missing pieces. I was wrong. The following code compiles fine though it surely lacks the equivalent of both operator++ and operator!=:
#include <iostream>
template<class T> class List { public:
const T *head;
const List<T> *tail;
List(const T *h, const List<T> *t):head(h),tail(t){}
const T *operator*() const { return head; } };
template<class T> const List<T> *begin(const List<T> *l) { return l; }
template<class T> const List<T> *end (const List<T> *l) { return nullptr; }
class Person { public: int age; Person(int a):age(a){} };
typedef List<Person> Persons;
int main(int argc, char **argv) {
Person *p1 = new Person(16);
Person *p2 = new Person(27);
Person *p3 = new Person(38);
Persons *persons = new Persons(p1,
new Persons(p2,
new Persons(p3, nullptr)));
for (const auto p: persons) { std::cout << (*p)->age << "\n"; }
return 0; }
How come this code compiles?
You have not defined ++ and !=, but they are perfectly well-defined for your iterator type, const List<T>*, because is a pointer type. However, the default behavior of ++ does not do what you want, which would be to follow the tail pointer.
To imbue your iterator with special knowledge of how ++ should be implemented, you would want to use a separate, custom iterator class, rather than using a pointer.
I also made some other changes to your code:
The List type is made iterable, not List*. That means the begin and end functions are not defined on pointers, but on the List object itself, and we iterate over *persons rather than persons.
In for (const auto p : *persons), p is a Person, not a pointer.
godbolt.org link
#include <iostream>
template<class T> class List { public:
const T *head;
const List<T> *tail;
List(const T *h, const List<T> *t):head(h),tail(t){}
const T *operator*() const { return head; }
class const_iterator {
const List<T>* cur = nullptr;
public:
explicit const_iterator(const List<T>* list) : cur(list) {}
const_iterator& operator++() {
cur = cur->tail;
return *this;
}
bool operator!=(const const_iterator& other) const {
return cur != other.cur;
}
const T& operator*() const {
return *cur->head;
}
};
const_iterator begin() const {
return const_iterator(this);
}
const_iterator end() const {
return const_iterator(nullptr);
}
};
class Person { public: int age; Person(int a):age(a){} };
typedef List<Person> Persons;
int main(int argc, char **argv) {
Person *p1 = new Person(16);
Person *p2 = new Person(27);
Person *p3 = new Person(38);
Persons *persons = new Persons(p1,
new Persons(p2,
new Persons(p3, nullptr)));
for (const auto p: *persons) {
std::cout << p.age << "\n";
}
return 0;
}
I have three classes: Client Database and Node as a nested class in Database.
Data of a Node is a pointer to a Client object, the Client class has it's own overloaded << operator.
I need to have an overloaded << operator that will output all of the linked list's data.
The problem that I encounter is not being able to iterate through all of the list using the << overloaded operator, the best thing that I can do is to output the head node's data using getData member, for some reason Node::Print won't output all of the lists Client *data.
Here is the Database class and two of the mentioned methods << and print().
Databse.h
class Databse
{
private:
class Node //node as nested class
{
public:
Node();
void setNode(Client*&);
Node* nextNode(Node*&);
Client getData();
void print (Node*);
private:
Client* data; //holds pointer to Client object
Node* next; //holds pointer to next node in list
};
Node *head; //holds the head node
int nClients;
public:
Databse();
friend ostream& operator<<(ostream&, const Databse&);
Node* getHead() const;
~Databsey();
};
Databse.cpp relevant methods:
ostream& operator<<(ostream& out, const Databse& obj)
{
out << endl << "The databse holds" << obj.nClients << " clients:" << endl;
out << obj.head->getData();
obj.head->print(obj.getHead());
return out;
}
void Database::Node::print (Node* str)
{
Node* current = str ;
while (current->next)
{
cout << current->data;
current = current->next;
}
}
Thanks.
Another approach.
Keep Database::Node:print() very simple -- print the data on the object only.
Let ostream& operator<<(ostream& out, const Database& obj) take care of iterating over the nodes in the list and print each node.
Here's the updated code.
class Database
{
private:
class Node //node as nested class
{
public:
Node();
void setNode(Client*&);
Node* nextNode(Node*&);
// Need this to allow iteration of the list of nodes
// of a Database object.
Node* nextNode() const
{
return next;
}
Client getData();
// Print the data associated with just one node.
void print(ostream& out) const
{
cout << data;
}
private:
Client* data; //holds pointer to Client object
Node* next; //holds pointer to next node in list
};
Node *head; //holds the head node
int nClients;
public:
Database();
friend ostream& operator<<(ostream&, const Database&);
Node* getHead() const;
~Database();
};
ostream& operator<<(ostream& out, const Database& obj)
{
out << endl << "The databse holds" << obj.nClients << " clients:" << endl;
// Iterate over the nodes of the Database object
// and print each one.
Database::Node* current = obj.head;
for ( ; current != NULL; current = current->nextNode() )
{
current->print(out);
// Printing a whitespace between nodes makes the
// output more readable.
out << " ";
}
return out;
}
Just add the overloaded operator<< as you would with any other class, for instance:
class Databse
{
private:
class Node //node as nested class
{
public:
Node();
void setNode(Client*&);
Node* nextNode(Node*&);
Client getData();
friend ostream& operator<<( ostream&, const Node*& pNode );
private:
Client* data; //holds pointer to Client object
Node* next; //holds pointer to next node in list
};
Node *head; //holds the head node
int nClients;
public:
Databse();
friend ostream& operator<<(ostream&, const Databse&);
friend ostream& operator<<( ostream&, const Node*& pNode );
Node* getHead() const;
~Databsey();
};
And then implement it as follows:
ostream& operator<<( ostream& out, const std::add_lvalue_reference<Databse::Node*>::type pNode )
{
Databse::Node* pCurrNode = pNode;
while( pCurrNode )
{
std::cout << pCurrNode->data;
pCurrNode = pCurrNode->next;
}
return out;
}
fix print that accept ostream
ostream& Database::Node::print (ostream& out, Node* str)
{
Node* current = str ;
while (current) //bugfix
{
out << current->data;
current = current->next;
}
return out
}
and then you can call
ostream& operator<<(ostream& out, const Databse& obj)
{
out << endl << "The databse holds" << obj.nClients << " clients:" << endl;
out << obj.head->getData();
obj.head->print(out,obj.getHead());
return out;
}
I have implemented my own doubly linked list, which has templated nodes. Through this node I have stored my own object (Play) which has get gunctions, and I have created an iterator for my list.
for(DLL<Play>::iterator itr=PlayList.begin(); itr!=PlayList.end(); itr++)
if(offense==*how do I access this*getoTeam()){
Here is my node and iterator code:
template<class T>
class node{
public:
T data;
node *next, *prev;
node(const T& t, node<T> *n = 0, node<T> *p = 0) {data=t; next=n; prev=p;}
node() {next = prev = 0;}
};
template<typename T>
class Iterator{
public:
Iterator(node<T> *np=0) : nodePtr(np) {}
T& operator*() const {return nodePtr->data;}
Iterator<T> &operator++(){
nodePtr = nodePtr->next;
return *this;
}
Iterator<T> operator++(int){
Iterator<T> Temp(nodePtr);
nodePtr = nodePtr->next;
return Temp;
}
bool operator==(Iterator<T> i) { return nodePtr == i.nodePtr; }
bool operator!=(Iterator<T> i) { return nodePtr != i.nodePtr; }
private:
node<T> * nodePtr;
};
I'm at a loss for what I would put inside how do I access this. If you could explain why as well, I'd appreciate it.
Thanks.
And just incase, here is my Play object:
#ifndef PLAY_H_INCLUDED
#define PLAY_H_INCLUDED
#include <string>
class Play
{
private:
int m_quarter;
int m_minutes;
std::string oTeam;
std::string dTeam;
int m_down;
int m_yardToGO;
int m_startLoc;
int playDesc;
std::string wholePlay;
public:
int getQuarter();
int getMinutes();
std::string getoTeam();
std::string getdTeam();
int getDown();
int getYard();
int getStartLoc();
int getPlayDesc();
std::string getwholePlay();
Play(int quarter, int minutes, std::string offense, std::string defense, int dwn, int ytg, int start, int desc, std::string play);
~Play();
Play parse(std::string toParse);
std::string findPlay(std::string playDesc);
};
#endif // PLAY_H_INCLUDED
Assuming itr is of type Iterator<Play>, use offense == (*itr).getoTeam().
*itr calls Iterator<Play>::operator*() returning a Play& on which you can then call getoTeam(). For consistency, you should also implement
T* Iterator::operator->() {return &nodePtr->data;}
This way, you could use the more familiar notation offense == itr->getoTeam()