C++: Overloading the << operator - c++

I have a very silly problem that I just can't figure out. I'm trying to overload the << operator in my "PrioQueue" class. I'm still pretty new to C++ and i've tried almost every example I could find on the web but nothing works.
The PrioQueue is a template class I made that works like a normal Queue but puts the highest value it receives on the top.
PrioQueue<int> intq1(5);
intq1.push(1);
intq1.push(2);
intq1.push(1);
cout << intq1;
The << operator should write all the values that I've pushed to the queue with a '|' in between. So like this:
2 | 1 | 1 |
This is my overload operator << method.
friend std::ostream& operator<<(std::ostream& out, PrioQueue q){
while(!q.empty()){
out.write(q.pop()); //This method pops off the top value and returns it
}
return out;
}
I hope this is enough information but if not. This is my full code:
#include "stdafx.h"
#include <iostream>
#include <ostream>
using namespace std;
template <typename Type>
class PrioQueue
{
private:
Type *bottom_;
Type *top_;
int size_;
public:
PrioQueue(Type size){
bottom_ = new Type[size];
top_ = bottom_;
size_ = size;
}
friend PrioQueue operator+(PrioQueue q1, PrioQueue q2){
while(!q2.empty()){
q1.push(q2.pop());
}
return q1;
}
friend std::ostream& operator<<(std::ostream& out, PrioQueue q){
while(!q.empty()){
out.write(q.pop());
}
return out;
}
//Checks to see if the given value is bigger than the bottom character.
//If so, the bottom and the given value swap places.
//If not, the value gets placed at the top of the queue
void push(Type t){
if(*bottom_ < t){
*top_ = *bottom_;
*bottom_ = t;
}else{
*top_ = t;
}
top_++;
}
int num_items() {
return (top_ - bottom_);
}
Type pop(){
return *(bottom_++);
}
int full() {
return (num_items() >= size_);
}
int empty() {
return (num_items() <= 0);
}
void print(){
cout << "Queue currently holds " << num_items() << " items: " ;
for (Type *element=top_-1; element >= bottom_; element--) {
cout << " " << *element;
}
cout << "\n";
}
int getSize(){
return size_;
}
~PrioQueue(){ // stacks when exiting functions
bottom_ = 0;
delete[] bottom_;
}
};
void intExample(){
PrioQueue<int> intq1(5);
intq1.push(1);
intq1.push(2);
intq1.push(1);
cout << intq1;
intq1.print();
PrioQueue<int> intq2(5);
intq2.push(8);
intq2.push(2);
intq2.push(5);
intq2.print();
PrioQueue<int> intq3(10);
intq3 = intq1 + intq2;
intq3.print();
cout << intq3;
}
void charExample(){
PrioQueue<char> charq1(5);
charq1.push('t');
charq1.push('h');
charq1.push('g');
charq1.print();
PrioQueue<char> charq2(5);
charq2.push('i');
charq2.push('q');
charq2.push('k');
charq2.print();
PrioQueue<char> charq3(10);
charq3 = charq1 + charq2;
charq3.print();
}
int main(){
intExample();
charExample();
return 0;
}

This would work:
friend std::ostream& operator<<(std::ostream& out, PrioQueue q){
while(!q.empty()){
out << q.pop() << "|";
}
return out << "\n"; // if you want a newline, otherwise just "return out;"
}
Edit Note that for this to work, you will have to modify your queue to be copyable. You need to add a copy constructor and an assignment operator (see the rule of three) or use a type that is copyable and assignable to store your data (see std::vector, std::deque, or container adapter std::priority_queue if this is not an exercise).

The problem is that the out.write() expects a const char* and size. First of all, your Type will not implicitly convert to const char* and also, you're missing an argument.
Using out << q.pop() will fix the problem for you.

Related

Is an isFull() function for a Dynamic Array Container Class needed?

