I have a program that uses something I made called "SortableVector," with a parent called SimpleVector. The Simple Vector is fine, and so is most of SortableVector, but the problem is the sort function in SortableVector. It sorts numbers just fine, but I can't get it to sort strings. Here's what I originally had:
template <class T>
void SortableVector<T>::sort()
{
T temp = 0;
for(int i = 0; i < this->size(); i++)
{
for (int count = i+1; count < this->size(); count++)
{
if(this->operator[](0) == int)
{
if (this->operator[](count) < this->operator[](i))
{
temp = this->operator[](count);
this->operator[](count) = this->operator[](i);
this->operator[](i) = temp;
count = i+1;
}
}
}
}
}
Then I tried to use the sort(begin, end) function, but that didn't work either:
template <class T>
void SortableVector<T>::sort()
{
sort(this->operator[].begin(), this->operator[].end();
}
EDIT: To help people understand the problem, here's the whole file:
#ifndef SORTABLEVECTOR_H
#define SORTABLEVECTOR_H
using namespace std;
#include "SimpleVector.h"
#include <algorithm>
#include <fstream>
#include <string>
template <class T>
class SortableVector : public SimpleVector<T>
{
public:
SortableVector(int s) : SimpleVector<T>(s)
{}
SortableVector(SortableVector &);
SortableVector(SimpleVector<T> &obj):
SimpleVector<T>(obj)
{}
void sort();
};
template <class T>
SortableVector<T>::SortableVector(SortableVector &obj):SimpleVector<T>(obj)
{
}
template <class T>
void SortableVector<T>::sort()
{
std::sort(this->operator[].begin(), this->operator[].end());
T temp = 0;
for(int i = 0; i < this->size(); i++)
{
for (int count = i+1; count < this->size(); count++)
{
if(this->operator[](0) == int)
{
if (this->operator[](count) < this->operator[](i))
{
temp = this->operator[](count);
this->operator[](count) = this->operator[](i);
this->operator[](i) = temp;
count = i+1;
}
}
}
}
}
#endif
And this is SimpleVector:
// SimpleVector.h
#ifndef SIMPLEVECTOR_H
#define SIMPLEVECTOR_H
#include <iostream>
#include <cstdlib>
using namespace std;
template <class T>
class SimpleVector
{
private:
T *aptr;
int arraySize;
void subError(); // Handles subscripts out of range
public:
SimpleVector() // Default constructor
{ aptr = 0; arraySize = 0;}
SimpleVector(int); // Constructor
SimpleVector(const SimpleVector &); // Copy constructor
~SimpleVector(); // Destructor
int size() { return arraySize; }
T &operator[](int); // Overloaded [] operator
void print() const; // outputs the array elements
void push_back(T); // newly added function (implemention needed)
T pop_back(); // newly added function (implemention needed)
};
//****************************************************************
// Constructor for SimpleVector class *
// Sets the size of the array and allocates memory for it. *
//****************************************************************
template <class T>
SimpleVector<T>::SimpleVector(int s)
{
arraySize = s;
aptr = new T [s];
}
//*********************************************
// Copy Constructor for SimpleVector class *
//*********************************************
template <class T>
SimpleVector<T>::SimpleVector(const SimpleVector &obj)
{
arraySize = obj.arraySize;
aptr = new T [arraySize];
for(int count = 0; count < arraySize; count++)
*(aptr + count) = *(obj.aptr + count);
}
// *************************************
// Destructor for SimpleVector class *
// *************************************
template <class T>
SimpleVector<T>::~SimpleVector()
{
if (arraySize > 0)
delete [] aptr;
}
//************************************************************
// SubError function *
// Displays an error message and terminates the program when *
// a subscript is out of range. *
//************************************************************
template <class T>
void SimpleVector<T>::subError()
{
cout << "ERROR: Subscript out of range.\n";
exit(0);
}
//***********************************************************
// Overloaded [] operator *
// This function returns a reference to the element *
// in the array indexed by the subscript. *
//***********************************************************
template <class T>
T &SimpleVector<T>::operator[](int sub)
{
if (sub < 0 || sub >= arraySize)
subError();
return aptr[sub];
}
//********************************************************
// prints all the entries is the array. *
//********************************************************
template <class T>
void SimpleVector<T>::print( ) const
{
for (int k = 0; k < arraySize; k++ )
cout << aptr[k] << " ";
cout << endl;
}
//***************************************************************
// (1) push_back(T val) *
// The push_back function pushes its argument onto the back *
// Of the vector. *
//***************************************************************
template <class T>
void SimpleVector<T>::push_back(T val)
{
aptr[arraySize] = val;
arraySize++;
}
// *****************************************************
// (2) pop_back() *
// The pop_back function removes the last element *
// Of the vector. It also returns that value. *
// *****************************************************
template <class T>
T SimpleVector<T>::pop_back()
{
arraySize--;
T temp = aptr[arraySize];
return temp;
}
#endif
The SimpleVector was provided by the instructor.
You can do without the repeated this-> 99% of the time
You can just invoke operators, instead of invoking them as functions
You can just use std::sort from <algorithm>
Imagining some of the code you didn't show:
#include <vector>
#include <algorithm>
template <typename T>
struct SimpleVector {
std::vector<T> data;
virtual ~SimpleVector() {}
};
template <typename T>
struct SortableVector : public SimpleVector<T> {
void sort() {
std::sort(this->data.begin(), this->data.end());
}
};
#include <iostream>
int main()
{
SortableVector<std::string> sv;
sv.data = {"one","two","three","four"};
sv.sort();
for(auto& s : sv.data)
std::cout << s << ' ';
}
DISCLAIMER This seems a very non-c++ way to design classes. Algorithms and containers are traditionally separated, for good reason. The exception being that member functions sometimes perform operations in more optimal ways (e.g. std::set<>::find instead of std::find)
It should be std::sort(aptr, aptr + arraySize);. Also you should check arraySize > 0 before doing this, if you're intending to catch errors like that instead of having undefined behaviour.
begin and end aren't magic; they rely on the object either being an array (not a pointer), or the object implementing functions .begin() and .end() that return iterators.
You could even define those functions yourself, e.g. SimpleVector<T>::begin() { return aptr; } etc. , but maybe this is not a good idea as it bypasses your bounds-checking. You'd have to actually write an iterator class instead of returning a pointer, which is more trouble than you're ready for :)
NB. Everywhere you write this->operator[](foo), it would be clearer to write (*this)[foo]
Related
Firstly, I have to print the value of Funcion "Ranking" which of parameter is Stack!
But my compiler says
I think that I delete memory which is not allocated. But, I can't find when I delete that memory....
Please help me the point I wrongly access memory.
P.S. I want to make a program that receive ints or strings and, put ints or strings into stack.
And use Ranking function as a Stack, the result would be,
For ints, how many numbers in stack which exceed first number of stack .
For strings, how many strings in stack which are later order than first string of stack.(The order of string objects is determined in the lexicographic order.)
For example, if inputs are 4 1 +2 5 3 -1 6 and the results is 2 (because 5 and 6 are bigger than first 4)
For example, if inputs are "to be or not to be" the results is 0 ( because there is no later order string than "to")
#include <iostream>
#include <sstream>
#include <string>
#include <cctype>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <algorithm>
const size_t SIZE = 100;
using namespace std;
template <class T>
class Stack
{
public:
Stack(size_t size = SIZE);
Stack(const Stack<T>& s);
const Stack<T>& operator = (const Stack<T>& s); ~Stack();
bool isfull();
bool isEmpty();
void push(T d);
T pop();
T Elem(size_t i);
// int Ranking(T obj);
private:
T *_data;
size_t _top, _size;
};
template <class T>
Stack<T>::Stack(size_t size) : _top(0), _size(size)
{
_data = new T[size];
}
template <class T>
Stack<T>::Stack(const Stack<T>& s) : _top(s._top), _size(s._size)
{
if (_data) delete[] _data;
_size = s._size;
_top = s._top;
_data = new T[_size];
for (int i = 0; i < _size; ++i)
_data[i] = s._data[i];
}
template <class T>
Stack<T>::~Stack()
{
delete [] _data;
}
template <class T>
bool Stack<T>::isfull()
{
return _top == _size;
}
template <class T>
bool Stack<T>::isEmpty()
{
return _top == 0;
}
template <class T>
void Stack<T>::push(T d)
{
if (! isfull())
_data[_top++] = d;
}
template <class T>
T Stack<T>::pop()
{
if (! isEmpty())
return _data[--_top];
throw -1;
}
template <class T>
T Stack<T>::Elem(size_t i)
{
return _data[i];
}
template <class T>
int Ranking(T obj)
{
int k = 0;
while(!obj.isEmpty())
{
if(obj.Elem(0).compare(obj.pop()) < 0 )
k++;
}
return k;
}
int main(void)
{
int k = 0;
int value = 0;
int num;
string s;
string line;
Stack<string> strs;
Stack<string> temps;
vector<int> nums;
while (getline(cin, line))
{
istringstream ins(line);
while (ins >> s)
{
strs.push(s);
}
nums.push_back(Ranking(strs));
}
}
In the body of your copy constructor, _data is initially uninitialised. if (_data) has undefined behaviour, which you have observed as delete[]ing an arbitrary pointer value.
There is never a previous allocation in a new object, so you don't need to delete[] anything. You declare (in a non-traditional way) but don't define a copy assignment operator.
I've also implemented a move constructor, which can reduce the number of copies you need.
Most of the bodies of your constructors can go, or be moved to the member initialiser. It is better to use a pre-defined algorithm rather than do it yourself.
#include <algorithm>
#include <utility>
template <class T>
Stack<T>::Stack(size_t size) : _data(new T[size]), _top(0), _size(size)
{}
template <class T>
Stack<T>::Stack(const Stack<T>& s) : _data(new T[s._size]), _top(s._top), _size(s._size)
{
std::copy_n(s._data, s._size, _data);
}
template <class T>
Stack<T>::Stack(Stack<T>&& s) : _data(std::exchange(s._data, nullptr)), _top(s._top), _size(s._size)
{
}
template <class T>
Stack<T>& Stack<T>::operator=(Stack<T> s) // nb: by-value argument, copies or moves
{
std::swap(_data, s._data);
_size = s._size;
_top = s._top;
return *this;
}
I had refrenced a few other similar questions, they would often point to circularity being the problem. But I cannot see that anywhere within my code.
arrayi.cpp:
#include "arrayi.h"
// Member function definitions for class Array
// Initialize static data member at file scope
template<typename T>
int Array<T>::arrayCount = 0; // no objects yet
// Default constructor for class Array
template<typename T>
Array<T>::Array(int arraySize)
{
++arrayCount; // count one more object
size = arraySize; // default size is 10
ptr = new int[size]; // create space for array
assert(ptr != 0); // terminate if memory not allocated
int i;
for (i = 0; i < size; i++)
ptr[i] = 0; // initialize array
}
arrayi.h:
#ifndef ARRAYI_H_
#define ARRAYI_H_
#include <iostream>
#include <cstdlib>
#include <cassert>
using namespace::std;
template<typename T> class Array;
template<typename T>
ostream &operator<< (ostream& output, const Array<T> &a);
template<typename T>
class Array
{
friend ostream &operator<< <>(ostream &output, const Array<T> &a);
public:
Array(int = 10); //constructor
Array(const Array &); //copy constructor
private:
int *ptr; //ptr to first array element
int size; //size of the array
static int arrayCount; // #of arrays instantiated
};
#include "arrayi.t"
#endif
arrayi.t:
#ifndef ARRAYI_T_
#define ARRAYI_T_
#include <iostream>
#include <cstdlib>
#include <cassert>
using namespace::std;
// Default constructor for class Array
template<typename T>
Array<T>::Array(int arraySize)
{
cout << "calling the constructor \n";
}
// Overloaded output operator for class Array
template<typename T>
ostream &operator<<(ostream &output, const Array<T> &a)
{
int i;
output << "{ ";
for (i = 0; i < a.size; i++)
{
output << a.ptr[i] << ' ';
if ((i + 1) % 10 == 0)
output << "}" << endl;
} //end for
if (i % 10 != 0)
output << "}" << endl;
return output; // enables cout << x << y;
}
#endif
I have been scanning my code up and down for quite some hours now, so any help would be much appreciated, thanks in advance! Any messy or broken looking code may be because this is from a work in progress, but there are no errors but the mentioned one at the moment. Everything shown compiles when the function "Array::Array(int arraySize)" is removed.
arrayi.t defines
Array<T>::Array(int arraySize)
{
cout << "calling the constructor \n";
}
arrayi.cpp defines
template<typename T>
Array<T>::Array(int arraySize)
{
++arrayCount; // count one more object
size = arraySize; // default size is 10
ptr = new int[size]; // create space for array
assert(ptr != 0); // terminate if memory not allocated
int i;
for (i = 0; i < size; i++)
ptr[i] = 0; // initialize array
}
Two definitions of the same function with the same parameters is not allowed.
Solution:
Pick the one that is the real constructor. Delete the other one. If you select the implementation in arrayi.cpp, ensure that it is visible to translation units that require it. This most likely means move it to arrayi.t.
Give Template static variable a read for heads-up on another problem coming your way.
I have an Abstractqueue and I want to inherit it's members to another child class. When I try to create the child object in my main file I keep getting an undefined reference to `AbstractQueue::AbstractQueue()'
enter code here
#ifndef ABSTRACT_QUEUE_H
#define ABSTRACT_QUEUE_H
#include <iostream>
template <class Type>
class AbstractQueue
{
protected:
Type *items;
int front;
int back;
int capacity;
int count;
private:
// data goes here
public:
AbstractQueue(int s);
AbstractQueue(void);
~AbstractQueue(void);
bool empty();
int size();
Type frontele(); //throw(exception) {}
Type dequeue(); //throw(exception) {}
void enqueue ( Type e );
};
template <class Type>
AbstractQueue<Type>::AbstractQueue(int s){
items = new Type[s];
front = 0;
back = 0;
capacity = s;
count = 0;
std::cout << "made the abstract queue!" << std::endl;
}
template <class Type>
AbstractQueue<Type>::~AbstractQueue() {
delete[] items;
std::cout << "destructor called" << std::endl;
}
#endif
IncrementalQueue.h
#ifndef _INCREMENTALQUEUE_H
#define _INCREMENTALQUEUE_H
#include "Queue.h"
//#define SIZE = 10
#include <iostream>
template <class Type>
class IncrementalQueue : public AbstractQueue<Type>{
public:
//AbstractQueue(void);
//~AbstractQueue(void);
IncrementalQueue(int s);
bool empty();
int size();
Type frontele(); //throw(exception) {}
Type dequeue(); //throw(exception) {}
void enqueue ( Type e );
//~IncrementalQueue(void);
//AbstractQueue(void);
//AbstractQueue(int size);
//bool empty(void) ;
/*if (count == 0) {
return true;
}
else {
return false;
}*/
//int size(void);
//Type front throw(exception) {}
//Type dequeue(); //throw(exception) {}
//void enqueue ( Type e ) ;
//IncrementalQueue(int size);
};
template <class Type>
IncrementalQueue<Type>::IncrementalQueue(int s){
this->items = new Type[50];
this->front = 0;
this->back = 0;
this->capacity = 50;
this->count = 0;
std::cout << "made the incremental queue!" << std::endl;
}
#endif
main.cpp
#include "Queue.h"
#include "IncrementalQueue.h"
int main(){
IncrementalQueue<int> incqueue(50);
return 0;
}
I'm a little rusty with templates so I've been struggling at it for a couple of hours. does anybody have any clues on where my code can be failing?
IncrementalQueue::IncrementalQueue() constructor is calling the AbstractQueue::AbstractQueue() constructor and you have not defined it.
To make it compile you can just say AbstractQueue() = default; to have it generated by the compiler, if you are using C++11 or later, but that will not necessarily be correct (see the comments).
As it always happens with templates, you either need to put AbstractQueue::AbstractQueue() implementation (function body) to its header, or, if you know in advance all its possible template parameters, explicitly instantiate this function in cpp-file:
template class AbstractQueue<NeededType>;
In your case, it's impossible to know all possible template args in advance, so you need to put your function body to the header. That's the price of separate unit compilation.
I'm in the early stage of trying to convert an array class containing operator overloading into a templatized class. At the moment I'm trying to add the template definition to the class and each function. This should be fairly simple however, whenever I run the program I get a scope error.
The compiler says `T' was not declared in this scope (I will comment the error on the line that it occurs). The error also re-occurs on the other function definitions. I'm using a program invovling a templatized class as a guide and it implements the functions in the exact manner that I am trying to(which is why I'm confused). What do I need to do to resolve this?
Thank you.
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <stdexcept>
using namespace std;
#ifndef ARRAY_H
#define ARRAY_H
template <typename T>
class Array
{
public:
Array(int = 10);
Array(const Array&);
~Array();
int getSize() const;
const Array &operator=(const Array &);
bool operator==(const Array&) const;
bool operator!=(const Array &right) const
{
return ! (*this == right);
}
int &operator[](int);
int operator[](int) const;
private:
int size;
int *ptr;
};
#endif
template<typename t>
Array<T>::Array(int arraySize) //ERROR: T was not declared in this scope***********
{
if(arraySize > 0)
size = arraySize;
else
throw invalid_argument("Array size myst be greater than 0");
ptr = new int[size];
for(int i = 0; i < size; i++)
ptr[i] = 0;
}
template<typename t>
Array<T>::Array(const Array &arrayToCopy): size(arrayToCopy.size)
{
ptr = new int[size];
for(int i = 0; i < size; i++)
ptr[i] = arrayToCopy.ptr[i];
}
template<typename t>
Array<T>::~Array()
{
delete [] ptr;
}
template<typename t>
int Array<T>::getSize() const
{
return size;
}
template<typename t>
const Array<T> &Array::operator=(const Array &right)
{
if (&right != this)
{
if(size != right.size)
{
delete [] ptr;
size = right.size;
ptr = new int[size];
}
for(int i = 0; i < size; i++)
ptr[i] = right.ptr[i];
}
return *this;
}
template<typename t>
bool Array<T>::operator==(const Array &right) const
{
if(size != right.size)
return false;
for(int i = 0; i < size; i++)
if(ptr[i] != right.ptr[i])
return false;
return true;
}
template<typename t>
int &Array<T>::operator[](int subscript)
{
if(subscript < 0 || subscript >= size)
throw out_of_range("Subscript out of range");
return ptr[subscript];
}
template<typename t>
int Array<T>::operator[](int subscript) const
{
if(subscript < 0 || subscript >= size)
throw out_of_range("Subscript out of range");
return ptr[subscript];
}
int main()
{
//main is empty at the moment because I want to make sure that the class is functional
//before implementing the driver function.
system("pause");
}
Before each of your function definitions, you have written:
template<typename t>
You mean:
template<typename T>
That is, it should match the template parameter of your class, which is a capital T.
I'm pretty new to C++ and this site so there are bound to be errors. When I try to compile my code I get errors like error: missing template argument before 'b'. I've been searching the world for answers for hours and it has led me here.
My assignment is to implement a templated class Collection that stores a collection of
Objects using an array, along
with the current size of the collection.
#include <iostream>
#include "collection.h"
using namespace std; v
int main(int argc, char* argv[])
{
collection b; //<----error missing template argument before 'b'
return 0;
}
#ifndef COLLECTION_H
#define COLLECTION_H
#include <iostream>
template <typename obj>
class collection
{
public:
collection();
bool isEmpty() const;
void makeEmpty();
void insert(obj val);
void remove(obj val);
bool contains(obj val) const;
private:
size_t size;
obj* col[];
};
#endif
#include "collection.h"
template <typename obj>
collection<obj>::collection() :size(10)
{
col = new obj*[size];
}
template <typename obj>
bool collection<obj>::isEmpty() const
{
for(size_t k = 0; k < size; k++)
{
if(col[k] != NULL)
return false;
}
return true;
}
template <typename obj>
void collection<obj>::makeEmpty()
{
for(size_t k = 0; k < size; k++)
{
col[k] = NULL;
}
}
template <typename obj>
void collection<obj>::insert(obj val)
{
int temp = 0;
for(size_t s = 0; s < size; s++)
{
if(col[s] != NULL)
temp++;
}
if(temp >= size)
{
obj* temp = new obj*[size*2];
for(size_t c = 0; c < size; c++)
temp[c] = col[c];
delete col;
col = temp;
}
else
col[temp] = val;
}
template <typename obj>
void collection<obj>::remove(obj val)
{
for(size_t x = 0; x < size; x++)
{
if (col[x] == val)
{
for(size_t y = x; y < size-1; y++)
{
col[y] = col[y+1];
}
col[size-1] = NULL;
return;
}
}
}
template <typename obj>
bool collection<obj>::contains(obj val) const
{
for(size_t z = 0; z < size; z++)
{
if(col[z] == val)
return true;
}
return false;
}
You have to say what it's a collection of.
template <class A> class collection {}
requires that you use it as
collection<int> b;
or some appropriate type. That then makes a collection of ints. You haven't told it what you want a collection of.
First : Instantiate template by type. So if you have template <typename obj> class T {...}; you should use it like
void main {
T<int> t;
T<bool> t1; // .. etc
}
You can use a template with default value for the typename parameter defined in the class template declaration
template <typename obj = int> class T {/*...*/};
void main {
T<> t;
}
but anyway you should put empty angle brackets when use it without parameter.
Second: While declaring template, place it whole in the header file. Each definition of his methods should be in the file "*.h", don't ask me why, just don't split it to the header and "cpp" file.
Hope it helps.
Well, you're missing a template argument. You can't create a collection object, that's just a template.
You can only create e.g. a collection<int> or collection<std::string>.
You need to specify the type for template, like int or some other type:
collection<int> b;
There are a large number of errors in your code. First define your template in a header file:
In collection.h put the following:
#ifndef COLLECTION_H
#define COLLECTION_H
template <typename obj>
class collection
{
public:
collection() {}
bool isEmpty() const;
void makeEmpty();
void insert(obj val);
void remove(obj val);
bool contains(obj val) const;
private:
size_t size;
obj* col[];
};
#endif
Then in a .cpp file inside a main function do the following:
collection<int> b;
Instead of int you can use a different type but the main point is that YOU NEED A TYPE to instantiate a template.