I'm just getting started with the use of templates and class templates in university, and honestly it's getting a little confusing for me.
I have to create a Vector class (custom class not std::vector) that can take an array of objects and handle operations on that array, and also automatically increase the size of the array by *2 which you can see in my addData method in Vector. My Registration class creates an array of Vector (class) by taking inputs from a file, passing them into Results so that they read in the data from the file as required.
My Vector class is meant to set the data from Registration into results and increase the size of the array if needed. How would I have to make the input and output operators in my Vector class in order to do this, similarly to how I've done it for my Registration class as it uses file input?
Vector.h:
#ifndef VECTOR_H
#define VECTOR_H
#include <iostream>
#include <string>
#include <sstream>
template <class T>
class Vector
{
public:
Vector(int arraysize1): arraysize(arraysize1), data(new T[arraysize1]){};
Vector<T> *addData(T dataToAdd){
Vector<T> *temp = new Vector<T> (this->arraysize);
temp->data = this->data;
Vector<T> *newData = new Vector<T> (this->arraysize*2);
for (int x = 0; this->arraysize; x++){
if(x < this->arraysize){
newData->setData(temp->getData()[x],x);
}
else
newData->setData(dataToAdd, x);
}
return newData;
};
void initArray(){
for(int x = 0; x<this->arraysize; x++){
this->setData(x ,x);
}
};
void printArray(){
std::ostringstream oss;
for (int i = 0; i < this->arraysize; ++i){
oss << this->data[i] + " ";
}
};
T* getData(){
return this->data;
};
int getSize(){
return this->arraysize;
}
void setData(T data, int index){
this->getData()[index] = data;
}
private:
int arraysize;
T* data;
};
#endif // VECTOR_H
Registration.h(class that makes array of 'results' which is another class)
This is how my array of objects was declared before in my header file, and now I must use my vector class so I change the declaration:
Vector<Result> results;
Registration.cpp:
Here I use input stream and osteam operator overloading to read from the file. Now that Im using my vector class for Results, what syntax do I need to change?
void Registration::readFile(istream &input){
long studentid1;
unsigned semester1;
input >> studentid1 >> semester1 >> count;
input.ignore(100, '\n');
SetStudentID(studentid1);
SetSemester(semester1);
for(unsigned i = 0; i < count; i++)
input >> results[i];
}
void Registration::writeFile(ostream & os) const{
os << "Student ID: " << GetStudentID() << '\n'
<< "Semester: " << GetSemester() << '\n';
for(unsigned i = 0; i < count; i++)
os << results[i] << '\n';
}
If my Result class is needed and any other details do let me know.
Related
I'm currently studying my second course of C++ object oriented programming at university, so I'll probably have bad programming practices and general errors in my code, so, please, point them out if you see any. I'm always open to learn.
I currently have an assignment on C++ templates, where I have to create a program with a class that simulates FIFO(First in First out) queue using a different class as the template type (Queue< Human >HumanQueue).
Queue.h
#ifndef QUEUE_H
#define QUEUE_H
#include "human.h"
template<class T>
class Queue : public Human{
public:
Queue(int = 5);
~Queue();
void enqueue(T);
T dequeue();
void PrintQueue();
private:
T* array;
int size, index;
};
#endif
Queue.cpp
#include <iostream>
#include "queue.h"
using namespace std;
template<class T>
Queue<T>::Queue(int s){
array = new T[s];
size = s;
index = 0;
}
template<class T>
Queue<T>::~Queue(){
delete [] array;
}
// Add object to end of array
template<class T>
void Queue<T>::enqueue(T obj){
if(index == size){
cout << "Rinda ir pilna, nevar pievienot elementu!" << endl; // Array full, can't add any more objects
return;}
else{
array[index] = obj;
index++;}
}
// Remove object from start of array and shift the whole array by 1 position
template<class T>
T Queue<T>::dequeue(){
for(int i = 0; i < size; i++){
array[i] = array[i + 1];
}
index--;
}
template<class T>
void Queue<T>::PrintQueue(){
for(int i = 0; i < index; i++){
cout << i + 1 << ". ";
array[i].PrintHuman();
}
}
main.cpp
#include <iostream>
#include "human.h"
#include "queue.h"
#include "queue.cpp"
using namespace std;
int main(){
Queue<Human> HumanQueue(3);
Human a("Janis", 1.86, 76);
Human b("Peteris", 1.76, 69);
Human c("Arturs", 1.79, 75);
Human d("Aleksis", 1.81, 78);
cout << "Elementu rinda" << endl; // Element queue
HumanQueue.enqueue(a);
HumanQueue.enqueue(b);
HumanQueue.PrintQueue();
cout << "\n//Pievienojam elementu rindai//" << endl; // Add element to queue
HumanQueue.enqueue(c);
HumanQueue.PrintQueue();
cout << "\n//Meginam pievienot vel 1 elementu rindai//" << endl; // Trying to add one more element to queue, should return, that queue is full
HumanQueue.enqueue(d);
HumanQueue.PrintQueue();
cout << "\n//Iznemam 2 elementus no rindas//" << endl; // Dequeue 2 elements from queue
HumanQueue.dequeue();
HumanQueue.dequeue();
HumanQueue.PrintQueue();
system("pause");
return 0;
}
The class "Human" is open to interpretation with any variables and functions of my choosing so I'm not including it in this thread.
The constructor, enqueue and print work fine, but when trying to dequeue I get a return value of 3221225477. From what I have gathered, it means it's some kind of problem with the way the program is using the memory. I used this same template for a previous project, where the types were int, char, float and it worked fine, but it doesn't like to work with objects.
Your dequeue function does not return a value.
It should be like this:
template<class T>
T Queue<T>::dequeue(){
if (index == 0) {
throw std::logic_error("queue is empty");
}
T value = array[0];
for(int i = 0; i < size - 1; i++){
array[i] = array[i + 1];
}
index--;
return value;
}
The exception is just an example of handling an empty queue when calling dequeue.
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).
I have a (what should be simple) assignment in my C++ class.
Here is the assignment:
Create a class template that contains two private data members: T * array and int size. The class uses a constructor to allocate the array based on the size entered. There is member function that allows the user to fill in the array based on the size. In addition, there is a member function that sorts the array and displays the sorted elements. Use the destructor to delete the array. Develop the main( ) to create two objects to call member functions. As a result, the first object will hold its array of double type, and the other will hold its array of the int type.
Here is what I have came up with but coming up with an error of "Allocation of incomplete type 'T'":
#include <iostream>
#include <new>
#include <vector>
using namespace std;
template <class T>
class DynArray {
protected:
int size;
T ** DynamicArray = new T[size];
public:
DynArray(){
void CreateArray(){
cout << "Enter size of Array: ";
cin >> size;
for (int i = 0; i < size; ++i){
DynamicArray[i] = new T();
}
for (int i = 0; i<size; i++) {
cout << "Element " << i << ": ";
cin >> DynamicArray[i];}
}
//Sort Array
void Sort(T a[], int size)
{
int idx, pass;
for (pass=0; pass<size; ++pass){
for (idx=0; idx<size-1; ++idx){
if (a[idx] > a[idx+1])
swap(a[idx], a[idx+1]);}
}
for (int i=0; i<size; ++i) {
for (idx = 0; idx<size-1; ++idx) {
cout << a[idx] << " ";
}
}
}
void DeleteArray(){
for (int i = 0; i < size; ++i){
delete DynamicArray[i];
}
delete[] DynamicArray;
}
};
int main() {
DynArray<class T>();
return 0;
}
Not sure if I am a complete retard in my line of thinking or if I am just missing a small element. Any help is great.
Thank you #jblixr and #user3655463 for your help. I got it worked out I think after your hints and help.
Here is what I came up with for reference if anyone else is working on this.
#include <iostream>
#include <new>
#include <algorithm>
using namespace std;
//Template Class T
template <class T>
class DynArray {
protected:
int size;
T * DynamicArray;
public:
DynArray(){};
DynArray(size_t s): size(s) {
DynamicArray = new T[size];
for (int i = 0; i<size; i++) {
cout << "Element " << i << ": ";
cin >> DynamicArray[i];
}
}
//Sort Array
void Sort(){
sort(DynamicArray, DynamicArray+size);
for (int i=0; i<size; i++) {
cout << DynamicArray[i] << endl;
}
}
//Clear Heap
~DynArray() {
delete []DynamicArray;
}
};
int main() {
int sizeOfArry;
cout << "Enter size of Array: ";
cin >> sizeOfArry;
//Use as an int Array;
DynArray<int> intArray = DynArray<int>(sizeOfArry);
intArray.Sort();
}
From description you have provided looks to me you want to do sth like that:
#include <iostream>
#include <algorithm>
using namespace std;
template <class T>
class DynArray {
protected:
int size;
T * DynamicArray;
public:
DynArray(size_t s): size(s) {
DynamicArray = new T[s];
}
void CreateArray(){
size_t size;
cout << "Enter size of Array: ";
cin >> size;
if(size > this->size)
size = this->size;
for (int i = 0; i<size; i++) {
cout << "Element " << i << ": ";
cin >> DynamicArray[i];
}
}
//Sort Array
void Sort()
{
std::sort(DynamicArray, DynamicArray+size);
}
DynArray() {
delete []DynamicArray;
}
};
int main() {
DynArray<double> dob(3);
DynArray<int> di(3);
dob.CreateArray();
di.CreateArray();
dob.Sort(); di.Sort();
}
I am wondering that whether you are creating a one dimensional array or 2D array, your initial requirements states one dimensional array but you are using 2D array in your code. Anyway, I play along with one dimensional array.
error: allocation of incomplete type 'T'
T *DynamicArray = new T[size];
What you are trying to do here is in-class initialization which can be done for static data members and it is an c++11 extension for non-static data member. So I suggest you not to do so since you are learning. You can only declare the members and don't initialize here.
Even if you make static it cannot be allocated because the template type T is known only after object creation, So the compiler isn't aware of the type it is going to allocate during the compile time.
So it should be simply as
T *DynamicArray;
Nested functions
C++ doesn't support nested functions, learn C++ syntax.
Usage of constructors and destructors
A constructor will do the functionality of CreateArray() and the destructor will do the functionlaity of DeleteArray()
Instantiating a template class
You should explicitly mention the type within the angle brackets that the template class is going to use
DynArray<int> intArray; // if you want to use int
DynArray<float> floatArray;
You can also use your own custom class for type T, hope you will learn soon in your class.
DynArray<MyCustomClass> customArray;
If you correct all these things then your final skeleton will be like the below one
template <class T>
class DynArray {
protected:
int size;
T *DynamicArray ;
public:
DynArray() {
// initailize DynamicArray here
// use your CreateArray() code here
}
void sort() {
// your own sort logic
// No need to pass the size to this function, its a member function
}
~DynArray() {
// use your DeleteArray() code here
}
};
int main() {
DynArray<int> intArray;
intArray.sort()
return 0;
}
Simple, isn't it? :)
I am working on an assignment where I need to sort vectors using a template so I can pass different data types to my class and sort them not using std::sort. so I am very stuck so far,
I don't really get how to use the template to accept my input from main().
PS. this is for Homework, that is why i am not using arrays and the sort function.
Here is my code so far.
using namespace std;
template <class T>
class SortableVector
{
private:
T a =0;
public:
SortableVector(); // constructor
~SortableVector(); // destructor
void bubble_sort(vector<T>, a)
{
for (int i = a.size(); i > 0;i--)
{
for (int j = 0, k = 1; k < i;j++, k++)
{
if (a[j] > a[k])
{
int swap = a[j];
a[j] = a[k];
a[k] = swap;
}
}
}
}
};
And my main is looking like this:
int main()
{
int alen, val;
vector<int> a;
cout << "Enter the number of elements : ";
cin >> alen;
for(int i = 0; i < alen; i++)
{
cin >> val;
a.push_back(val);
}
SortableVector::bubble_sort(a);
cout << "List of sorted elements: " << endl;
for(int i = 0; i < alen; i++)
{
cout << a[i] << " ";
}
cout << endl;
}
Any help will be welcome :)
Ok...
So I made some changes thanks to Namfuak
now I have a totally different problem
command line output;
Hw8_3.cpp:(.text+0x11): undefined reference to SortableVector<int>::SortableVector()'
Hw8_3.cpp:(.text+0x138): undefined reference toSortableVector::~SortableVector()'
Hw8_3.cpp:(.text+0x170): undefined reference to `SortableVector::~SortableVector()'
collect2: error: ld returned 1 exit status
I am really not getting this one. This is the code I have so far;
template <class T>
class SortableVector
{
private:
vector<T> vec;
public:
SortableVector(); // constructor
~SortableVector(); // destructor
void push_back(T push) {vec.push_back(push);}
T bubble_sort(vector<T> a);
};
template <class T>
T SortableVector<T>::bubble_sort(vector<T> a)
{
for (int i = a.size(); i > 0;i--)
{
for (int j = 0, k = 1; k < i;j++, k++)
{
if (a[j] > a[k])
{
T swap = vec[j];
vec[j] = vec[k];
vec[k] = swap;
}
}
}return 0;
}
And my main() ;
{
SortableVector<int> L;
int alen, val;
vector<int> a;
cout << "Enter the number of elements : ";
cin >> alen;
for(int i = 0; i < alen; i++)
{
cin >> val;
L.push_back(val);
}
L.SortableVector<int>::bubble_sort(a);
cout << "List of sorted elements: " << endl;
for(int i = 0; i < alen; i++)
{
cout << a[i] << " ";
}
}
Any other Idea? I am really lost here...
If you are using a template, your swap variable needs to be of that template type. IE:
T swap = a[j];
EDIT: Looking through, I don't think you are using the correct design. Your SortableVector should probably have a vector<T> as a member, IE:
template <class T>
class SortableVector
{
private:
std::vector<T> vec;
public:
SortableVector();
~SortableVector();
void push_back(T push) {vec.push_back(push);}
void bubble_sort() //You could also return a sorted version of vec
}
Otherwise, there is no reason for a SortableVector class, you can just take the function and put it in the global space as a templated function.
You need to provide definitions for the constructor and destructor.
If you don't declare them, the compiler will automatically create them for you. The constructor will call the default constructor on each element (and the base class if there is one) and the destructor will call the destructor of each class element.
However, since you have declared them, you also need to provide definitions.
The error is pretty clear:
Hw8_3.cpp:(.text+0x11): undefined reference to SortableVector<int>::SortableVector()'
Hw8_3.cpp:(.text+0x138): undefined reference toSortableVector::~SortableVector()' Hw8_3.cpp:(.text+0x170): undefined reference to `SortableVector::~SortableVector()' collect2: error: ld returned 1 exit status
You're not defining the constructor and the destructor...
SortableVector() { }
~SortableVector() { }
Or if you want:
template<class T>
SortableVector::SortableVector()
{
...
}
template<class T>
SortableVector::~SortableVector()
{
...
}
Also, this line L.SortableVector<int>::bubble_sort(a); why not just L.buble_sort(a);
Also, here:
template <class T>
T SortableVector<T>::bubble_sort(vector<T> a)
Did you know you're passing a copy of a instead of a reference? This means you any modifications to that vector will not be live in vector<int> a; in your main function or whatever function you're calling it from:
template <class T>
T SortableVector<T>::bubble_sort(vector<T>& a)
Notice the &
This:
vec[j] = vec[k];
vec[k] = swap;
Did you mean a?
This class member is useless:
vector<T> vec;
I'd suggest providing functions for appending to that member instead and remove the vector<T>& a parameter from the bubble_sort function in the class, then instead of making another vector in your main or w/e, use push on your SortableVector class instance.
#include <vector>
#include <algorithm> //This library give us some handy function swap
#include <iostream>
#include <random>
// This is a function to create random number between 1 and 10
static int random_int(){
static std::random_device rd;
static std::mt19937 prng{ rd() };
static std::uniform_int_distribution<> d10{1, 10};
return d10(prng);
}
template<class T>
class SortableVector{
//By default element define in classes are private so no need to specify
std::vector<T> v_;
public:
//You dont need to specify constructor
//Also, you dont need to specify destructor.
//This is because the default constructor and destructor are ok.
//The default constructor use item to item copy. In this case it's gonna copy the vector val_ wich is ok.
//For the destructor, we don't need to do anything
//Usually you use const T& to avoid copy
void push_back(const T& val){
v_.push_back(val);
}
//Here i don't really know what u want to do.
//Do you want to sort your inner vector and return it ?
//Or do you want to make a copy and return it ?
//Let's make a static method so it helps us covering both cases.
//This method is static so it can be used outside of an instance.
//It's like a function that is define inside the scope of this class.
static void bubble_sort(std::vector<T>& v){
//Using the correct type is always better.
//In this case it's the type that define the size of this particular vector is :
size_t size = v.size();//Or with c++11 : auto size = v.size()
bool change;
do{
change = false;
for(int i = 0; i < size - 1; ++i){
if(v[i-1] > v[i]){
std::swap(v[i-1],v[i]);
change = true;
}
}
}
while(change);
}
//This is the method version using the static one.
std::vector<T>& bubble_sort(){
bubble_sort(v_);
return v_;
}
};
int main() {
SortableVector<int> ss;
for(int k = 0; k < 10; ++k){
ss.push_back(random_int());
}
for(auto& elem : ss.bubble_sort()){//C++ 11 foreach
std::cout << elem << std::endl;
}
}
This is my Code
#ifndef INTLIST_H_INCLUDED
#define INTLIST_H_INCLUDED
#include <iostream>
using namespace std;
class intList
{
int upper_bound;
int arr[0];
public:
intList(){ arr[0] = 0; upper_bound = 0; }
void append(int x);
void sort();
friend ostream & operator << (ostream &, intList&);
inline int len(){ return upper_bound; }
inline int &operator [](int x){ return arr[x]; }
private:
void increment(int *a, int &l);
void swap(int &a, int &b);
};
void intList::swap(int &a, int &b)
{
int temp = a;
a = b;
b = temp;
}
void intList::increment(int *a, int &b)
{
b++;
a[b] = 0;
}
void intList::append(int num)
{
arr[upper_bound] = num;
increment(arr, upper_bound);
}
void intList::sort()
{
for(int i = 0; i < upper_bound; i++)
{
int minLoc = i;
for(int j = i+1; j<upper_bound; j++)
{
if(arr[j] < arr[minLoc])
minLoc = j;
}
if(minLoc != i)
swap(arr[i], arr[minLoc]);
}
}
ostream& operator << (ostream & dout, intList &a)
{
dout << "[ ";
for(int i = 0; i<a.upper_bound-1; i++)
dout << a.arr[i] << ", ";
dout << a.arr[a.upper_bound-1] << " ]";
return dout;
}
#endif // INTLIST_H_INCLUDED
The Code does its work perfectly fine. But at the end the Program Crashes. Giving some error like
process returned -1073741819 (0xC0000005) execution time : some seconds.
Just didn't get where am I going wrong.
This looks bad:
int arr[0];
First, C++ doesn't allow zero-sized fixed size arrays. Second, your code certainly needs more than a zero sized array.
Whatever use you make of this code is undefined behaviour (UB). UB includes code seemingly "working perfectly fine".
Your code has several problems.
For example, you have a fixed array of 0 size. If you want a dynamically growable array, you can use std::vector: you can add new items at the end of the vector (dynamically resizing it) using push_back() method:
#include <vector>
// Start with an empty vector
std::vector<int> v;
// Add some items to it
v.push_back(10);
v.push_back(20);
....
Note also that in header files it's not good to insert a using namespace std;. In this way you pollute the global namespace with STL classes, which is bad. Just use std:: prefix in header files.
Moreover, if you want to print the class content to an output stream, you may want to take the class as a const reference, since instances of the class are input parameters (you observe them and print their content to the stream):
std::ostream& operator<<(std::ostream& os, const IntList& a)
{
....
}