I'm having a bit of trouble wrapping this around my head; I used the debugger in VS to go through my code. I realized that when I call the insertBack() function in main() the elements aren't inserted since the condition if (!isFull) isn't met--returning false causing the insertion to not happen. I tried removing the condition and got some errors regarding my code trying to insert a number into an invalid portion of the array. While going through this, I started to ask myself is the isFull() function required since a dynamic array can be resized; but, how can it be full if this is the case? I looked a bit into vectors on cpprefrence and didn't find an isFull() member function.
#include <iostream>
template<typename T>
class container
{
template <typename T2>
friend std::ostream& operator<<(std::ostream& out, const container<T2> &cobj);
// Postcondition: contents of the container object cobj is displayed
public:
container();
// Postcondition: an empty container object is created with data members arr set to NULL, n set to -1 and Capacity set to 0
~container();
// Destructor; required as one of the Big-3 (or Big(5) because of the presence of a pointer data member. Default version results in
// memory leak!
// Postcondition: dynamic memory pointed to by arr has been release back to the “heap” and arr set to NULL or nullptr
// In order to see the action, message "destructor called and dynamic memory released!" is displayed
bool isEmpty() const;
// Postcondition: returns true is nothing is stored; returns false otherwise
bool isFull() const;
// Postcondition: returns true if arr array is filled to capacity; returns false otherwise
int size() const;
// Postcondition: returns the size or the number of elements (values) currently stored in the container
int capacity() const;
// Postcondition: returns the current storage capacity of the container
bool insertBack(const T& val);
// Postcondition: if container is not full, newVal is inserted at the end of the array;
// otherwise, double the current capacity followed by the insertion
bool deleteBack();
// Precondition: The array must not be empty
// Postcondition: the last element stored in the array is removed! size of the container is decremented by 1, capacity unchanged
void clear();
// Postcondition: all elements in arr of calling container object are cleared and the dynamic memory is released back to “heap”
private:
void allocate(T* &temp);
// Postcondition: if Capacity = 0, allocate a single location; otherwise the current capacity is doubled
T *arr;
int Capacity; // Note: Capital 'C' as capacity is used as a function name
int n; // size or actual # of values currently stored in the container; n <= SIZE
};
template<typename T2>
std::ostream& operator<<(std::ostream& out, const container<T2> &cobj)
{
std::cout << "Currently it contains " << cobj.size() << " value(s)" << std::endl
<< "Container storage capacity = " << cobj.capacity() << std::endl
<< "The contents of the container:" << std::endl;
if (cobj.isEmpty())
{
std::cout << "*** Container is currently empty!" << std::endl;
}
else
{
for (int i=0; i<cobj.size(); ++i)
{
std::cout << cobj.arr[i];
}
}
return out;
}
template<typename T>
container<T>::container()
{
arr = nullptr;
Capacity = 0;
n = 0;
}
template<typename T>
container<T>::~container()
{
delete arr;
arr = nullptr;
std::cout << "Destructor called! (this line is normally not displayed)" << std::endl;
}
template<typename T>
bool container<T>::isEmpty() const
{
return n==0;
}
template<typename T>
bool container<T>::isFull() const
{
return n==Capacity;
}
template<typename T>
int container<T>::capacity() const
{
return Capacity;
}
template<typename T>
int container<T>::size() const
{
return n;
}
template<typename T>
bool container<T>::insertBack(const T& val)
{
if (!isFull())
{
n++;
arr[n-1] = val;
return true;
}
else
{
return false;
}
}
template<typename T>
bool container<T>::deleteBack()
{
if (!isEmpty())
{
n--;
return true;
}
else
{
return false;
}
}
template<typename T>
void container<T>::clear()
{
if (!isEmpty())
{
n = 0;
return true;
}
else
{
return false;
}
}
template<typename T>
void container<T>::allocate(T* &temp)
{
if (Capacity==0)
{
temp = new T;
}
else
{
return Capacity*2;
}
}
int main()
{
container<int> a1;
std::cout << a1 << std::endl;
std::cout << "Currently, the container object contains 0 element(s) or 0 value(s)" << std::endl;
std::cout << "\nWe now insert 3 values at the back of the array, one at a time:" << std::endl;
const int num = 3;
for (int i=0, c=0; i<=num; ++i, c+=10)
{
a1.insertBack(c);
}
std::cout << a1;
}
I think that having an isFull method does not make sense, since your dynamic container is not limited in capacity. Instead, you can use the size and capacity methods to track the state of the container.
If you want to implement a vector and want to check if size smaller than or equals to capacity, then decide whether to resize it, you can wrapper size > = capacity as a private isFull() function. But I think it makes no sense to set it public.

