linked list operator overloading issue - c++

i tried to build up my own linked list class and got a problem with the = operator overloading. as far as i know, we should use const parameter when overloading the assignment operator, say using linked_list<T>& operator=( const linked_list<T>& a). however, the complier gave me errors unless i put linked_list<T>& a instead. the complier would stop at
if(this->head==a.front()), giving me Error
11 error C2662: 'linked_list<T>::front' : cannot convert 'this' pointer from 'const linked_list<T>' to 'linked_list<T> &'
below are the details.
#ifndef _LINKED_LIST_H_
#define _LINKED_LIST_H_
template <class T>
struct node
{
T data;
node<T>* next;
};
template <class T>
class linked_list
{
private:
node<T>* head;
public:
linked_list<T>();
linked_list<T>(const linked_list<T>& a);
~linked_list<T>();
linked_list<T>& operator=(const linked_list<T>& a);
bool isEmpty();
int size() const;
void insert_front(T a);
void insert_end(T a);
void erase_end();
void erase_front();
void print() const;
void erase(node<T>* a);
node<T>*& front()
{
node<T>* ptr = new node<T>;
ptr = head;
return ptr;
}
void setFront(node<T>* a);
};
#endif
template <class T>
linked_list<T>& linked_list<T>::operator=(const linked_list<T>& a)
{
if (this->head == a.front()) // the error mentioned happened here. however,
// if no const in the parameter, it would be
// no error
{
return *this;
}
while (head != nullptr) erase_front();
node<T>* copy;
copy = a.front();
while (copy->next != nullptr)
{
insert_end(copy->data);
copy = copy->next;
}
return *this;
}
anybody can help? thanks.

When an accessor returns a reference to an owned structure, it's usually a good idea to implement two versions: One which is non-const and returns a non-const reference, and one which is const and returns a const reference. That way it can be used in both mutating and non-mutating contexts. front() would be a good candidate for this.
Though a side note -- you probably don't want to expose your nodes in the public linked_list interface, particularly non-const references to them. That's the sort of thing to encapsulate entirely in the class.

The problem is that front() is not a const member function, and you're trying to call it on a const instance.

Related

Operator overload template

I'm trying to implement an operator overload function based on a header file that was given to me, but I'm not understanding one this. Here's what I've been given:
template<class Type>
myClass<Type>& myClass<Type>::operator =(const myClass<Type> &);
My question is in relation to the parameter passed. (const myClass &) indicate a value passed, but how to I reference that value within the function? Normally if I have (const myClass &myValue), I would reference that with myValue=whatever. But I'm not sure how to handle this one.
This is the header file that i'm trying to implement. I'm not asking for anyone to solve this, but I would like some clarifications:
template<class Type>
struct nodeType{
Type value;
nodeType<Type> *next;
nodeType<Type> *prev;
};
template <class Type>
class sortedListADT {
public:
const sortedListADT<Type>& operator=(const sortedListADT<Type> &);
bool isEmpty() const;
bool search(const Type& searchElem) const;
void removeElement(const Type& remElem);
void insertElement(const Type& newElem);
Type front() const;
Type back() const;
void printInOrder() const;
void printRevOrder() const;
void destroyList();
sortedListADT();
sortedListADT(const sortedListADT<Type>& otherList);
~sortedListADT();
private:
nodeType<Type> *first;
nodeType<Type> *last;
int numElements;
void copyList(const sortedListADT<Type>& otherList);
};
how to I reference that value within the function?
We just can't because the parameter is unnamed and for us to use it inside the function it must have a name(to refer to it by that name).
It seems that you're trying to implement the overloaded operator= which you can do as shown below:
template <class Type>
class sortedListADT {
public:
//this is a declaration
const sortedListADT<Type>& operator=(const sortedListADT<Type> &);
//other code as before
};
template<typename Type>
//-----------------------------------------------------------------------------------vvvvvvvvvvvvv--->added a name for the paramter
const sortedListADT<Type>& sortedListADT<Type>::operator=(const sortedListADT<Type> &namedParameer)
{
//add your code here
//don't forget to have a return statement here
}
Working demo

