Error using template for overloaded operator= - c++

I'm trying to write an overloaded assignment operator for my linked list class using a template but I keep getting errors.
Any help with what I'm doing wrong would be great.
The error I'm getting is "out of line definition does not match any declaration in LL".
The declaration I have is:
const LL<T>& operator=(const LL<T> &rhsObj);
and the implementation is:
template<typename T>
LL<T>& LL<T>::operator=(const LL<T>& rhsObj) const
{
if (this!= &rhsObj)
{
//no self assignment so OK to continue
//deallocate left hand side memory
this->clear();
count = 0;
head = NULL;
cout <<"calling function copyList()" << endl;
count = 0;
head = NULL;
string diCode = "";
int onNode = 0;
if(rhsObj.head == NULL)
{
cout <<"other list is empty, nothing to do" << endl;
}
else
{
onNode =0;
Node<T> *otherCurrent = rhsObj.head;
while( otherCurrent != NULL)
{
int duplicateInfo;
duplicateInfo = otherCurrent->info;
push_back(duplicateInfo);
otherCurrent = otherCurrent ->next;
onNode++;
} //END while(otherCurrent != NULL)
} // END else block of if (otherLL.head == NULL)
} // END if (this != &rhsObj)
return *this;
}

In the updated code, the error is because your declaration is:
const LL<T>& operator=(const LL<T> &rhsObj);
but the attempted implementation is:
LL<T>& LL<T>::operator=(const LL<T>& rhsObj) const
The location of const is actually significant. The first one means that the function returns a reference which is const; the second one means you may not modify *this within the function.
A trailing const is part of the function signature, so the compiler does not consider your implementation to correspond to the function that was declared initially. So it looks like you're trying to add a new function that wasn't declared in the class definition, which isn't permitted.
To fix this, make the implementation match the declaration (move the const from the end to the start).

Related

operator == overload for double linked list

I have realized Double Linked List. And now i need to overload == operator.
dll.cpp:67:17: error: expected expression
if ([ind] != sp[ind]) {
The problem i don't understand how to overload == operator if only one parameter is given. I mean if i write bool operator ==(DLL sp1, DLL sp2){} compiler says error: overloaded 'operator==' must be a binary operator (has 3 parameters)
#include<iostream>
#include<string>
using namespace std;
template<typename T>
class DLL {
public:
DLL(){
size = 0;
head = nullptr;
tail = nullptr;
}
T operator [](int ind) {
int counter = 0;
T res = T();
Node *cur = this->head;
while(cur != nullptr) {
if(counter == ind) {
res = cur->data;
}
cur = cur->next;
counter++;
}
return res;
}
bool operator ==(DLL<int> sp){
bool isequal = true;
for(int ind = 0; ind < sp.length(); ind++){
if ([ind] != sp[ind]) {
isequal = false;
}
}
return isequal;
}
void clear() {
while(size != 1)
pop_front();
delete tail;
size--;
}
int length() {return size;}
}
private:
class Node{
public:
T data;
Node *next;
Node *prev;
Node(T data = T(), Node *prev= nullptr, Node *next = nullptr) {
this->data = data;
this->next = next;
this->prev = prev;
}
};
int size;
Node *head;
Node *tail;
};
The way you have it defined as a member function (and it only takes list of int for some reason (you should probably remove the <int>).
bool operator ==(DLL<int> sp); // There is a small issue in that you
// passing by value and thus causing a copy.
// Another issue with this is that it should
// probably marked "const" to indicate state
// is not changed by the call.
When the compiler see's this.
list1 == list2
This is simply syntactic sugar for:
list1.operator==(list2);
Thus is why you only need one parameter when you declare it as a member function. The alternative is to declare it as a friend function.
friend bool operator ==(DLL<T> const& lhs, DLL<T> const& rhs);
In this case it is a free standing function. When the compiler sees:
list1 == list2
This is syntactic sugar for:
operator==(list1, list2)
The problem was that you were defining a member function with two parameters. The left hand side is the class object and then you were expecting two objects on the right hand side (but the == operator only has one place on the right). That is why it is complaining about three parameters.
So the real question is should it be a member or a friend.
It does not matter here.
There are situations where it "can".
Example: If your class contains a single argument constructor (lets say you could create a list from an integer) and you use a member operator==()
DLL<int> list;
if (list == 5) {
}
This will now compile. Because your member operator uses a parameter and the compiler can convert an integer into the DLL parameter using a single argument constructor.
The counter argument to this is that normally you don't want automatic conversions of your type so you should mark single argument constructors as explicit to prevent this.
So:
If you class can automatically be created via a one argument constructor (most cases this is not true but it can be).
Then you should prefer a friend function version.
otherwise it does not matter and I would probably fall towards the member function.
You're doing the right thing for the most part.
The problem that is causing this error:
dll.cpp:67:17: error: expected expression if ([ind] != sp[ind]) {
is that you actually want to do this instead:
*this[ind] != sp[ind]
Also, there appears to be an extra } right here:
int length() {return size;}
} // <- not exactly sure what that's about, but I don't think you need it.
A comparison operator is a binary operator that treats both the operands equally, it is advisable to make it a friend function and not a member.
So the declaration for the function would change to
friend bool operator ==(const DLL<int> & lhs, const DLL<int> & rhs);
You can choose to define it inside or outside the class.
Read here on when you need to make an operator member vs non-member.