Writing a vector class c++

So I'm trying to write a vector class which can take objects without a default constructor. To do so I'm using an array of raw pointers. Thing is, when I'm instantiating a new vector, let's call it 2, based upon a previous vector, let's call it 1-- it points to the underlying address of said previous object, 1. So when I insert a new value into 1, 2 is updated as well.
#ifndef MYVECTOR_MYVECTOR_H
#define MYVECTOR_MYVECTOR_H
#include <sstream>
#include <stdexcept>
#include <memory>
#include <vector>
#include <ostream>
template<typename T>
class MyVector;
template<typename T>
std::ostream& operator<<(std::ostream& out, const MyVector<T>& myVec){
out << "{";
for(int i = 0; i < myVec.numElem; i++){
out << &myVec.elements[i] << " ";
}
out << "}";
return out;
}
template<typename T>
class MyVector{
public:
int numElem;
int capacity;
T** elements;
MyVector(const unsigned int& numElements, const T& value) : numElem(numElements), capacity(numElements * 2){
elements = new T*[capacity];
for(int i = 0; i < numElem; i++){
elements[i] = new T(value);
}
}
template<typename U>
MyVector(const std::vector<U>& values): numElem(values.size()), capacity(values.size() * 2){
elements = new T*[capacity];
for(int i = 0; i < numElem; i++){
elements[i] = new T(values[i]);
}
}
void insert(const unsigned& pos, const T& value){
elements[numElem] = new T(*elements[numElem - 1]);
numElem++;
for(unsigned int i = numElem - 1; i > pos; i--){
elements[i] = elements[i - 1];
}
elements[pos] = new T(value);
}
};
#endif
Per comment #1:
class NoDefault {
public:
NoDefault(const int& value) : value(value) {}
int value;
};
std::ostream& operator<<(std::ostream& out, const NoDefault& noDefault) {
out << noDefault.value;
return out;
}
int main() {
MyVector<NoDefault> noDefaultVec(std::vector<NoDefault>{7,8,9,10,11});
MyVector<MyVector<NoDefault>> vecvec(2, noDefaultVec);
std::cout << "noDefaultVec = " << noDefaultVec << std::endl;
std::cout << "vecvec = " << vecvec << std::endl;
noDefaultVec.insert(3, 99);
vecvec.insert(1, noDefaultVec);
std::cout << "noDefaultVec = " << noDefaultVec << std::endl;
std::cout << "vecvec = " << vecvec << std::endl;
return 0;
}
You perform a shallow copy instead of a deep copy.
A shallow copy of your vector creates a new collection which shares elements with an old one. What follows, any change made to the original object will cause a change in a new one. What you need in that case is a deep copy, which duplicates every element from the source to the destination. After performing such a copy you are left with two vectors with seperate set of data.
Providing a copy constructor for your class solves the problem, but you should also remember about implementing destructor and assignment operator, basing on The Rule Of Three. You can also consider adding move constructor and move assignment operator (or one assignment operator following copy-and-swap idiom).

too many parameters for this operator function

