I have a class template
template <class T> class Collection
{
private:
int size;
int type;
T* Arr;
int Case;
public:
void ArrayGenerating() {
switch(type) {
case 1:
Arr = new T[size];
for (int i = 0; i < size; i++) {
srand((unsigned)time(NULL));
Arr[i] = static_cast <T> (rand()) % size;
}
case 2:
Arr = new T[size];
for (int i = 0; i < size; i++) {
srand((unsigned)time(NULL));
Arr[i] = static_cast <T> (rand()) / (static_cast <T> (RAND_MAX/size));
}
case 3:
Arr = new T[size];
for (int i = 0; i < size; i++) {
srand((unsigned)time(NULL));
Arr[i].setNumerator(static_cast <int> (rand()) % size);
srand((unsigned)time(NULL));
Arr[i].setDenominator(static_cast <int> (rand()) % size);
}
}
}
};
I want to creat an random array of generic data type
with type 1, that is an interger array. type 2, an float array. type 3, I have an self-defined data type "fraction". But when I compile the programm, there are errors:
Error 1 error C2228: left of '.setNumerator' must have class/struct/union
Error 2 error C2228: left of '.setDenominator' must have class/struct/union
So if there are any solution for this complication?
I guess, type is a constant depending on T. Otherwise it would make no sense to have a T* point to an int, when T is a float. If that is true, it is not necessary at all.
I think, what you are looking for is template specialization (untested code):
// this is common to all cases.
class CollectionBase {
protected:
int size;
};
// the general template is not defined
// the compiler will complain whenever T is neither int, nor float, nor fraction.
template<class T> class Collection;
// here come the specializations
template<> class Collection<int>: private CollectionBase
{
private:
int* Arr;
public:
void ArrayGenerating() {
Arr = new int[size];
for (int i = 0; i < size; i++) {
srand((unsigned)time(NULL));
Arr[i] = static_cast<int>(rand()) % size;
}
}
};
template<> class Collection<float>: private CollectionBase
{
private:
float* Arr;
public:
void ArrayGenerating() {
Arr = new float[size];
for (int i = 0; i < size; i++) {
srand((unsigned)time(NULL));
Arr[i] = static_cast<float>(rand()) / (static_cast<float>(RAND_MAX/size));
}
}
};
template<> class Collection<fraction>: private CollectionBase
{
private:
fraction* Arr;
public:
void ArrayGenerating() {
Arr = new fraction[size];
for (int i = 0; i < size; i++) {
srand((unsigned)time(NULL));
Arr[i].setNumerator(static_cast <int> (rand()) % size);
srand((unsigned)time(NULL));
Arr[i].setDenominator(static_cast <int> (rand()) % size);
}
}
};
Please note, that this kind of code is dangerous. Consider std::vector<> instead of managing dynamically allocated array yourself.
Also be aware, that as a rule of thumb all methods of your class should be safely callable as soon as the constructor has finished. In your code any function that accesses Arr uses a random pointer to some memory, before ArrayGenerating() has run. Whenever you call ArrayGenerating() twice for some reason, your code will leak memory, because you never bother to delete[] your array before creating a new one.
The best tool C++ gives you for memory management is constructors and destructors. You are best of, when you encapsulate every resource, that you have to release once in a while, in a handler object. In this case std::vector already does what you need.
So here is a full (yet untested) most generic solution for you. I'd start with a free function to create random numbers:
template<typename T> struct dist{
using uniform = std::uniuniform_int_distribution<T>;
};
template<> struct dist<float> {
using uniform = std::uniuniform_real_distribution<float>;
};
template<typename T>
std::vector<T> createRandomNumbers(size_t s) {
auto e1 = std::default_random_engine{std::random_device{}()};
auto u = dist<T>::uniform{0, static_cast<T>(s)};
auto r = std::vector<T>(s, 0);
for( auto& i: r ) i = u(e1);
return r;
}
// fraction need a specialization
template<>
std::vector<fraction> createRandomNumbers<fraction>(size_t s) {
auto e1 = std::default_random_engine{std::random_device{}()};
auto u = dist<int>::uniform{0, static_cast<int>(s)};
auto r = std::vector<fraction>(s, 0);
for( auto& i: r ) {
i.setNumerator(u(e1));
i.setDenominator(u(e1));
}
return r;
}
Now we implement a Collection class template like yours, if we really still need it:
template <typename T> Collection {
private:
// this will handle all your memory management needs
std::vector<T> randoms;
public:
Collection(size_t s) :
randoms{createRandomNumbers<T>(s)}
{};
createNewRandoms(size_t s) {
std::swap(randoms, createRandomNumbers<T>(s));
};
// whatever else is necessary
};
Why would you want to do this and make your life infinitely more difficult?
It could be as simple as this:
#include <iostream>
#include <chrono>
#include <random>
template<class type_t, std::size_t size>
class Array
{
private:
type_t arr[size];
public:
Array()
{
for (std::size_t i = 0; i < size; ++i)
{
//nice C++ random number generation
auto seed = static_cast<unsigned>(std::chrono::system_clock::now().time_since_epoch().count());
std::minstd_rand0 randm(seed);
arr[i] = randm();
}
}
//test function
void print()
{
for (int i = 0; i < size; ++i)
std::cout << arr[i] << " ";
}
};
int main()
{
Array<int, 4> arr;
arr.print();
std::cin.get();
}
Try to get away from C-style C++. Join the dark side.
Note: I won't comment on your use of C functions or other problems. Others have already told you how to avoid them.
A type member in a class template somehow defeats the purpose of generic programming, doesn't it? You should get rid of your type and replace the switch with template specialisation.
Here is a simple example to get you started:
// Collection for all T except of `fraction`
template <class T> class Collection
{
private:
int size;
T* Arr;
int Case;
public:
void ArrayGenerating() {
Arr = new T[size];
for (int i = 0; i < size; i++) {
srand((unsigned)time(NULL));
Arr[i] = static_cast <T> (rand()) % size;
}
};
};
// Collection for `fraction`
template <> class Collection<fraction>
{
private:
int size;
fraction* Arr;
int Case;
public:
void ArrayGenerating() {
Arr = new fraction[size];
for (int i = 0; i < size; i++) {
srand((unsigned)time(NULL));
Arr[i].setNumerator(static_cast <int> (rand()) % size);
srand((unsigned)time(NULL));
Arr[i].setDenominator(static_cast <int> (rand()) % size);
}
}
};
This is the simplest kind of template specialisation but may lead to a lot of code duplication. You can get around this problem, too, though. For example, you could extract all common parts into a common private base class, something like this:
namespace detail
{
template <class T> class CollectionBase
{
protected:
int size;
T* Arr;
int Case;
};
}
template <class T> class Collection : detail::CollectionBase<T>
{
public:
void ArrayGenerating() {
Base::Arr = new T[Base::size];
for (int i = 0; i < Base::size; i++) {
srand((unsigned)time(NULL));
Base::Arr[i] = static_cast <T> (rand()) % Base::size;
}
};
private:
using Base = detail::CollectionBase<T>;
};
template<> class Collection<fraction> : detail::CollectionBase<fraction>
{
public:
void ArrayGenerating() {
Base::Arr = new fraction[Base::size];
for (int i = 0; i < size; i++) {
srand((unsigned)time(NULL));
Arr[i].setNumerator(static_cast <int> (rand()) % size);
srand((unsigned)time(NULL));
Arr[i].setDenominator(static_cast <int> (rand()) % size);
}
}
private:
using Base = detail::CollectionBase<fraction>;
};
Generally, read more about template specialisation and you will certainly find the right solution:
http://en.cppreference.com/w/cpp/language/template_specialization
http://en.cppreference.com/w/cpp/language/partial_specialization
Related
I am trying to initiate an object with an array. Is there a way to do it with pointers or should i find another way to do this.
EDIT: I want to write this code with dynamic memory allocation, I know vector is better way to solve this.
#include <iostream>
template <class t>
class die {
private:
int sideCount;
t* valueOfSides;
public:
die(int side, t arr[]) {
sideCount = side;
valueOfSides = (t*)malloc(side * sizeof(t));
for (int counter; counter < side; counter++) {
valueOfSides[counter] = val[counter];
}
}
~die() {
free(valueOfSides);
}
};
int main() {
die<int> sixsided(6, {1,2,3,4,5,6});
}
The right ways to do this would be
std::vector<t> valueOfSides;
template<size_t len> die(t (&arr)[len])
: valueOfSides(std::begin(arr), std::end(arr))
{}
or
std::vector<t> valueOfSides;
die(std::initializer_list<t> arr) : valueOfSides(arr) {}
I think. Though really, the best answer is
std::vector<t> valueOfSides;
die(std::vector<t> arr) : valueOfSides(std::move(arr)) {}
One should never use raw pointers to own memory in C++, and virtually never use new or malloc. As it is, you have undefined behavior in your code because of misusing malloc.
If you're absolutely insane, or doing homework, it can be done with raw pointers, though I doubt I can get it entirely right without tests and a compiler.
template<class t>
class die {
private:
int sideCount;
t* valueOfSides;
public:
die(int side, t* arr) {
sideCount = 0;
std::size_t buffer_size = sizeof(t)*side;
char* buffer;
try {
buffer = new char[side];
valueOfSides = reinterpret_cast<t*>(buffer);
for(int i=0; i<side; i++) {
new(valueOfSides+i)t(arr[i]);
sideCount++;
}
} catch(...) {
for(int i=sideCount; i>=0; i--)
(valueOfSides+i)->~t();
delete[]buffer;
throw;
}
}
die& operator=(die&& rhs) {
sideCount = rhs.sideCount;
valueOfSides = rhs.valueOfSides;
rhs.valueOfSides = nullptr;
rhs.sideCount = 0;
return *this;
}
//die& operator=(const die& rhs) not shown because its super hard.
~die() {
for(int i=sideCount; i>=0; i--)
(valueOfSides+i)->~t();
delete[]reinterpret_cast<char*>(valueOfSides);
}
};
As we've said before, getting this stuff right is crazy hard. Use a std::vector.
Use std::vector.
#include <iostream>
#include <initalizer_list>
#include <vector>
template<class T>
class die {
public:
die() = default;
die(std::initializer_list<T> list)
: sides{list}
{ /* DO NOTHING */ }
private:
std::vector<T> sides{};
};
int main() {
die<int> sixsided({1,2,3,4,5,6});
}
One way you can do this, using more of a C technique, is a variable argument list:
#include <cstdarg>
#include <iostream>
template <class t>
class die {
private:
int sideCount;
t* valueOfSides;
public:
die(int side, ...) {
sideCount = side;
valueOfSides = new t[side];
va_list args;
va_start(args, side);
for (int counter = 0; counter < side; counter++) {
valueOfSides[counter] = va_arg(args, t);
}
va_end(args);
}
~die() {
delete[] valueOfSides;
}
};
int main() {
die<int> sixsided(6, 1,2,3,4,5,6);
}
Rather than passing an array, you're passing the parameters individually (i.e. no need for a temporary array) and using a va_list to access them.
Also, the calls to malloc and free were replaced with new and delete which is the C++ way of allocating and deallocating memory.
The C++ solution:
template <class t>
class die {
private:
int sideCount;
t* valueOfSides;
public:
die(int side, t arr[]) {
sideCount = side;
valueOfSides = new T[side]
for (int counter = 0; counter < side; counter++) { //always initialize variables
valueOfSides[i] = arr[i];
}
}
~die() {
delete[] valueOfSides;
}
};
int main() {
int arr[6] = { 1,2,3,4,5,6 };
die<int> sixsided(6, arr);
}
The new operator is like malloc and the delete and delete[] operators are like free. They are dynamic allocators.
C solution:
template <class t>
class die {
private:
int sideCount;
t* valueOfSides;
public:
die(int side, t arr[]) {
sideCount = side;
valueOfSides = (t*)malloc(side * sizeof(t));
for (int counter = 0; counter < side; counter++) { //always initialize variables
valueOfSides[i] = arr[i];
}
}
~die() {
free(valueOfSides);
}
};
int main() {
int arr[6] = { 1,2,3,4,5,6 };
die<int> sixsided(6, arr);
}
Note: in C the <iostream> header will not work, this is C++ only.
There are other containers, namely std::vector, that can work, but this is the solution for your answer.
I have to create a class template for 2 dimension array; every variable in the array would get a random value [65;90], I need to find the MAX value in the array. But in class template data type should be unspecified, so later I could use it with any - int/char etc in main().
I have tried several ways to initialize the array, however it still doesnt work. Now here is one part to put the values in the array and 2nd to print().
#include <iostream>
#include <cstdlib>
using namespace std;
template <typename T>
class Array {
private:
T **ptr;
public:
Array(T arr[7][12]);
void print();
};
template <typename T>
Array<T>::Array(T arr[7][12]) {
ptr = new T[7][12];
for(int i = 0; i < 7; i++) {
for (int j=0;j<12;j++) {
arr[i][j]=rand()%26+65;
ptr[i][j]=arr[i][j];
}
}
}
template <typename T>
void Array<T>::print() {
for(int i = 0; i < 7; i++) {
for (int j=0; j<12; j++) {
cout<<*(ptr+j)<<" ";
}
cout<<"\n";
}
cout<<endl;
}
int main() {
int arr[7][12];
Array<int> a(arr[7][12]);
a.print();
return 0;
}
If the dimensions are known at compile time and you can use std::array then you don't need to dynamically allocate the array:
#include <array>
template <typename T,unsigned M,unsigned N>
struct my_2d_array {
using row_type = std::array<T,N>;
std::array< row_type, M> data;
};
If you cannot use std::array for some reasons:
template <typename T,unsigned M,unsigned N>
struct my_2d_array {
T data[M][N];
};
Here
int arr[7][12];
Array<int> a(arr[7][12]);
you declare arr to be of size 7x12 and then access it of of bounds. The last valid element is arr[6][11] and arr[i][j] is a single element (an int) from the array.
I think that this is what you want
#include <iostream>
#include <cstdlib>
using namespace std;
template <typename T>
class Array {
private:
T **ptr;
public:
Array(T arr[][12]);
void print();
};
template <typename T>
Array<T>::Array(T arr[][12]) {
ptr = new T *[7];
for(int i = 0; i < 7; i++) {
ptr[i] = new T[12];
for (int j=0;j<12;j++) {
arr[i][j]=rand()%26+65;
ptr[i][j]=arr[i][j];
}
}
}
template <typename T>
void Array<T>::print() {
for(int i = 0; i < 7; i++) {
for (int j=0; j<12; j++) {
cout<<ptr[i][j]<<" ";
}
cout<<"\n";
}
cout<<endl;
}
int main() {
int arr[7][12];
Array<int> a(arr);
a.print();
return 0;
}
Here is ways that you can pass 2D array
Passing a 2D array to a C++ function
The class defines objects that are DIMXDIM dynamic two-dimensional arrays that contain objects of any type.
Ive added c'tor, d'tor, operator =, operator () that allows me to get the value of (2,5) column/row.
and a main that demonstrates the action of T from type float and complex.
I have tried to change the declaration of the c'tor but i think it is not the issue. im really lost
#include<iostream>
#include<cassert>
using namespace std;
//#define DIM 3
template<class T, int DIM>
class Array {
T **p;
public:
template<class T, int DIM>
class Array(T** p) {
p = new T*[DIM];
assert(p != NULL);
for (int i = 0; i < DIM; i++)
{
p[i] = new T[DIM];
assert(p[i] != NULL);
}
for (int i = 0; i < DIM; i++) {
for (int j = 0; j < DIM; j++) {
p[i][j] = 3;
}
}
}
template<class T, int DIM>
class ~Array() {
for (int i = 0; i < DIM; i++) {
delete[]p[i];
}
delete[]p;
}
template<class T, int DIM>
Array& operator=(const Array& other) {
if (this != other) {
for (int i = 0; i < DIM; i++) {
delete[]p[i];
}
delete[]p;
this.p = new T*[DIM];
assert(p != NULL);
for (int i = 0; i < DIM; i++)
{
p[i] = new T[DIM];
assert(p[i] != NULL);
}
for (int i = 0; i < DIM; i++) {
for (int j = 0; j < DIM; j++) {
p[i][j] = other.p[i][j];
}
}
}
}
};
int main() {
Array<int, 3> ob[][];
return 0;
}
E0065 expected a ';' Project C:\Users\Lorine E0070 incomplete type is not allowed Project
E0098 an array may not have elements of this type
C2988 unrecognizable template declaration/definition
C2059 syntax error: 'type'
C2334 unexpected token(s) preceding '{'; skipping apparent function body C2332 'class': missing tag name
C3306 '': unnamed class template is not allowed
C2988 unrecognizable template declaration/definition
C2143 syntax error: missing ';' before '~'
There are a few separate errors, but we'll go through them one by one.
Problem. This is the wrong syntax to define a constructor. It looks like you're defining both a class and a function at the same time, which the compiler finds very confusing.
template<class T, int DIM>
class Array(T** p) {
// stuff...
}
Correction. We already have T defined as a template parameter, so we don't need to re-define it. It should be:
Array(T** p) {
// stuff...
}
Problem. A destructor should never be templated, and you shouldn't put 'class' before it:
template<class T, int DIM>
class ~Array() {
for (int i = 0; i < DIM; i++) {
delete[]p[i];
}
delete[]p;
}
Correction. Just remove template<class T, int DIM> and class:
~Array() {
for (int i = 0; i < DIM; i++) {
delete[]p[i];
}
delete[]p;
}
Problem. Unnecessary template before = operator. You only need to template an = operator if the input type depends on the template.
template<class T, int DIM>
Array& operator=(const Array& other) {
// stuff...
}
Correction. We can just remove the template<class T, int DIM>, since it's unnecessary.
Array& operator=(const Array& other) {
// stuff...
}
Problem. You're declaring a multidimensional c-style array, without specifying the dimensions (c-style arrays must have all (or all but the first) of their dimensions specified at the point they're declared, when used as a local variable).
int main() {
Array<int, 3> ob[][];
return 0;
}
Solution. Either specify the dimensions of the array, or don't use a c-array. (I don't know which one fits your needs. If you post more information I could update the answer to clarify)
Problem. There's no default-constructor
Solution. Add a default constructor after public:
// stuff...
public:
Array() {
p = new T*[DIM];
// More stuff...
}
Problem. You immediately discard your parameter in the Array(T** p) constructor:
Array(T** p) {
p = new T*[DIM]; // WTF?? Whatever parameter was passed gets thrown out the window
assert(p != NULL);
// stuff...
}
Solution: Do something with the parameter, instead of just discarding it
Some days ago I wrote a template class which looks like this:
template <class T>
class Matrix {
private:
T ** matrix;
int n;
int m;
.
.
.
}
And constructor:
template <class T>
Matrix<T>::Matrix(int _n, int _m)
{
n = _n;
m = _m;
matrix = new T * [n];
for (int i = 0; i < n; i ++)
{
matrix[i] = new T[m];
}
}
And right now I would like to create a destructor like this:
template <class T>
aghMatrix<T>::~aghMatrix()
{
for (int i = 0; i < n; i ++)
{
delete [] matrix[i];
}
}
At first I thought it'd solve all problems but I was wrong.
In function main:
Matrix<int> a; //destructor works find
Matrix<int*>a; //error destructor
How to solve this problem?
I will assume that this is a coding exercise of some kind. For a real world application you should not write your own matrix implementations but rather rely on containers found in the standard library or on one of the many matrix libraries out there.
The example that was posted had several problems and wouldn't even compile. So let me just start by giving a minimal solution:
template <class T>
class Matrix {
public:
Matrix(int _n, int _m)
: n(_n), m(_m), matrix(new T*[n]) // always initialize your members
{
for (int i=0; i<n; i++)
{
matrix[i] = new T[m];
}
}
~Matrix()
{
for (int i=0; i<n; i++)
{
delete[] matrix[i];
}
delete[] matrix; // this deletes the first level
}
private:
int n;
int m;
T ** matrix;
};
What should be learnt from this is:
Make sure you initialize every class member in the constructor's
initializer list for safety and performance reasons
Do not forget to delete the memory pointed to by your first level pointers (last line in destructor)
Do not use explicit new and delete if you don't have to
What about copy and move semantics? They are defined but won't do what they should.
In order to make use of RAII and to avoid explicit delete you can use std::unique_ptr instead. The equivalent code now looks like this:
#include <memory>
template <class T>
class Matrix2 {
public:
Matrix2(int _n, int _m)
: n(_n), m(_m), matrix(new T[n * m])
{}
private:
int n;
int m;
std::unique_ptr<T> matrix;
};
Much simpler and less error prone. The unique pointer is now taking care of the resource management. Note that I allocate n * m objects of type T which means your matrix access operator will look like this:
T operator()(int i, int j)
{
return matrix.get()[i * n + j];
}
The unique_ptr can be moved but not copied which means you can now safely move Matrix2 but not copy. Copy semantics must be defined explicitly:
Matrix2(const Matrix2& other)
: n(other.n), m(other.m), matrix(new T[n * m])
{
std::copy(other.matrix.get(), other.matrix.get() + n * m, matrix.get());
}
Matrix2& operator=(const Matrix2& other)
{
if (this != &other)
{
n = other.n;
m = other.m;
matrix.reset(new T[n * m]);
std::copy(other.matrix.get(), other.matrix.get() + n * m, matrix.get());
}
return *this;
}
Note that this code is for demo purposes only and still lacks important aspects and should not be used in a real application.
Let's say I have a base class template MyBase:
template <class T>
class MyBase{
private:
T data;
public:
MyBase(T _data);
};
I want to subclass this twice (at least for now):
data should be a dynamic 2-dimensional array: T **data
data should be a fixed 2-dimensional array: T data[rows][cols]
I'm still a bit of a novice with C++, and I can't figure out how to do this.
Specifically, I want to make a sort of matrix library (primarily as a learning project). I've done some things in the past where having my matrix stored dynamically made more sense, and vice versa. So, it seems like a good solution would be to implement a base class that provides all the common functionality (insert(T item, int i, int j), for example, should use data[i][j] = item; in either case), then subclass a DynamicMatrix and a FixedMatrix. The DynamicMatrix would have a constructor that did
data = new T*[rows];
for (int i = 0; i < rows; i++)
{
data[i] = new T[cols];
}
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
data[i][j] = 0;
}
}
And FixedMatrix just:
for (i=0; i < rows; i++)
{
for (j=0; j < cols; j++)
{
data[i][j] = 0;
}
}
Creating a member variable T data; in the base class is easy enough. But then in the subclasses, how do I convert that to a double pointer? Perhaps I can't, I'm okay with that. But then what should I do instead?
Here you are trying to use inheritance for code reuse which, in my opinion, is not a good approach to design; inheritance is for freedom of implementation while composition is for code reuse.
In this case, if it were really necessary to support these different cases, I would formalize a 2d array:
template<typename T> class Array2D {
public:
virtual const T* operator[](int row_index) const = 0;
virtual T* operator[](int row_index) = 0;
virtual size_t rows() const = 0;
virtual size_t cols() const = 0;
};
Then I would provide the implementations of Array2D that you've specified:
template<typename T, int R, int C> class FixedArray2D : public Array2D {
public:
virtual const T* operator[](int row_index) const {
return &data_[row_index][0];
}
virtual T* operator[](int row_index) {
return &data_[row_index][0];
}
virtual size_t rows() const { return R; }
virtual size_t cols() const { return C; }
private:
T data_[R][C];
};
template<typename T> class DynamicArray2D : public Array2D {
public:
DynamicAray2D(int rows, int cols) {
// ...
}
// ...
};
At this point, you can instantiate an Array2D using either format. Now whatever code you are using can simply take a const Array2D& or an Array2D& wherever it needs to deal with such an object.
That said, I think this is probably unnecessary complexity in that a dynamically sized array will work for either case, hence I would just go with that unless there were a compelling reason to support both types.