How to enable conversion template argument T to const T?

Suppose that I have a following class
template <typename T>
struct Node { T value; Node* next; };
Often one needs to write code similar to this (let's assume that Sometype is std::string for now, although I don't think that it matters).
Node<SomeType> node = Node{ someValue, someNodePtr };
...
Node <const SomeType> constNode = node; // compile error
One way to work around is to define explicit conversion operator:
template <typename T>
struct Node
{
T value;
Node* next;
operator Node<const T>() const {
return Node<const T>{value, reinterpret_cast<Node<const T>* >(next)};
}
};
Is there a better, "proper" way to do it?
1. In general, what is the proper way to allow conversion of SomeType to SomeType except explicitly defining conversion operator? (Not in my example only).
2. If defining conversion operator is necessary, is reinterpret_cast is the proper way to do it? Or there are "cleaner" ways?
EDIT: Answers and comments were very helpful. I decided to provide more context right now. My problem is not with implementing const_iterator itself (I think that I know how to do it), but how to use same template for iterator and const_iterator. Here is what I mean
template <typename T>
struct iterator
{
iterator(Node<T>* _node) : node{ _node } {}
T& operator*() { return node->value; } // for iterator only
const T& operator*() const { return node->value; } // we need both for iterator
// for const iterator to be usable
iterator& operator++() { node = node->next; return *this; }
iterator operator++(int) { auto result = iterator{ node }; node = node->next; return result; }
bool operator==(const iterator& other) { return node == other.node; }
bool operator!=(const iterator& other) { return Node != other.node; }
private:
Node<T>* node;
};
Implementing const_iterator is essentially the same, except that T& operator*() { return node->value; }.
The initial solution is just to write two wrapper classes, one with T& operator*() and the other one without. Or use inheritance, with iterator deriving from const_iterator (which might be a good solution and has an advantage - we don't need to rewrite comparison operators for iterator and can compare iterator with const_iterator - which most often makes sense - as we check that they both point at same node).
However, I am curious how to write this without inheritance or typing same code twice. Basically, I think that some conditional template generation is needed - to have the method T& operator*() { return node->value; } generated only for iterator and not const_iterator. What is the proper way to do it? If const_iterator treated the Node* as Node*, it almost solves my problem.
Is there a better, "proper" way to do it?
There must be since your solution both has a weird behavior and is also invalid as specified by the C++ standard.
There's a rule called strict aliasing which dictate what kind of pointer type can alias another type. For example, both char* and std::byte* can alias any type, so this code is valid:
struct A {
// ... whatever
};
int main() {
A a{};
std::string b;
char* aptr = static_cast<void*>(&a); // roughtly equivalent to reinterpret
std::byte* bptr = reintepret_cast<std::byte*>(&b); // static cast to void works too
}
But, you cannot make any type alias another:
double a;
int* b = reinterpret_cast<int*>(&a); // NOT ALLOWED, undefined behavior
In the C++ type system, each instantiation of a template type are different, unrelated types. So in your example, Node<int> is a completely, unrelated, different type than Node<int const>.
I also said that your code has a very strange behavior?
Consider this code:
struct A {
int n;
A(int _n) : n(_n) { std::cout << "construct " << n << std::endl; }
A(A const&) { std::cout << "copy " << n << std::endl; }
~A() { std::cout << "destruct " << n << std::endl; }
};
Node<A> node1{A{1}};
Node<A> node2{A{2}};
Node<A> node3{A{3}};
node1.next = &node2;
node2.next = &node3;
Node<A const> node_const = node1;
This will output the following:
construct 1
construct 2
construct 3
copy 1
destruct 1
destruct 3
destruct 2
destruct 1
As you can see, you copy only one data, but not the rest of the nodes.
What can you do?
In the comments you mentionned that you wanted to implement a const iterator. That can be done without changing your data structures:
// inside list's scope
struct list_const_iterator {
auto operator*() -> T const& {
return node->value;
}
auto operator++() -> node_const_iterator& {
node = node->next;
return *this;
}
private:
Node const* node;
};
Since you contain a pointer to constant node, you cannot mutate the value inside of the node. The expression node->value yield a T const&.
Since the nodes are there only to implement List, I will assume they are abstracted away completely and never exposed to the users of the list.
If so, then you never have to convert a node, and operate on pointer to constant inside the implementation of the list and its iterators.
To reuse the same iterator, I would do something like this:
template<typename T>
struct iterator_base {
using reference = T&;
using node_pointer = Node<T>*;
};
template<typename T>
struct const_iterator_base {
using reference = T const&;
using node_pointer = Node<T> const*;
};
template<typename T, bool is_const>
using select_iterator_base = std::conditional_t<is_const, const_iterator_base<T>, iterator_base<T>>;
Then simply make your iterator type parameterized by the boolean:
template<bool is_const>
struct list_basic_iterator : select_iterator_base<is_const> {
auto operator*() -> typename select_iterator_base<is_const>::reference {
return node->value;
}
auto operator++() -> list_basic_iterator& {
node = node->next;
return *this;
}
private:
typename select_iterator_base<is_const>::node_ptr node;
};
using iterator = list_basic_iterator<false>;
using const_iterator = list_basic_iterator<true>;
Maybe you want another class altogether, like this:
template<typename T>
struct NodeView
{
T const& value; // Reference or not (if you can make a copy)
Node<T>* next;
NodeView(Node<T> const& node) :
value(node.value), next(node.next) {
}
};
Demo
If however you are talking about an iterator or a fancy pointer (as you mention in the comments), it's quite easy to do with an additional template parameter and some std::conditional:
template<typename T, bool C = false>
class Iterator {
public:
using Pointer = std::conditional_t<C, T const*, T*>;
using Reference = std::conditional_t<C, T const&, T&>;
Iterator(Pointer element) :
element(element) {
}
Iterator(Iterator<T, false> const& other) :
element(other.element) {
}
auto operator*() -> Reference {
return *element;
}
private:
Pointer element;
friend Iterator<T, !C>;
};
Demo

Overloading operator compile error?

So I'm trying to overload the ^ operator to perform the intersection between my two sets, but I keep getting this compile time error "Invalid operands to binary expression.
intersection = list ^ listTwo; is what causes the error
My methods work fine without overloading.
Here is my header file.
#ifndef SetHeader_h
#define SetHeader_h
template<typename T>
class Node{
public:
T data;
Node<T> *next;
};
template<typename T>
class SetADT{
private:
Node<T> *head;
public:
SetADT();
~SetADT();
void add(T data);
void print();
bool isDuplicate(T data) const;
SetADT<T> operator ^ (SetADT<T> node);
};
#endif /* SetHeader_h */
Here is my cpp file
#include <iostream>
#include "SetHeader.h"
using namespace std;
template <typename T>
SetADT<T> ::SetADT(){
head = NULL;
}
template<typename T>
SetADT<T> :: ~SetADT<T>(){
cout<<"Set deleted!" << endl;
}
template<typename T>
bool SetADT<T>::isDuplicate(T data) const{
Node<T> *cur = this->head;
while (cur) {
if (cur->data == data) {
return true;
}
cur=cur->next;
}
return false;
}
template <typename T>
void SetADT<T>:: add(T data){
Node<T> *node = new Node<T>();
bool isPresent = isDuplicate(data);
if (!isPresent) {
node->data = data;
node->next = this->head;
this->head = node;
}
}
template <typename T>
void SetADT<T>:: print(){
Node<T> *head = this->head;
if (head == NULL) {
cout << "{}";
}
Node<T> *cur = head;
while (cur) {
cout << cur->data << ' ';
cur = cur->next;
}
cout << endl;
}
template <typename T>
SetADT<T> SetADT<T> :: operator &(SetADT<T> one){
SetADT<T> result;
Node<T> *setACurrent = this->head;
while (setACurrent) {
if (one.isDuplicate(setACurrent->data)) {
result.add(setACurrent->data);
}
setACurrent = setACurrent->next;
}
return result;
}
int main (){
SetADT<int> list;
list.add(10);
list.print();
SetADT<int> listTwo;
listTwo.add(10);
list.print();
SetADT<int> intersection;
//error right here
intersection = list ^ listTwo;
return 0;
}
The essence of your problem is that the operator function is defined for the class SetADT<T>, however you are are trying to invoke the ^ operator against pointers (to objects); the compiler does not match your operator function implementation to your usage. Only the bitwise-xor (^) operator is defined and it does not know how to handle SetADT<T> arguments.
In order for the complier to match the invocation with your declaration, you need to dereference the left-hand "argument," list.
intersection = *list ^ listTwo;
I might suggest that you write the operator to accept reference arguments rather than pointers, like so:
SetADT<T>* operator ^ (SetADT<T> &node) { … }
Then you invoke it,
intersection = *list ^ *listTwo;
Of course you can leave the existing declaration/definition in place if there is a reason for it, but it is not nice. You should consider returning a reference to the object rather than a pointer. And, for completeness, you should consider implementing the ^= operator, as well.
SetADT<T>& operator ^ (SetADT<T> &node);
SetADT<T>& operator ^=(const X& rhs);
Then the expression to use for ^ operator could look like,
*intersection = *list ^ *listTwo;
list ^ listTwo;
Both list and listTwo are a SetADT<int> *, a pointer to an instance of this template. Both operands of this ^ operator are pointers.
template<typename T>
class SetADT{
// ...
SetADT<T>* operator ^ (SetADT<T> *node);
Here you defined the ^ operator of a SetADT<T>, and not a SetADT<T> *.
This operator^ declaration ends up overloading an operator on an instance of the class, and not on a pointer to the instance of the class.
That's how operator members work: they overload an operator on an instance of the class, and not on a pointer to an instance of the class.
If you would like to invoke this operator correctly, the right syntax would be:
(*list) ^ listTwo
Here, *list dereferences a pointer to an instance of a class, so you end up with (a reference to) an instance of the class, which has an operator^ overload that takes a pointer to an instance of the same class as a parameter.
Note that your operator overload's parameter is a pointer to an instance of the class, and since listTwo is such a pointer, this should work.
The general mistake you are making is that you are not correctly understanding the fundamental difference between a class and a pointer to an instance of the class. The is not a trivial matter, it's an important distinction. If something is defined to work for an instance of a class, it expects to have an instance of a class to work with, and not a pointer of such a class. And vice-versa.

How to initialize pointers in a linked list to templated class to NULL in constructor implemented in header file [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
Hello I am working on a project for data structures and I am stuck.
The project is to build a templated linked list class and a nested iterator class, inside a headerfile only. I do not understand how to use the iterator class inside of the templated LinkedList class. I am not sure about iterators in general. The methods declared are all needed to run the tests that will be ran. I am currently stuck on initializing 'LinkedList* prev' and next in the constructor. Please help! How do I initialize something that is templated? the compiler wants to know what data type I think? Thanks for your time
The error is on the constructor declaration in the class LinkedList
EDITED "invalid initialization of non-const reference of type 'std::basic_string char&' from an rvalue of type 'int'" is the error message
#ifndef LINKEDLIST_H_
#define LINKEDLIST_H_
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
template <typename T> class LinkedList
{
private:
LinkedList<T>* head;
int size;
T element = NULL;
LinkedList<T>* prev;
LinkedList<T>* next;
public:
class Iterator
{
friend class LinkedList<T>;
private:
public:
Iterator();
T operator*() const;
Iterator& operator++();
bool operator==(Iterator const& rhs);
bool operator!=(Iterator const& rhs);
};
LinkedList<T>():prev(0), next(0){} //HERE is the ERROR????////////
Iterator begin() const
{
// Iterator tempIterator = LinkedList<T>();
//
// return tempIterator->front;
return NULL;
}
Iterator end() const{return NULL;}
bool isEmpty() const;
T getFront() const;
T getBack() const;
void enqueue(T newElement)
{
LinkedList<T>* newElem = new LinkedList<T>();
newElem->element = newElement;
if(front == 0)
{
front = newElem;
}
else
{
back->next = newElem;
}
back = newElem;
listSize++;
}
void dequeue()
{
LinkedList<T>* tempElem = new LinkedList<T>();
if(front == 0){
cout << "List is empty!" << endl;
}
else
{
tempElem = front;
front = front->next;
cout << "the element dequeued: " << tempElem->element;
delete tempElem;
}
}
void pop();
void clear();
bool contains(T element) const;
void remove(T element);
};
#endif /* LINKEDLIST_H_ */
The constructor syntax is wrong.
LinkedList():prev(0), next(0){}
This is the correct constructor syntax. Once the template class and parameters are declared, in the template declaration, the name of the template alone, without the parameters, refers to the template itself, inside its scope. Similarly, if you were to explicitly define a destructor, it would be:
~LinkedList() { /* ... */ }
If you wanted to only declare the constructor inside the template declaration:
LinkedList();
and then define it outside of the template declaration, then the correct syntax would be:
template<typename T>
LinkedList<T>::LinkedList() :prev(0), next(0){}

Just a few simple errors

I am getting a few errors that I don't know about and have spent entirely to much time pulling my hair out. Here is my Header:
#ifndef MYBSTREE_H
#define MYBSTREE_H
#include "abstractbstree.h"
#include "MyBSTreeFunc.h"
using namespace std;
template<typename T>
class TreeNode
{
public:
T m_data;
TreeNode* m_right;
TreeNode* m_left;
};
template<typename T>
class MyBSTree:public AbstractBSTree<T> //LINE 18
{
private:
TreeNode<T>* m_root;
public:
void MyBSTree();
int size() const;
bool isEmpty() const;
int height() const;
const T& findMax() const;
const T& findMin() const;
int contains(const T& x) const;
void clear();
void insert(const T& x);
void remove(const T& x);
void printPreOrder() const;
void printPostOrder() const;
void print() const;
};
#endif
And my implementation file:
Line 1-6
void MyBSTree()
{
m_root -> m_data = NULL;
m_root -> m_right = NULL;
m_root -> m_left = NULL;
}
Line 13-21
template<typename T>
bool MyBSTree<T>::isEmpty() const
{
if (m_root== NULL)
return true;
else
return false;
}
Line 28-35
template < typename T >
const T& MyBSTree<T>::findMax() const
{
TreeNode* p = m_root;
while(p -> m_right != NULL)
p = p -> m_right;
return p;
}
The error for line 3 in the implementation says 'm_root' was not declared in this scope. But it's cool with lines 4 and 5. I'm guessing because m_data isn't a pointer? I don't know.
Next, Line 14, and 21, and quite a few others say that it expected an initializer before the '<' token. I assume they are all the same issue so I only put a few here.
Finally, it says for line 18 in the header: "template struct MyBSTree redeclared as a different kind of symbol." It then says Line 1 of my implementation is a previous declaration of 'void MyBSTree". I am assuming those go together.
Thanks for all the help.
You need to fix your constructor declaration:
template < typename T >
classMyBSTree
{
... // some stuff
public:
MyBSTree(); // no return type
... // some stuff
};
You alse need to fix your constructor:
template < typename T >
MyBSTree::MyBSTree() // proper ctor definition
{
m_root -> m_data = T(); // use the initializer for that data type
m_root -> m_right = NULL;
m_root -> m_left = NULL;
}
Lines 1-6: You've define a standalone function in the .cpp named void MyBSTree(). This is not part of the class. It's also bad that you named the function the same as your class. It looks like you want this to be your constructor, in which case you need this (I won't include the template stuff, as it's not the issue):
// in .h
class MyBSTree {
public:
MyBSTree(); // No void
}
// in .cpp
// Uses MyBSTree namespace.
MyBSTree::MyBSTree() { /* initialize your pointers etc */ }
This seems to be your main issue, and may fix the other problems too.
The reason the compiler cannot find m_roots is because your function is not part of the class. You would fix this by putting your function into the class scope with operator :: (e.g. myBSTree::myBSTree(){};)
Template functions cannot be placed in separate files from their class, you need to define all of your template class and function in the same file. Move the implementation of your functions into your header file.