First, I'm not good at english and also first time in StackOverflow, but I try to explain about my code's problem.
I was asked to make my own Vector(similar thing) from my professer, and there's a problem in fuction which returns a reference to the element at the requested position in the vector container. If the requested position is out of range, it should output some messages and terminate the program.
I should make this to Operator overloading, and this is my code.
double operator [](int n, const MyDoubleVector& _mV)//The arror come out at this line.
{
if(n > num)//'num' is private reference in class to count array. it typed int.
{
return 0;
}
return &_mV.data[n];//'data' is private reference in class. It declare like 'double *data = new double [num];'
}
I saw that sometimes 'friend' solve this, but when I put 'friend' in this line, it said me like "operator[] must be a member function."
Finally, Ihave no idea how to do. Would you please help me?
You need to implement the overload of operator[] as a member function of your class MyDoubleVector.
Here's the definition :
double & MyDoubleVector::operator[](int index);
operator [] must be defined as a member of the class.
example:
#include <iostream>
#include <cstdlib>
#include <algorithm>
struct MyDoubleVector
{
MyDoubleVector()
{}
MyDoubleVector(MyDoubleVector const& other)
{
// very naiive copy constructor
if (other.data)
{
std::for_each(other.data, other.data + other.num, [&](double val)
{
this->push(val);
});
}
}
MyDoubleVector& operator=(MyDoubleVector const& other)
{
auto temp = other; // invoke copy constructor
std::swap(num, temp.num);
std::swap(capacity, temp.capacity);
std::swap(data, temp.data);
return *this;
}
~MyDoubleVector()
{
delete [] data;
}
double& operator [](int n);
/** either define the method inline like this...
{
if(n > num)
{
std::cerr << "MyDoubleVector::operator[]: index " << n << " out of range" << std::endl;
std::exit(100);
}
return data[n];
}
**/
void push(double val)
{
if (num == capacity)
{
more();
}
data[num++] = val;
}
private:
void more()
{
if (!data)
{
data = new double [10];
capacity = 16;
}
else
{
auto newcapacity = capacity * 2;
auto newdata = new double [newcapacity];
std::copy(data, data + capacity, newdata);
std::swap(data, newdata);
capacity = newcapacity;
delete [] newdata;
}
}
int num = 0;
int capacity = 0;
double* data = nullptr;
};
/** ...
** or out of line like this
**/
double& MyDoubleVector::operator [](int n)
{
if(n > num)
{
std::cerr << "MyDoubleVector::operator[]: index " << n << " out of range" << std::endl;
std::exit(100);
}
return data[n];
}
int main()
{
MyDoubleVector v;
v.push(10.0);
v[1];
}

Link List of Class, How to get call toString while Transversing?

