There are some Classes: Array, NumericArray. Array is a template class, and NumericArray is a class inherited from Array designed to take int, double, etc.
Part of Header of NumericArray:
template <class T = int>
class NumericArray : public Array<T>{
private:
T* m_data;
int size;
public:
NumericArray<T> operator * (T factor)const;
};
here are constructors and some functions of NumericArray:
template <class T>
NumericArray<T>::NumericArray(){
m_data = new T[10];
size = 10;
}
template <class T>
NumericArray<T>::NumericArray(int n){
m_data = new T[n];
size = n;
}
template <class T>
NumericArray<T>::NumericArray(const NumericArray<T>& s_data){
m_data = new T[s_data.size];
// assign elements in the source array
for (int i = 0;i<=(s_data.Size()-1 ); i++){
m_data[i] = s_data.m_data[i];
}
size = s_data.Size();
}
/* Destructor */
template <class T>
NumericArray<T>::~NumericArray(){
delete [] m_data;
}
template <class T>
NumericArray<T> NumericArray<T>::operator * (T factor)const{
NumericArray<T> temp(size);
for (int i = 0; i<size;i++){
temp.m_data[i] = (*this)[i] *factor;
}
return temp;
}
And when I call it in the main(), something weird happens. For example:
NumericArray<int> intArray1(10);
NumericArray<int> intArray2;
for(int i =0; i<10;i++){
intArray1[i] = i;
intArray2[i] = i;
}
The 2 arrays do contain numbers 0-9, but if I call
NumericArray intArray4 = intArray1*2;
intArray4 consists of zero(0)s. It seems that the default constructor is called in the function and passed to Array4. And after the operator, Array1 and Array2 are still numbers 0-9
Below are the related code of Array
template class Array{
private:
T* m_data;
int size;
public:
Array(); // constructor
Array(int n); // constructor
Array(const Array<T>& s_data); //Copy Constructor
virtual ~Array(); // destructor
void SetElement(int i, const T& source);
T& GetElement(int i)const;
int Size() const;
int DefaultSize()const;
void DefaultSize(int n);
// Operator overloading
Array<T>& operator = (const Array<T>& source) ;
T& operator [](int i);
const T& operator [] (int i) const;
};
template <class T>
Array<T>::Array(){
// default constructor
m_data = new T[defaultSize]; // initialize T*
size = defaultSize; // initialize integer
}
template <class T>
Array<T>::Array(int n){
// Constructor with arguments
m_data = new T[n];
size = n;
}
template <class T>
Array<T>::Array(const Array<T>& s_data){
// Copy constructor
m_data = new T[s_data.Size()];
// assign elements in the source array
for (int i = 0;i<=(s_data.Size()-1 ); i++){
m_data[i] = T( s_data.m_data[i]);
}
size = s_data.Size();
defaultSize = s_data.Size();
}
template <class T>
T& Array<T>::operator [](int i) {
if (i > size|| i<0){
OutOfBoundsException a;
throw a;
}
return m_data[i];
}
Not sure if provided enough information. Any hint is greatly appreciated.
The easiest way to access base class data members when the base is a (dependent) class template, is a using declaration like this:
#include <iostream>
using namespace std;
template< class Item >
class Base
{
protected:
Item item_;
Base( Item const& v ): item_( v ) {}
};
template< class Item >
class Derived
: public Base< Item >
{
protected:
using Base<Item>::item_;
public:
auto value() const -> Item { return item_; }
Derived( Item const& v ): Base<Item>( v ) {}
};
auto main() -> int
{
Derived<int> const x( 42 );
cout << x.value() << endl;
}
Alternatively you can qualify the access, e.g. this->item_ or Base<Item>::item_.
That said, it’s usually not a good idea to let derived classes access base class data members directly.
Here is the problem: both NumericArray and Array have
T* m_data;
int size;
The function Array::operator[] is called from Array which uses Array::m_data, however the NumericArray::operator* sets NumericAray::m_data. It probably is working as you would expect, but you are reading from the wrong pointer.
Remove the members from NumericArray and make the members protected instead of private in Array. The second part is optional if the implementation is changed a little bit.
Related
I create a class Vector that contain two variables that are template variable, I am trying to build such a dictionary that tell mark of a specific student.
The problem is I am struggling dynamic allocating memory with template. I have to do this without map or STL help. Can you explain, how to allocate them properly.
#define DEF_CAPACITY 20
template <class U, class T>
class Vector {
protected:
T* _data;
U* _keys;
int _size; //size in use
int _capacity; //available capacity
public:
//constructors
Vector(int capacity = DEF_CAPACITY);
~Vector();
int getSize() const { return size; }
void insert(U key, T data);
T operator[](U key);
};
template<class U, class T>
inline Vector<U, T>::Vector(int capacity)
{
this->_capacity = capacity;
this->_size = 0;
}
template<class U, class T>
Vector<U, T>::~Vector()
{
if (_data)
delete[] _data;
if (_keys)
delete[] _keys;
}
template<class U, class T>
void Vector<U, T>::insert(U key, T data)
{
_keys[_size] = new U;
//Maybe I have to do something like that, but all options I test doesn't work
//keys[_size] = new U[Some size];
_keys[_size] = key;
_data[_size] = new T;
_data[_size] = data;
_size++;
}
template<class U, class T>
T Vector<U, T>::operator[](U key)
{
int index = 0;
for (int i = 0; i < size; i++)
if (_keys[i] == key)
index = i;
return _data[index];
}
int main() {
Vector<string, int> grades;
grades.insert("john", 90);
grades.insert("marc", 100);
grades.insert("ron", 87);
grades.insert("lynda", 95);
//...
grades.insert("Tome", 93);
//...
cout << grades["marc"] << endl;
cout << grades["lynda"] << endl;
cout << grades["john"] << endl;
return 0;
}
To allocate n elements of type T you use:
T* array = new T[n];
so to allocate space for your keys and values:
// be aware: this will call the constructor for each element!!!
_keys = new U[n];
_data = new T[n];
If your "Vector" has a fixed capacity, this should be done in your constructor:
template<class U, class T>
inline Vector<U, T>::Vector(int capacity)
: _data(new T[capacity]);
, _keys(new U[capacity]);
, _size(0);
, _capacity(capacity);
{
}
after that, you can insert key/value pairs like this:
template<class U, class T>
void Vector<U, T>::insert(const U& key, const T& data)
{
if(_size == _capacity)
throw std::out_of_range("no space left!!!");
_keys[_size] = key; // copy assignment
_data[_size] = data; // copy assignment
_size++;
}
This design will unnecessarily call constructors for unused keys and values.
You could also do this with malloc and free to prevent this, though I wouldn't recommend going that way and instead use the standard library.
hello i want to create simple array class to get value and insert value like (array[0] = 4) and this is my program but i have problem to use [] = in same time for insert
template <typename Param>
class arr
{
private:
int Last_point = 0;
Param Data[];
public:
void& operator[]=(int Element_id, Param v)
{
Data[Element_id] = v;
}
Param& operator[] (int Element_id)
{
return Data[Element_id];
}
};
void main()
{
arr <int> Array;
Array[1] = 555;
cout << "Is(" << to_string(Array[1]) << ")" << endl;
system("pause");
}
is there any operator like ([]=)? or for this, i have to use which methods? also i want to get value if just used []
The syntax you are attempting for the operator[] functions is quite wrong. You need something like:
// Version for non-const objects
Param& operator[](std::size_t i)
{
return Data[i];
}
// Version for const objects
Param const& operator[](std::size_t i) const
{
return Data[i];
}
If you want to support arrays whose sizes are known at compile time, you can use:
template <typename Param, std::size_t N>
class arr
{
private:
Param Data[N];
public:
Param& operator[](std::size_t i)
{
return Data[i];
}
Param const& operator[](std::size_t i) const
{
return Data[i];
}
};
If you want to support arrays whose sizes are known at run time, you can use the following. However, you need to be aware of The Rule of Three and make sure to implement the copy constructor and the copy assignment operator properly.
template <typename Param>
class arr
{
private:
Param* Data;
public:
arr(size_t size) : Data(new Param[size]) {}
~arr() { delete [] Data; }
Param& operator[](std::size_t i)
{
return Data[i];
}
Param const& operator[](std::size_t i) const
{
return Data[i];
}
};
Foo& operator[] is sufficient for reading and writing.
Include the size of the array as a template parameter, or replace Param[] with std::vector<Param>.
Use size_t instead of int for array index types.
You don't need to wrap Array[1] in to_string for output.
Don't use void main! The standard says main must be int.
void& is not valid C++ either.
#include <iostream>
using namespace std;
template <typename Param, size_t Size> class arr {
private:
Param Data[Size];
public:
Param &operator[](size_t Element_id) {
return Data[Element_id];
}
};
int main() {
arr<int, 3> Array;
Array[1] = 555;
cout << "Is(" << Array[1] << ")" << endl;
}
However, all that arr does in my snippet is be a less useful std::array!
I've been getting this error for some time, and I have no clue how to fix it.
I searched for similar problem here on stack overflow, but I've failed to find anything.
Source code:
template <typename T>
class Dynamic_Array
{
private:
T* actual_array;
unsigned int number_of_elements;
public:
Dynamic_Array() {}
~Dynamic_Array() {delete[] actual_array;}
unsigned int get_size() const {return number_of_elements;}
T& operator [](unsigned int index) {return actual_array[index];}
void operator +=(T&);
void operator -=(unsigned int);
};
template <typename T> /*Not sure if this is needed, but compiler doesn't mind, still prints the same error*/
void Dynamic_Array<T>::operator+=(T& object)
{
if(number_of_elements>1)
{
T* temp_array = new T[number_of_elements];
for(unsigned int i=0;i<number_of_elements;i++)
{
temp_array[i]=actual_array[i];
}
delete[] actual_array;
actual_array = new T[number_of_elements+1];
for(unsigned int i=0;i<number_of_elements;i++)
{
actual_array[i]=temp_array[i];
}
delete [] temp_array;
temp_array=NULL;
actual_array[number_of_elements]=object;
number_of_elements++;
}
else
{
number_of_elements++;
actual_array = new T[1];
}
}
void Dynamic_Array<T>::operator-=(unsigned int index)
{
T* temp_array = new T[number_of_elements-1];
for(unsigned int i=0, j=0;i<number_of_elements;i++)
{
if(i!=index)
{
temp_array[j]=actual_array[i];
j++;
}
}
delete[] actual_array;
number_of_elements--;
actual_array = new T[number_of_elements];
for(unsigned int i=0;i<number_of_elements;i++)
{
actual_array[i]=temp_array[i];
}
delete [] temp_array;
temp_array = NULL;
}
According to compiler, the error is present in line 18 (the empty one between "};" and "template"
As I said, I have no idea what I screwed up, so any help is appreciated.
When you define member functions outside of a class template declaration then you need to specify the template for each function. When you define
void Dynamic_Array<T>::operator-=(unsigned int index)
{
//...
}
You need to have the template part as well like
template <typename T>
void Dynamic_Array<T>::operator-=(unsigned int index)
{
//...
}
This has to be present for every function definition that you do out of line. A single template <typename T> at the start of all the definition does not apply to all of the function definitions.
Dynamic_Array is a template class so when defining operator+= and operator-= outside the scope of the class you need to provide template type as follows:
template<typename T> void Dynamic_Array<T>::operator+=(T& object) {
//...
}
template<typename T> void Dynamic_Array<T>::operator-=(unsigned int index) {
//...
}
Also, I should note that it is somewhat odd to have void as a return type for operator+= and operator-=, typically you should return a reference to the altered instance of this, i.e:
template<typename T> Dynamic_Array<T>& Dynamic_Array<T>::operator+=(const T& object) {
//...
}
I want to design a class PrimitiveType which serves as an abstract class for mathematical entities such as scalar, vector, tensor, and so on to store them in a std::vector<PrimitiveType *> myVector through which I can iterate. For example, having two of these vectors of identical size, say myVector1 and myVector2, I want to be able to do something like
for (size_t i = 0; i < myVector1.size(); i++)
myVector1[i] += myVector2[i];
and don't want to care whether I'm adding scalars, vectors, or tensors. Up to now, I came up with
#include <algorithm>
#include <cstddef>
#include <iostream>
template<class T> class Scalar;
template<class T>
class PrimitiveType
{
protected:
size_t size_;
T *value_;
public:
virtual ~PrimitiveType() = 0;
PrimitiveType & operator+=(const PrimitiveType &primitiveType)
{
for (size_t i = 0; i < size_; i++)
value_[i] += primitiveType.value_[i];
return *this;
}
};
template<class T> PrimitiveType<T>::~PrimitiveType() {};
template<class T>
class Scalar : public PrimitiveType<T>
{
using PrimitiveType<T>::size_;
using PrimitiveType<T>::value_;
public:
Scalar(T value = 0.0)
{
size_ = 1;
value_ = new T(value);
}
~Scalar() { delete value_; }
operator T &() { return *value_; }
};
template<class T>
class Vector : public PrimitiveType<T>
{
using PrimitiveType<T>::size_;
using PrimitiveType<T>::value_;
public:
Vector(T value = 0.0)
{
size_ = 3;
value_ = new T[size_];
std::fill(value_, size_, value);
}
~Vector() { delete[] value_; }
T & operator()(size_t index) { return value_[index]; }
};
int main()
{
Scalar<double> s(3.2);
std::cout << s << std::endl;
static const size_t size = 3;
std::vector<PrimitiveType<double> *> p = std::vector<PrimitiveType<double> *>(size);
for (size_t i = 0; i < size; i++)
{
p[i] = new Scalar<double>();
*(p[i]) += s;
std::cout << *static_cast<Scalar<double> *>(p[i]) << std::endl;
}
}
but I don't think this is a very clean solution. In particular,
1) I would like to be able to use initializer lists in the child classes but get problems with dependent name lookup, e.g.
error: ‘using PrimitiveType::size_’ is not a non-static data member of ‘Scalar’
How to realize something like Scalar(T value = 0.0) : size_(1) , value_(new T(value)) {}?
2) I would actually prefer to make value_ a static array because I know at compile time what size value_ has for Scalar, Vector, ... Of course, this does not hold for PrimitiveType, however, an instance of PrimitiveType gets never created.
Edit: Complete edit because other solution was not ok.
Well, the simplest way for your problem would be to move the storage from the main class to the base class and provide accessor of element:
template <class C>
class PrimitiveType {
public:
PrimitiveType & operator+=(const PrimitiveType &primitiveType) {
if (this->_size() != primitiveType._size()) {
throw "Incompatible type." ;
}
for (size_t i = 0 ; i < this->_size() ; ++i) {
this->_get(i) += primitiveType._get(i) ;
}
return *this ;
}
protected:
virtual C& _get (size_t) = 0 ;
virtual C _get(size_t) const = 0 ;
virtual size_t _size () const = 0 ;
};
Then in Scalar and Vector for example:
template <class C>
class Scalar : PrimitiveType <C> {
C _value ;
public:
Scalar (C const& c) : _value(c) { }
protected:
virtual C& _get (size_t) = 0 { return _value ; }
virtual C _get(size_t) const = 0 { return _value ; }
virtual size_t _size () const = 0 { return 1 ; }
};
template <class C, int N = 3>
class Vector : PrimitiveType <C> {
std::array <C, N> _values ;
public:
Scalar (std::initializer_list <C> l) : _values(l) { }
protected:
virtual C& _get (size_t i) = 0 { return _values(i) ; }
virtual C _get(size_t i) const = 0 { return _values(i) ; }
virtual size_t _size () const = 0 { return _values.size() ; }
};
End of edit.
For your first question, just add a protected constructor in PrimitiveType and call it from your child class:
class PrimitiveType {
protected:
PrimitiveType (/* */) : _values(/* */), /* ... */ { }
};
class Scalar {
public:
Scalar (/* */) : PrimitiveType(/* */) { }
}
For your second questions, add a storage type as second argument templates of primitive type:
template <class C, class S = std::vector <C>>
class PrimitiveType { /* */ }
template <class C>
class Scalar : public PrimitiveType <C, std::array <C, 1>> { /* */ }
Detailled example:
template <class C, class S = std::vector <C>>
class PrimitiveType {
public:
PrimitiveType & operator+=(const PrimitiveType &primitiveType) {
/** Same code as yours. **/
}
protected:
S _values ;
PrimitiveType (std::initializer_list <C> l) : _values(l) { }
};
template <class C>
class Scalar : public PrimitiveType <C, std::array <C, 1>> {
public:
Scalar (C const& c) : PrimitiveType({c}) { }
};
I'm starting to learn c++ but I'm stuck in the destructor. We need to implement a vector and this is what I have so far.
#include<string.h>
#include<cassert>
#include<iostream>
using namespace std;
template<class T>
class Vector {
template<class U> friend ostream& operator<<(ostream&, const Vector<U>&);
private:
T* data;
unsigned len;
unsigned capacity;
public:
Vector(unsigned = 10);
Vector(const Vector<T>&);
virtual ~Vector(void);
Vector<T>& operator =(const Vector<T>&);
bool operator==(const Vector<T>&);
T& operator[](unsigned);
};
//PROBLEM!
template <class T>
~ Vector() {
delete data;
}
template<class T>
Vector<T>::Vector(unsigned int _capacity)
{
capacity = _capacity;
len = _capacity;
data = new T[_capacity];
}
template<class T>
Vector<T>::Vector(const Vector<T> & v)
{
len = v.len;
capacity = v.capacity;
data = new T[len];
for (unsigned int i = 0; i < len; i++)
data[i] = v.data[i];
}
template<class T>
Vector<T> & Vector<T>::operator = (const Vector<T> & v)
{
delete[ ] data;
len = v.len;
capacity = v.capacity;
data = new T [len];
for (unsigned int i = 0; i < len; i++)
data[i] = v.data[i];
return *this;
}
template<class T>
bool Vector<T>::operator == (const Vector<T> & v)
{
bool check = true;
check &= (len == v.len);
if (!check) return false;
check &= (capacity == v.capacity);
if (!check) return false;
for (unsigned int i = 0; i < len; i++) {
check &= (data[i] == v.data[i]);
if (!check) return false;
}
return true;
}
template<class T>
T& Vector<T>::operator[](unsigned int index)
{
return data[index];
}
The interface is given and I need to implement it. But this is so different from C and Java, that I'm a bit lost.
In the second exercise we need to implement something like this using a) the previous Vector implementation as derived class and b) the Vector as composition class, so maybe we will use the virtual destructor in one of the approaches?
void testAssociativeArray() {
AssociativeArray<String, int> table;
table["abc"] = 15;
table["jkl"] = 12;
table["xyz"] = 85;
assert(table["jkl"], 12);
}
template<class P, class Q>
class Pair {
P p;
Q q; public:
Pair(const P& _p = P(), const Q& _q = Q()): p(_p), q(_q) {}
P& objectP() {return p;}
Q& objectQ() {return q;}
};
First off, why do you think that the destructor should be virtual? Are you using polymorphism?
Second, you are using delete incorrectly for your array.
Since you used:
data = new T[length];
You must use the array syntax:
delete [] data;
Third, you need to put the namespace in front of all of your class function definitions:
template <class T>
Vector<T>::~Vector()
{
delete [] data;
}
And just for your information, you declare the destructor like so...
virtual ~Vector(void);
As I mentioned, virtual is unnecessary unless you are using this class as a base or derived class in a polymorphic manner. For more information on when you need to use virtual destructors, look at the answer to this question.
In addition, the void in the parameters is also unnecessary. This used to be required in old C standard, but it is not in C++.
You should be able to declare it like so:
~Vector();
If you define AssociativeArray<P,Q> with a has-a relationship to Vector<T>, then you can simply make the class contain a Vector<Pair<P,Q> >. Declaring virtual methods in this case, are not needed, but can still be used--with some extra overhead.
If you define AssociativeArray<P,Q> with a is-a relationship to Vector<Pair<P,Q> >, then you should define some virtual methods in Vector<T>, including a virtual destructor.
The use of virtual methods only matters when using objects polymorphically through pointers and references. See this page.
AssociativeArray<String,Int>* myDerivedMap = new AssociativeArray<String,Int>();
delete myDerivedMap; //NO virtual methods necessary here. using a pointer to derived class
Vector<Pair<String,Int> >* myBaseMap = new AssociativeArray<String,Int>();
delete myBaseMap; //virtual methods ARE necessary here. using a pointer to base class
template<class T>
Vector<T>::~Vector()
{
delete [] data;
}
Note that you must use delete [] and not delete
Should be
template <class T>
Vector<T>::~Vector() {
delete[] data;
}