Generic Single Linked List using std::unique_ptr, unknown uncompilation errors in Microsoft Visual Studio C++

I am very new to Microsoft visual studio C++ as well as std::unique_ptr. On CodeReview I was recommended to rewrite using std::unique_ptr. You can find the question I am referencing here.
Here are the following errors I am receiving:
1>main.cpp
1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(26): error C2760: syntax error: unexpected token 'identifier', expected ';'
1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(61): note: see reference to class template instantiation 'SingleLinkedList<T>' being compiled
1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(65): error C2760: syntax error: unexpected token 'identifier', expected ';'
1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(104): error C2760: syntax error: unexpected token 'identifier', expected ';'
1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(104): error C7510: 'make_unique': use of dependent type name must be prefixed with 'typename'
1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(120): error C2760: syntax error: unexpected token 'identifier', expected ';'
1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(120): error C7510: 'make_unique': use of dependent type name must be prefixed with 'typename'
1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(136): error C2760: syntax error: unexpected token 'identifier', expected ';'
1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(136): error C7510: 'make_unique': use of dependent type name must be prefixed with 'typename'
1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(145): error C2760: syntax error: unexpected token 'identifier', expected ';'
1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(145): error C7510: 'make_unique': use of dependent type name must be prefixed with 'typename'
1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(152): error C2760: syntax error: unexpected token 'identifier', expected ';'
1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(152): error C7510: 'make_unique': use of dependent type name must be prefixed with 'typename'
1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(164): error C2760: syntax error: unexpected token 'identifier', expected ';'
1>c:\dev\linkedlist\linkedlist\singlelinkedlist.h(164): error C7510: 'make_unique': use of dependent type name must be prefixed with 'typename'
1>Done building project "LinkedList.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Here is the header file:
#ifndef SingleLinkedList_h
#define SingleLinkedList_h
#include <iostream>
template <class T>
class SingleLinkedList {
private:
struct Node {
T data;
std::unique_ptr<Node> next = nullptr;
Node(T x) : data(x), next(nullptr) {}
};
std::unique_ptr<Node> head = nullptr;
std::unique_ptr<Node> tail = nullptr;
// This function is for the overloaded operator <<
void display(std::ostream &str) const {
for (std::make_unique<Node> loop = head; loop != nullptr; loop = loop->next) {
str << loop->data << "\t";
}
str << "\n";
}
public:
// Constructors
SingleLinkedList() = default; // empty constructor
SingleLinkedList(SingleLinkedList const &source); // copy constructor
// Rule of 5
SingleLinkedList(SingleLinkedList &&move) noexcept; // move constructor
SingleLinkedList& operator=(SingleLinkedList &&move) noexcept; // move assignment operator
~SingleLinkedList();
// Overload operators
SingleLinkedList& operator=(SingleLinkedList const &rhs);
friend std::ostream& operator<<(std::ostream &str, SingleLinkedList &data) {
data.display(str);
return str;
}
// Memeber functions
void swap(SingleLinkedList &other) noexcept;
void push(const T &theData);
void push(T &&theData);
void display() const;
void insertHead(const T &theData);
void insertTail(const T &theData);
void insertPosition(int pos, const T &theData);
void deleteHead();
void deleteTail();
void deletePosition(int pos);
bool search(const T &x);
};
template <class T>
SingleLinkedList<T>::SingleLinkedList(SingleLinkedList<T> const &source) {
for(std::make_unique<Node> loop = source->head; loop != nullptr; loop = loop->next) {
push(loop->data);
}
}
template <class T>
SingleLinkedList<T>::SingleLinkedList(SingleLinkedList<T>&& move) noexcept {
move.swap(*this);
}
template <class T>
SingleLinkedList<T>& SingleLinkedList<T>::operator=(SingleLinkedList<T> &&move) noexcept {
move.swap(*this);
return *this;
}
template <class T>
SingleLinkedList<T>::~SingleLinkedList() {
while (head != nullptr) {
deleteHead();
}
}
template <class T>
SingleLinkedList<T>& SingleLinkedList<T>::operator=(SingleLinkedList const &rhs) {
SingleLinkedList copy{ rhs };
swap(copy);
return *this;
}
template <class T>
void SingleLinkedList<T>::swap(SingleLinkedList &other) noexcept {
using std::swap;
swap(head, other.head);
swap(tail, other.tail);
}
template <class T>
void SingleLinkedList<T>::push(const T &theData) {
std::make_unique<Node> newNode = Node(theData);
if (head == nullptr) {
head = newNode;
tail = newNode;
newNode = nullptr;
}
else {
tail->next = newNode;
tail = newNode;
}
}
template <class T>
void SingleLinkedList<T>::push(T &&theData) {
std::make_unique<Node> newNode = Node(std::move(theData));
if (head == nullptr) {
head = newNode;
tail = newNode;
newNode = nullptr;
}
else {
tail->next = newNode;
tail = newNode;
}
}
template <class T>
void SingleLinkedList<T>::display() const {
std::make_unique<Node> newNode = head;
while (newNode != nullptr) {
std::cout << newNode->data << "\t";
newNode = newNode->next;
}
}
template <class T>
void SingleLinkedList<T>::insertHead(const T &theData) {
std::make_unique<Node> newNode = Node(theData);
newNode->next = head;
head = newNode;
}
template <class T>
void SingleLinkedList<T>::insertTail(const T &theData) {
std::make_unique<Node> newNode = Node(theData);
tail->next = newNode;
tail = newNode;
}
template <class T>
void SingleLinkedList<T>::insertPosition(int pos, const T &theData) {
}
template <class T>
void SingleLinkedList<T>::deleteHead() {
std::make_unique<Node> old = head;
head = head->next;
delete old;
}
template <class T>
void SingleLinkedList<T>::deleteTail() {
}
template <class T>
void SingleLinkedList<T>::deletePosition(int pos) {
}
template <class T>
bool SingleLinkedList<T>::search(const T &x) {
}
#endif /* SingleLinkedList_h*/
Here is the main.cpp file:
#include <algorithm>
#include <cassert>
#include <iostream>
#include <ostream>
#include <iosfwd>
#include "SingleLinkedList.h"
int main(int argc, const char * argv[]) {
///////////////////////////////////////////////////////////////////////
///////////////////////////// Single Linked List //////////////////////
///////////////////////////////////////////////////////////////////////
SingleLinkedList<int> obj;
obj.push(2);
obj.push(4);
obj.push(6);
obj.push(8);
obj.push(10);
std::cout<<"\n--------------------------------------------------\n";
std::cout<<"---------------displaying all nodes---------------";
std::cout<<"\n--------------------------------------------------\n";
std::cout << obj << std::endl;
//
// std::cout<<"\n--------------------------------------------------\n";
// std::cout<<"-----------------Inserting At End-----------------";
// std::cout<<"\n--------------------------------------------------\n";
// obj.insertTail(20);
// std::cout << obj << std::endl;
//
// std::cout<<"\n--------------------------------------------------\n";
// std::cout<<"----------------Inserting At Start----------------";
// std::cout<<"\n--------------------------------------------------\n";
// obj.insertHead(50);
// std::cout << obj << std::endl;
//
// std::cout<<"\n--------------------------------------------------\n";
// std::cout<<"-------------Inserting At Particular--------------";
// std::cout<<"\n--------------------------------------------------\n";
// obj.insertPosition(5,60);
// std::cout << obj << std::endl;
//
// std::cout<<"\n--------------------------------------------------\n";
// std::cout<<"----------------Deleting At Start-----------------";
// std::cout<<"\n--------------------------------------------------\n";
// obj.deleteHead();
// std::cout << obj << std::endl;
//
// std::cout<<"\n--------------------------------------------------\n";
// std::cout<<"----------------Deleting At End-----------------";
// std::cout<<"\n--------------------------------------------------\n";
// obj.deleteTail();
// std::cout << obj << std::endl;
//
//
// std::cout<<"\n--------------------------------------------------\n";
// std::cout<<"--------------Deleting At Particular--------------";
// std::cout<<"\n--------------------------------------------------\n";
// obj.deletePosition(4);
// std::cout << obj << std::endl;
// std::cout << std::endl;
//
// obj.search(8) ? printf("Yes"):printf("No");
std::cin.get();
}
I assume most of the errors are syntax errors or that I just made very careless mistakes. Thanks.
The bulk of your syntax errors are derivatives of the same mistake, so lets look at the first one. It's extra-instructive because it points out TWO mistakes. Any time you can kill two stones with one bird, I say go for it. It's damn hard to kill a stone at the best of times.
void display(std::ostream &str) const {
for (std::make_unique<Node> loop = head; loop != nullptr; loop = loop->next) {
str << loop->data << "\t";
}
str << "\n";
}
In std::make_unique<Node> loop = head, std::make_uniqueis a function that gives you a std::unique_ptr. It is not a type you can use to declare a variable. This mistake is repeated several times through the code and cleaning up all of them will reveal a bunch of new errors. Yay fun.
Step one, let's replace the function with the correct type.
void display(std::ostream &str) const {
for (std::unique_ptr<Node> loop = head; loop != nullptr; loop = loop->next) {
str << loop->data << "\t";
}
str << "\n";
}
Groovy. Simple. Unfortunately it doesn't work. std::unique_ptr<Node> loop = head means you now have two unique_ptrs to the same object. That doesn't sound particularly unique and the compiler won't allow it. You'll probably get some arcane error message about a deleted function. That's because unique_ptr's copy constructor and = operator have been banished to the dark dimension to make it harder to accidentally wind up with multiple unique_ptrs.
A quick note on why all this matters: Ownership. One of the biggest problems with pointers is deciding who deletes what and when. To sort this out you establish ownership of a pointer. Perhaps the pointer is to an Automatic variable and the stack or whatever's being used to manage Automatic data will take care of it. You delete NOTHING! Muhuhahahaha! Maybe someone newed the variable. Someone has to delete it. That someone is the owner. Some insane fool may even have malloced the object. Someone has to free it instead of deleteing it. Again, that's the owner.
There is no practical way to determine how the object was allocated and how it needs to be disposed of from a pointer. All a pointer does is point. The programmer needs to establish a contract that outlines who, if anybody, looks after it and how. In the old days this could be a painstaking process.
History has shown that contract-based pointer management is difficult to get right. And if you do get it right, the next programmer to come along can completely smurf it up. Pointer management works a lot better when the contract has some sort of automated enforcement.
Today we use a smart pointer. There are a bunch of smart pointers. We're sticking to unique_ptr this time. If you want to know more, read What is a smart pointer and when should I use one?
unique_ptr is the owner. It is a plain old Automatic variable that happens to contain a pointer that it will release as soon as the unique_ptr goes out of scope. No more worries about ownership. The owner is explicit. And like the Highlander, There can be only one.. If you have two unique_ptrs to the same object, it's not all that unique, is it? With two owners, one would go out of scope first and destroy the object, leaving the other owner a ticking timebomb.
Do not new a unique_ptr. That completely defeats the point.
You cannot copy a unique_ptr, but you can transfer ownership with std::move. Note that the object, if any, currently owned by the the destination unique_ptr will be destroyed.
If you call a function that receives a unique_ptr, you will have to transfer ownership to the receiving function parameter. The pointer will now be destroyed the function returns, assuming it doesn't transfer ownership of the pointer elsewhere. Since you often don't want this to happen, but still want the ownership of the pointer to remain clear, pass the unique_ptr by reference.
You can also use the unique_ptr::get method to get a raw, un-owned pointer, but whoever you give it to must know to leave the pointer alone, and that brings us back to contract- based pointer management.
Huh. That wasn't all that <expletive deleted> quick, was it? Sorry about that.
Getting back on topic, your pointer is owned by a unique_ptr. You can't just make a new copy with std::unique_ptr<Node> loop = head;, Highlander's law, above. Transferring ownership to a tightly scoped Automatic variable that will die and destroy the pointer at the end of the loop with std::unique_ptr<Node> loop = std::move(head); would leave the head pointer pointing to nothing. Not useful. The linked list is ruined, but at least everything in it was "correctly" destroyed.
As discussed above you can use a reference or get. You cannot reseat the reference with loop = loop->next, so reference cannot work. That leaves get
void display(std::ostream &str) const {
for (Node* loop = head.get(); loop != nullptr; loop = loop->next.get()) {
str << loop->data << "\t";
}
str << "\n";
}
There is very little room in which the programmer can get confused by the raw pointer here and ownership is still guaranteed by the unique_ptr, so all should be good.
This problem is repeated in
template <class T>
SingleLinkedList<T>::SingleLinkedList(SingleLinkedList<T> const &source) {
for(std::make_unique<Node> loop = source->head; loop != nullptr; loop = loop->next) {
push(loop->data);
}
}
Same solution.
There is a variant in the two push methods
template <class T>
void SingleLinkedList<T>::push(const T &theData) {
std::make_unique<Node> newNode = Node(theData);
if (head == nullptr) {
head = newNode;
tail = newNode;
newNode = nullptr;
}
else {
tail->next = newNode;
tail = newNode;
}
}
Solution (sort of):
template <class T>
void SingleLinkedList<T>::push(const T &theData) {
std::unique_ptr<Node> newNode = std::make_unique<Node>(theData);
if (head == nullptr) {
head = newNode;
tail = newNode;
newNode = nullptr;
}
else {
tail->next = newNode;
tail = newNode;
}
}
But note the assignments to head and tail. That violates Highlander and needs to be fixed. You can transfer ownership of newNode into head, but then there is nothing left to give tail. And why should tail get ownership of anything? Whatever tail points at should be owned by head or some Node's next. It's ownership is guaranteed. Since it's confined within SingleLinkedList it is entering into a contract with itself and can get away with just being a plain old pointer.
That means
Node* tail = nullptr;
and
template <class T>
void SingleLinkedList<T>::push(const T &theData) {
std::unique_ptr<Node> newNode = std::make_unique<Node>(theData);
if (head == nullptr) {
head = std::move(newNode);
tail = head.get();
}
else {
tail->next = std::move(newNode);
tail = tail->next.get();
}
}
I'm out of time, but
void SingleLinkedList<T>::insertHead(const T &theData)
and
void SingleLinkedList<T>::insertTail(const T &theData) {
need to be updated to the new world order and take into account "What if the list is empty?"

Overloading < operator in template

I'm programming a binary tree class template. When I add a new node I check if the new one is less or greater than current.
I overloaded < and > operator in the class type (Object) and works properly but the template doesn't call the overloaded operator, instead uses the generated by the compiler.
object.cc - Comparison between objects works outside the template
bool Object::operator<(const Object& par_other) const
{
printf("\n <");
return id_ < par_other.id_; //assume that you compare the record based on a
}
EDIT 1: Added some requested code. Thx for the help :)
struct Node {
T* value;
Node* left;
Node* right;
};
template <class T>
void BinaryTree<T>::add(T* par_T, Node* par_node) {
if (par_node == nullptr) {
par_node->left = nullptr;
par_node->value = par_T;
par_node->right = nullptr;
} else {
if (par_node->value == nullptr) {
par_node->value = par_T;
} else if (par_node->value > par_T) {
if (!par_node->right) {
par_node->right = createNode();
}
add(par_T, par_node->right);
} else if (par_node->value < par_T) {
if (!par_node->left) {
par_node->left = createNode();
}
add(par_T, par_node->left);
}
}
Why does a node have a T* instead of a T?
If you have a good reason to do that, then compare with:
*par_T < *(par_node->value)
and
*(par_node->value) < *par_T
Notice the use of * and notice I switched the sides rather than misuse >
If you didn't have a good reason to have a node contain a T* then get rid of the *s in this code (and correspondingly elsewhere) but still remember not to use >, ==, != etc. They all can be inferred by results of < ( a is "equal to" b when both a<b and b<a are false)
You also need to fix more things than you asked about. You seem generally confused about the nature of pointers. An extreme example from your code:
if (par_node == nullptr) {
par_node->left = nullptr;
par_node->value = par_T;
par_node->right = nullptr;
}
Think about what that code is doing!

Constructor of template class calls type constructor when new keyword is used

I am beginning a basic implementation of a template LinkedList class. When I compile the header file alone with g++ there is not problem. However, when I try to compile with another class that implements a certain type of the linked list, it gives me an error. It seems to want to compile an object of the type of the node. Why would it do so? The Node constructor doesn't call the constructor of the template type.
I will post all the relevant header files. There may be extraneous code, but I wanted to show what is being used. I will post the error message followed by the linked list implementation, then the class that uses the linked list, and then the ParkingLot constructor that is mentioned in error.
Here is the error message:
LinkedList.h: In instantiation of ‘Node<T>::Node(T) [with T = ParkingLot]’:
LinkedList.h:46:9: required from ‘void LinkedList<Type>::addNode(Type) [with Type = ParkingLot]’
Decal.h:20:28: required from here
LinkedList.h:13:16: error: no matching function for call to ‘ParkingLot::ParkingLot()’
Node(T input) {
^
LinkedList.h:13:16: note: candidates are:
In file included from Decal.h:2:0,
from test.cpp:3:
ParkingLot.h:28:2: note: ParkingLot::ParkingLot(int, std::string, int, int, int, int)
ParkingLot(int num_spaces, std::string name, int x, int y, int randSpacesPercent, int randLotPercent){
^
ParkingLot.h:28:2: note: candidate expects 6 arguments, 0 provided
ParkingLot.h:7:7: note: ParkingLot::ParkingLot(const ParkingLot&)
class ParkingLot {
^
ParkingLot.h:7:7: note: candidate expects 1 argument, 0 provided
ParkingLot.h:7:7: note: ParkingLot::ParkingLot(ParkingLot&&)
ParkingLot.h:7:7: note: candidate expects 1 argument, 0 provided
Could anyone provide some advice? I have no idea why it would try to construct a ParkingLot object when I only want to construct a Node of type ParkingLot.
Here is the implementation:
#include <iostream>
template <typename T> class Node {
public:
/*Class variables*/
T data;
Node* next;
/*Class constructors*/
Node(T input) {
data = input;
next = NULL;
}
};
template <typename Type> class LinkedList {
public:
/*Class variables*/
Node<Type>* head;
/*Class constructor*/
LinkedList(){
head = NULL;
}
/*Class Methods*/
void addNode(Type value) {
Node<Type>* p;
if (head == NULL) {
head = new Node<Type>(value); ********ERROR
}
else {
p = head;
while (p->next != NULL){
p = p->next;
}
p->next = new Node<Type>(value); ************ERROR
}
}
//Check to see if linked list contains specified value
bool contains(Type value) {
Node<Type>* search;
if ( head != NULL) {
search = head;
}
else {
return false;
}
while(search->next != NULL) {
if (search->data.compare(value)) {
return true;
}
search = search->next;
}
if (search->next == NULL && search->data.compare(value)) {
return true;
}
else {
return false;
}
}
void print(){
Node<Type>* p;
p = head;
while (p != NULL) {
std::cout << p->data.print() << " ";
p = p->next;
}
std::cout << "\n";
}
};
Here is the code from the Decal class which just tries to use a linked list of type parking lot. It is designed in this way so that some amount of parking lots correspond to a type of decal.
#include <string>
#include "ParkingLot.h"
#include "LinkedList.h"
class Decal {
//Class Variables
private:
LinkedList <ParkingLot> decal_list;
std::string decal_name;
//Class Methods
public:
Decal(std::string name) {
decal_name = name;
}
void addLot(ParkingLot newLot) {
decal_list.addNode(newLot);
}
bool hasLot(ParkingLot searchLot) {
return decal_list.contains(searchLot);
}
};
Lastly, I have included the Parking Lot constructor for reference. It has a name and locations x,y as well as other parameters for filling its spaces.
ParkingLot(int num_spaces, std::string name, int x, int y, int randSpacesPercent, int randLotPercent){
//Generate bool array for parking spaces
lot_capacity = num_spaces;
for (int i =0; i<lot_capacity; i++) {
parking_lot[i] = true;
}
/*Determine if lot is full or not, and if not generate random full spaces*/
//Assigning percentages to corresponding variable
sp_generator = randSpacesPercent;
lot_generator = randLotPercent;
//Make lot full or not based on percentage
generateLot(lot_generator);
//If lot is not full, assign certain percentage of spots as full/empty
if (isFull() == false) {
generateSpaces(sp_generator);
}
//Assing other vars
parking_lot_name = name;
x_locat = x;
y_locat = y;
}
Thank you for any help you can provide!
The ctor of Node called the default ctor of type T, and then assign it in the body of ctor. If type T does not have a default ctor, compile will fail.
It's better to use initializer list in constructor instead of assignment, it will call the copy ctor of type T. And it can improve the performance in most cases.
Node(T input) : data(input), next(NULL) {}
BTW: It's better to use const reference for the parameter input, it can avoid once copy.
Node(const T& input) : data(input), next(NULL) {}

Constructor and Destructor Declaration Syntax with Template Class

I am trying to make a queue implementing a linked list but am running into a compiler error. The error is coming from the overloaded assignment operator function on the line where I call the destructor (marked with an all-caps comment). I have a hunch it is a simple fix that has something to do with the syntax of my constructor/destructor declarations.
The error I am getting states the following code: error C2512: 'Queue<char>::Queue' : no appropriate default constructor available
It mentions no constructor, but the line it refers to is the one below where I am trying to call the destructor.
Thanks in advance for your help.
#ifndef QUEUE_H
#define QUEUE_H
#include <iostream>
using namespace std;
template <class Type>
class Queue // Create a Queue data structure implementing a linked list
{
private: // The private members
struct Cell // The Cell class will be the blueprints for each link in the list
{
Type data; // The information held by the cell
Cell* next; // The link to the next cell
};
Cell* first = NULL;
Cell* last = NULL;
public: // The public members
Queue(Type);
bool isEmpty();
void push(Type);
Type pop();
Queue<Type>& operator=(Queue<Type>&);
friend ostream& operator<<(ostream&, const Queue<Type>&);
~Queue();
};
template<class Type>
Queue<Type>::Queue(Type inputData) // Constructor that initializes the queue with a new cell that last and first point to
{
first = new Cell;
first->data = inputData;
first->next = NULL;
last = first;
}
template<class Type>
Queue<Type>& Queue<Type>::operator=(Queue<Type>& queue) // Overload "=" so that it performs a deep copy of a Queue object
{
if (!queue.isEmpty())
{
~Queue(); // HERE IS THE ERROR LINE
Cell* rhs = queue.first;
while (rhs != NULL)
{
push(rhs->data);
rhs = rhs->next;
}
}
return *this;
}
template<class Type>
Queue<Type>::~Queue() // Destructor that deallocates all of the memory used by the queue.
{
if (!isEmpty()) // We only need to deallocate the queue if it is non-empty
{
Cell *link = last;
while (link != NULL) // Until we reach the end of the queue, keep deleting each link
{
pop();
}
first = NULL;
last = NULL;
}
else // If the queue is already empty, let the user know
{
cout << "Cannot call destructor. The list is already empty.\n";
}
}
#endif
Check out this thread: Can i call destructor from its class method?. An easy way around this is to make a function to empty the queue, then call it from the destructor and assignment operator.
template<class Type>
void Queue<Type> empty(){
if (!isEmpty()) // We only need to deallocate the queue if it is non-empty
{
Cell *link = last;
while (link != NULL) // Until we reach the end of the queue, keep deleting each link
{
pop();
}
first = NULL;
last = NULL;
}
else // If the queue is already empty, let the user know
{
cout << "Cannot call empty. The list is already empty.\n";
}
}
template<class Type>
Queue<Type>& Queue<Type>::operator=(Queue<Type>& queue) // Overload "=" so that it performs a deep copy of a Queue object
{
if (!queue.isEmpty())
{
empty(); // Tada, no more error
Cell* rhs = queue.first;
while (rhs != NULL)
{
push(rhs->data);
rhs = rhs->next;
}
}
return *this;
}
template<class Type>
Queue<Type>::~Queue() // Deconstructor that deallocates all of the memory used by the queue.
{
empty();
}
This has nothing to do with template.
If you declare any constructor for your class, the compiler synthesized default constructor(i.e. the one that takes no arg) is deleted.
You have to define Queue() yourself.
BTW, a using directive in the global scope is not a good idea.
I guess you define a queue without parameter, like
Queue<char> quCh;
If you want to do this, you must define a constructor without parameter.
Queue();
or you must define your queue like this:
Queue<char> quCh('a');