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? :)
Related
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.
What I'm trying to create is a TestScore Template class that just simply calculates the average of a array. I'm trying to throw a exception when a grade is negative or bigger than 100. I have created a NegativeScore exception class and a TooLargeScore exception class,both which just return a string message. In main, i create my array and ask the user for the grades, then use the class to get the average but for some reason it doesnt find the average. It doesnt print out the average when i try to. Im thinking the problem lies with my pointers but i dont know what the exact problem is, anyone know?
#ifndef TESTSCORES_H_INCLUDED
#define TESTSCORES_H_INCLUDED
#include <iostream>
#include "NegativeScore.h"
#include "TooLargeScore.h"
#include <iomanip>
using namespace std;
template <class T>
class TestScores
{
private:
T* testscores[];
public:
TestScores(T testscores[]);
T GetAverage();
};
template <class T>
TestScores<T>::TestScores(T testscores[])
{
*(this->testscores) = testscores;
}
template <class T>
T TestScores<T>::GetAverage()
{
T average;
T sum;
T counter;
for(int i = 0; i <= 5; i++)
{
if(*testscores[i] < 0)
{
throw NegativeScore("Test Score is negative, its invalid!");
}
else if(*testscores[i] > 100)
{
throw TooLargeScore("Test score it too high, its invalid!");
}
else
{
sum = sum + *testscores[i];
}
counter++;
}
average = sum / 5;
return average;
}
MAIN
int main()
{
int MAX = 5;
double scores[MAX];
for(int i = 0; i < MAX; i++)
{
int score;
cout << "Enter the test score for test "<< (i+1) << endl;
cin >> score;
scores[i] = score;
}
try
{
TestScores<double> tests(scores);
tests.GetAverage();
cout << tests.GetAverage() << endl;
}
catch(NegativeScore ex)
{
cout << ex.getMessage() << endl;
}
catch(TooLargeScore ex2)
{
cout << ex2.getMessage() << endl;
}
return 0;
}
Your problem is that you class holds an array of pointer to T, but you attempt to initialize it with a array of double (i.e. array of T values).
template <class T>
class TestScores
{
private:
T* testscores[];
public:
TestScores(T testscores[]);
T GetAverage();
};
template <class T>
TestScores<T>::TestScores(T testscores[])
{
*(this->testscores) = testscores; // <--- This is not doing what you think it is.
}
I am surprised that compiled, and you should strongly consider using a better compiler that will warn you of dubious operations.
You should change the class to hold a plain pointer-to-T, i.e. a T* testscores;, or better, an std::vector<T>.
For example, I could get your code working with this change:
template <class T>
class TestScores
{
private:
T* testscores; // Note simpler pointer to first element of array of length of 5.
public:
TestScores(T testscores[]);
T GetAverage();
};
You also have an error in the limits of your for loop in GetAverage (should not include 5), and your variables in that function are uninitialized and may hold garbage values.
The code snippet is as follows. The error is in foo function for the cout line:
typedef struct Datatype {
int first;
int second;
} Datatype;
void foo(std::array<Datatype, 100>* integerarray){
cout << *integerarray[0].first << endl; //ERROR: has no member first
}
void main() {
std::array<Datatype, 100> newarray;
for(int i=0; i<100; i++)
newarray[i] = i;
}
foo(&newarray);
}
Because of operator precedence, *integerarray[0].first is translated as *(integerarray[0].first), which is not what you want. You need to use (*integerarray)[0].first.
cout << (*integerarray)[0].first << endl;
You can make your life simpler by passing a reference.
void foo(std::array<Datatype, 100>& integerarray){
cout << integerarray[0].first << endl;
}
Also, you don't need to use typedef struct DataType { ... } DataType; in C++. You can use just struct DataType { ... };
newarray[i] = i;
In this line you have missed adding value to structure variables.
Also you have passed array as a reference to function. Removing it and passing just the name of array will pass base address of array.
I am adding following code for your reference:
#include<iostream>
#include <array>
struct Datatype{
int first;
int second;
}
typedef Datatype varInts;
void display(std::array<varInts,20> &dummy)
{
int b =5;
for(int i=0; i<20; i++)
{
dummy[i].first =b++;
dummy[i].second = b+5; //Give any logic you wish.just adding different values;
b++;
}
}
int main()
{
std::array<varInts,20> data;
int a =1;
for(int i=0;i<20;i++)
{
data[i].first = a++;
data[i].second = a+5;
a++; //Just adding values for example
}
display(data);
return 0;
}
It runs without error.Hope it helps!!
I am currently exploring the new c++11 features, I am wondering how to initialize the memory pointed by the unique_ptr, with the value I provided in the initializer_list. With a raw memory pointer like "T* data", I can use uninitialized_copy, but when I change from "T* data" to "unique_ptr data" (so I don't have to do explicit deconstruction) it does not work. I am still reading materials on unique_ptr (and my guess is that's because unique_ptr is not copyable), but could someone point out the function that does the job? Thanks!
#include <iostream>
#include <memory>
using namespace std;
template<class T>
class Vector
{
private:
unique_ptr<T []> data;
int size;
public:
Vector(initializer_list<T> l)
{
size = l.size();
cout << "Constructing, size is: " << size << endl;
data.reset(new T[size]); // reserve memory
uninitialized_copy(l.begin(),l.end(),data); // not working
//for(int i = 0; i<size; i++ ) // not working -> l has no operator[]
// data[i] = l[i];
}
void Report()
{
for(int i = 0; i<size; i++ )
cout << data[i] << ' ';
cout << '\n';
}
};
int main(int argc, const char *argv[])
{
int a = 1;
Vector<int> v {1,2,3,4};
v.Report();
return 0;
}
Simply use the getter :
std::copy(l.begin(),l.end(),data.get());
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;
}
}