I was wondering how I could call the toString() method in my Link List of the class BoxClass. BoxClass has a double length, width and height.
my BoxClass:
class BoxClass{
private:
double length;
double width;
double height;
public:
// Default constructor w/ no parameters
BoxClass(){
length = 0;
width = 0;
height = 0;
}
// Constructor with arguments
BoxClass(double boxLength, double boxWidth, double boxHeight){
length = boxLength;
width = boxWidth;
height = boxHeight;
}
// Setters and Getters
void setLength(double boxLength){
length = boxLength;
}
double getLength(){
return length;
}
void setWidth(double boxWidth){
width = boxWidth;
}
double getWidth(){
return width;
}
void setHeight(double boxHeight){
height = boxHeight;
}
double getHeight(){
return height;
}
// Returns the volume of the boxes
double Volume(){
return (length * width * height);
}
// toString method for boxes, returns "(length) x (width) x (height) string
string toString(){
return ("(" + to_string(length)+ "x" + to_string(width) + "x" + to_string(height) + ")");
}
}; // End of BoxClass() class
LinkNode.h
//Template ListNode class definition.
#ifndef LINKNODE_H
#define LINKNODE_H
template <typename T> class LinkList;
template <typename T> class LinkNode{
friend class LinkNode <T>;
public:
LinkNode(const T &);
T getData()const;
T data;
LinkNode <T> *nextPtr;
};
template <typename T> LinkNode <T>::LinkNode(const T &info):data(info), nextPtr(NULL){
// Empty body
}
template <typename T>T LinkNode<T>::getData()const{
return data;
}
#endif
Main (Creating the class, adding it to Link List
// Create the Box class
BoxClass userBox(length, width, height);
// Add box class to Link List
Box.insertNode(userBox);
Box.print();
LinkList.h print() method
template<typename T>void LinkList<T>::print()const {
// To list off nodes
int counter = 1;
if (isEmpty()) {
cout << "No boxes in list!\n";
} else {
LinkNode<T>*currentPtr = firstPtr;
cout << "Your boxes in increasing order of volume is:\n";
// while (currentPtr) {
while (currentPtr != NULL) {
// Output as "#. (length x width x height)
cout << counter << ". " << currentPtr->data << endl;
printf(" %i. %.2f\n", counter, currentPtr->data);
currentPtr = currentPtr->nextPtr;
counter++;
}
}
}
LinkList.h
//Template LinkList class definition.
#ifndef LINKLIST_H
#define LINKLIST_H
#include <iostream>
#include "LinkNode.h"
using namespace std;
template<typename T> class LinkList {
public:
LinkList();
void addNode(const T &);
void insertNode(const T &);
bool isEmpty() const;
void print() const;
private:
LinkNode<T>*firstPtr;
LinkNode<T>*getNewNode(const T &);
};
template<typename T>LinkList<T>::LinkList() :firstPtr(NULL) {
// Empty body
}
template <typename T>void LinkList<T>::insertNode(const T &value) {
LinkNode<T>*newPtr = getNewNode(value);
bool inserted = false;
if (isEmpty() || (newPtr->data < firstPtr->data)) {
newPtr->nextPtr = firstPtr;
firstPtr = newPtr;
// cout << " " << newPtr->data << " inserted at front of list.\n";
printf(" %.2f inserted at front of list.\n", newPtr->data);
} else {
LinkNode<T>*currentPtr = firstPtr;
while (currentPtr->nextPtr && !inserted) {
if (newPtr->data < currentPtr->nextPtr->data) {
// cout << " " << newPtr->data << " inserted before " << currentPtr->nextPtr->data << ". " << endl;
printf(" %.2f inserted before %.2f.\n", newPtr->data, currentPtr->nextPtr->data);
newPtr->nextPtr = currentPtr->nextPtr;
currentPtr->nextPtr = newPtr;
inserted = true;
} else {
currentPtr = currentPtr->nextPtr;
}
}
if (!inserted) {
currentPtr->nextPtr = newPtr;
printf(" %.2f inserted at the end of list.\n", newPtr->data);
}
}
}
template<typename T>bool LinkList<T>::isEmpty()const {
return firstPtr == NULL;
}
template<typename T>LinkNode<T>*LinkList<T>::getNewNode(const T &value) {
return new LinkNode<T>(value);
}
template<typename T>void LinkList<T>::print()const {
// To list off nodes
int counter = 1;
if (isEmpty()) {
cout << "No boxes in list!\n";
} else {
LinkNode<T>*currentPtr = firstPtr;
cout << "Your boxes in increasing order of volume is:\n";
// while (currentPtr) {
while (currentPtr != NULL) {
// Output as "#. (length x width x height)
cout << counter << ". " << currentPtr->data << endl;
printf(" %i. %.2f\n", counter, currentPtr->data);
currentPtr = currentPtr->nextPtr;
counter++;
}
}
}
#endif
So again, my question is- How do I go about traversing the list and calling the toString() BoxClass method? I tried everything from cout << data.toString() << endl; but that doesn't work. I've been stuck on this for days, can someone help me out?
edit: added LinkList.h
When you write template <typename T> class LinkNode{ you are specifically stating that your node class will have no built-in knowledge of the type of the node that it contains.
You have not shown us your LinkList<T> class, but obviously, the same thing applies to it: since it consists of LinkNode<T> it has to also accept a generic parameter of type <T>, so it cannot have built-in knowledge of the actual type of <T> either.
Therefore, you cannot suddenly introduce a method which has such knowledge. It does not make sense. "It does not compute".
What you need to do instead is add this print() method of yours elsewhere, and make it accept a LinkList<BoxClass>. Then, it will be able to view the LinkNodes as LinkNode<BoxClass>, and it will be able to invoke linkNode.data.toString().
The problem is that your implementation of LinkList<T> class has no way for the client code to go through each node of the list in a loop. What if we don't want to print, but do something else with each box?
In addition, it would look weird if I have a LinkList<Widget>, and I see the text when I call print():
"Your boxes in increasing order of volume is:";
I would say, "what boxes? what volume? I have Widgets, not boxes".
A more complete implementation would look something like this (caveat: This has not been compiled. It is to give you the gist of what you should be doing):
template<typename T> class LinkList {
public:
LinkList();
void addNode(const T &);
void insertNode(const T &);
bool isEmpty() const;
// this is what you're missing from the current implementation
typedef LinkNode<T>* Iterator;
Iterator begin() { return firstPtr; }
Iterator next(Iterator ptr) { return ptr->nextPtr; }
Iterator end() { return NULL; }
private:
LinkNode<T>* firstPtr;
LinkNode<T>* getNewNode(const T &);
};
Then with this, the print function need not be part of the linked list. It can live on the outside:
LinkList<BoxClass> boxList;
//...
void print()
{
if (boxList.isEmpty())
cout << "No boxes in list!\n";
else
{
int counter = 1;
cout << "Your boxes in increasing order of volume is:\n";
// get first box
LinkList<BoxClass>::Iterator curBox = boxList.begin();
// loop until no more boxes
while (curBox != boxList.end())
{
// now use curBox to do whatever you want with this box
BoxClass& b = curBox->getData();
cout << counter << ". " << b.toString();
// go to the next box
curBox = boxList.next(curBox);
counter++;
}
}
}
Note how print is no longer a member of LinkList. Also, note the typedef to give us a "nice" name for the LinkNode pointer that the client uses. The comments should be self-explanatory.
I didn't want to overcomplicate the code by introducing a "real" iterator (i.e. overloaded ++), but that operator would replace the LinkList<T>:::next() function call. I leave that to you as an additional exercise.

Getting unresolved external error when operator overloading, even after defining all the methods

EDIT: need to delete post -- problem was trivial (typographical error) and won't be of any help to others
I'm getting errorLNK2019, the unresolved external error, when trying to use an operator overload in one of my cpp files. I've looked all over, and many people have been able to fix the problem by making sure to define every single method in their class prototypes.
I think this has to do a lot with my project design to be honest, but I really can't pinpoint exactly why this error is happening
Here's the code:
//a.cpp
//
// ... skipped all code to bottom to where i modified it
//OVERLOADED FUNCTIONS
int operator+(const int n, const a& entry){
return n + entry.getTime();
}
ostream& operator<<(ostream & out, const a& entry){
out << entry.getTitle() << " by " << entry.getArtist()
<< " (" << entry.getTime() << ") ";
return out;
}
//*********************************************************
// a.h
//... only posting what I changed
//
// Inside the class..
class a
{
public:
friend ostream& operator<<(const ostream& out, const a& entry);
friend int operator+(const int n, const a& entry);
//..
//.. SNIPPED
//..
}
I run into the error when I try to output a b object in the show() method.
//b.cpp
#include "b.h"
b b::etnsl(const int &indexOfItemToAdd) const{
if (originalObjects != NULL && indexOfItemToAdd >= (*originalObjects).size()){
throw "Index out of bounds";
}
b x(originalObjects);
vector<int> *iCopy = x.getIndices();
(*iCopy) = indices;
iCopy->push_back(indexOfItemToAdd);
x.setSum(sum + (*originalObjects)[indexOfItemToAdd].getTime());
return x;
}
void b::show() const{
cout << " Item at loc " << "0x" << this << ":" << endl;
//int j = indices.size();
//if (j == 0)
if (size == 0)
cout << " Empty item." << endl;
else{
for (int i = 0; i < size; i++) //ERROR IN LOOP
cout << " Index " << indices[i] << " : " << (*originalObjects)[indices[i]] << endl;
}
}
int b::getSum() const{
return sum;
}
void b::setSum(const int& num){
sum = num;
}
vector<int>* b::getIndices(){
return &indices;
}
//*********************************************************
//b header class
#ifndef B_H
#define B_H
#include <iostream>
#include <vector>
#include "a.h"
using namespace std;
class b{
private:
int sum, size;
vector <a> *originalObjects;
vector <int> indices;
public:
b(vector<a> *orig = NULL) //counts as 2 constructors: default and a custom one.
: sum(0), originalObjects(orig), size(indices.size()) {
}
b etnsl(const int &indexOfItemToAdd) const;
void show() const;
int getSum() const;
void setSum(const int& num);
vector<int> *getIndices();
};
#endif
ostream& operator<<(ostream & out, const iTunesEntry& tune)
is not same as
ostream& operator<<(const ostream& out, const iTunesEntry& entry);
// ~~~~~
inside the iTunesEntry class (friend method)
And const shouldn't be used as you will have to modify the out object of ostream