#include <iostream>
using namespace std;
template<class T>
class Array {
public: // should be private, big ignore that
int n;
T *arr;
public:
Array(int sz, T initValue) {
n = sz;
arr = new T[n];
for (int i=0; i<n; i++) arr[i] = initValue;
}
Array& operator = (const Array& b) {
if (this!=&b) {
delete[] arr;
n = b.n;
arr = new T[n];
for (int i=0;i<n;i++) arr[i] = b.arr[i];
}
return *this;
}
Array operator + (const Array& b) {
Array res(n, 0);
for (int i=0; i<n;i++) res.arr[i] = arr[i] + b.arr[i];
return res;
}
};
int main()
{
Array<double> a(10, 1); //Array<double> b(10, 2); // this works
Array<int> b(10, 2);
a = b; // error
for (int i=0; i<10; i++) cout << i << " " << a.arr[i] << "\n";
Array<double> c(10,0);
c = a + b; // error if b is <int>, runs if b is <double>
c = a - b;
c = a * b;
}
So I have a template class that can takes int, float, double, ...
Intuitively, Array<double> a; Array<int> b; a = b; should be possible because element-wise, we can do a[i] = b[i]. However, I have the conversion error because something is missing.
How can I make a = b; possible? Thank you.
Edit: the point is not about making an Array. It can be a Matrix, 3dArray, etc. It's about assignment of a float template and int template. You can also replace int with float, and float with highPrecisionFloat, for example.
Edit 2: I forgot to mention, I not just only need operator =, but operator + (and - * /, etc) as well. If I user #churill answer, I need to do so for each operator. How can I make conversion from Array to Array implicit?
In the class template
template<class T>
class Array { ... }
The identifier Array refers actually to Array<T>. You will have to make operator== a template and you probably want to add an explicit cast:
template<typename TOther>
Array<T> &operator = (const Array<TOther>& b) {
if constexpr (std::is_same<T, TOther>::value) {
// only check for self-assignment T and TOther are the same type
if (this == &b)
{
return *this;
}
}
delete[] arr;
n = b.n;
arr = new T[n];
for (int i=0;i<n;i++)
arr[i] = static_cast<T>(b.arr[i]);
return *this;
}
Note that std::is_same is from the type_traits-header.
Related
I have a very simple code where I am trying to create class template. Unfortunately, I am getting error with my code for the friend function.
In the following code 'myArray' as a template class. How can I handle the friend function operator *(...) in this scenario? With my current code, I get following error:
compilation error:error: invalid use of template-name 'myArray'
without an argument list myArray operator * (myArray &a1, myArray &a2)*/
Here is the code:
#include<iostream>
using namespace std;
const int sz = 3;
template <typename T>
class myArray
{
T *arr;
const static int size = 3;
public:
myArray()
{
arr = new T[size];
for (int i=0; i<size; i++)
arr[i] = 0;
}
myArray(T *actArray)
{
arr = new T[size];
for (int i=0; i<size; i++)
arr[i] = actArray[i];
}
void prArray()
{
cout<<endl<<endl;
for (int i=0; i<size; i++)
cout << "arr [" << i << "] = " << arr[i] << endl;
}
friend myArray operator * (myArray &arr1, myArray &arr2);
};
myArray operator * (myArray &a1, myArray &a2)
{
myArray product;
for (int i=0; i<sz; i++)
product.arr[i] = a1.arr[i] * a2.arr[i];
return product;
}
int main()
{
int xi[3] = {1, 2, 3};
int yi[3] = {5, 5, 5};
float xf[3] = {1.1, 2.1, 3.1};
float yf[3] = {5.5, 5.5, 5.5};
//considering template class as integer
myArray <int>a1;
myArray <int>a2;
a1 = xi;
a2 = yi;
a1.prArray();
a2.prArray();
cout<<"Interger class..."<<endl;
myArray <int>a3;
a3 = a1 * a2;
a3.prArray();
/*//considering template class as float
myArray <float>b1, <float>b2;
b1 = xi;
b2 = yi;
b1.prArray();
b2.prArray();
cout<<"Float class..."<<endl;
myArray <float>b3;
b3 = b1 * b2;
b3.prArray();*/
}
Move the body of operator* into the body of the class:
friend myArray operator * (myArray &arr1, myArray &arr2) {
myArray product;
for (int i=0; i<sz; i++)
product.arr[i] = a1.arr[i] * a2.arr[i];
return product;
}
Also:
myArray operator*=(myArray const& arr2)& {
for (int i=0; i<sz; i++)
arr[i] *= a2.arr[i];
return *this;
}
friend myArray operator * (myArray arr1, myArray const& arr2) {
arr1*=arr2;
return arr1;
}
with efficient move this reduces temporary objects created.
//Finally I define the friend function in the class itself along with the suggestions made by Peter.... so the final code is...Thanks all for your help
But still didn't understand why we made it as const parameters...?
#include<iostream>
using namespace std;
template <typename T>
class myArray
{
T *arr;
const static int size = 3;
public:
myArray()
{
arr = new T[size];
for (int i=0; i<size; i++)
arr[i] = 0;
}
myArray(T *actArray)
{
arr = new T[size];
for (int i=0; i<size; i++)
arr[i] = actArray[i];
}
void prArray()
{
cout<<endl<<endl;
for (int i=0; i<size; i++)
cout << "arr [" << i << "] = " << arr[i] << endl;
}
friend myArray<T> operator* (const myArray<T>& a1, const myArray<T>& a2)
{
myArray <T> product;
for (int i=0; i<size; i++)
product.arr[i] = a1.arr[i] * a2.arr[i];
return product;
}
};
int main()
{
int xi[3] = {1, 2, 3};
int yi[3] = {5, 5, 5};
float xf[3] = {1.1, 2.1, 3.1};
float yf[3] = {5.5, 5.5, 5.5};
//considering template class as integer
myArray <int>a1;
myArray <int>a2;
a1 = xi;
a2 = yi;
a1.prArray();
a2.prArray();
cout<<"Interger class..."<<endl;
myArray <int>a3;
a3 = a1 * a2;
a3.prArray();
//considering template class as float
myArray <float>b1;
myArray <float>b2;
b1 = xf;
b2 = yf;
b1.prArray();
b2.prArray();
cout<<"Float class..."<<endl;
myArray <float>b3;
b3 = b1 * b2;
b3.prArray();
}
I am trying to create a member function which print out the array that I control, but I am running into Seg fault. Any help would be really useful!
Here is my header file, all the code in there work except the last member function.
#include <iostream>
#include <assert.h>
using namespace std;
#ifndef _ARRAY_H
#define _ARRAY_H
template<class T>
class Array{
private:
T *a;
int length;
public:
// constructor
Array (int len){
length = len;
a = new T[length];
for (int i = 0; i < len; i++){
a[i]=0;
}
}
// destructor
~Array()
{delete[] a;}
// operator overload
T& operator [](int i){
assert (i>=0 && i < length);
return a[i];
}
// operator overload
Array<T>& operator=(Array<T> &b){
if (a !=nullptr) delete[] a;
a = b.a;
b.a = nullptr;
length = b.length;
return *this;
}
//get the length of the array
int arraylength(){
return length;
}
//------------------This below is where I am having issue --------//
//print out the array
Array<T> printarray(){
for (int i = 0; i < length; i++){
cout << a[i];
}
}
};
int main();
#endif
This is my main file
#include <iostream>
#include "../include/array.h"
using namespace std;
int main(){
// initialize array
Array <int> a(5);
Array <int> b(5);
// put stuff into array
for (int i = 0; i< a.arraylength(); i++){
a[i] = i;
}
// set b = a using operator overload
b = a;
// print out the result b array
for (int i = 0; i < b.arraylength(); i++){
cout << b[i] << endl;
}
a.printarray();
return 0;
}
Again. Thank you for the help, I am quite new to C++ and mostly self taught.
In this statement
b = a;
you have called operator= in which a pointer of a object was set to nullptr, but in printArray you don't check if a is not null, so you are accesing data for null pointer, it is undefined behaviour. Add the condition to check if array is not empty:
void printarray(){
if (!a) return; // <- array is empty
for (int i = 0; i < length; i++){
cout << a[i];
}
}
Secondly, return type of printArray should be void, you don't return any value in this function.
You should fix printarray by changing the return type to void and making it a const member function.
void printarray() const {
for (int i = 0; i < length; i++){
cout << a[i];
}
}
However, that is not the main problem in your code. The main problem is that you are not following the The Rule of Three.
You don't have copy constructor.
You have a copy assignment operator but it is not implemented properly.
The line
b = a;
causes problems downstream that can be fixed by following The Rule of Three.
Here's an implementation of the copy assignment operator function that should work.
// Make the RHS of the operator a const object.
Array<T>& operator=(Array<T> const& b)
{
// Prevent self assignment.
// Do the real assignment only when the objects are different.
if ( this != &b )
{
if (a != nullptr)
{
delete[] a;
a = nullptr;
}
// This is not appropriate.
// a = b.a;
// b.a = nullptr;
// b needs to be left untouched.
// Memory needs to be allocated for this->a.
length = b.length;
if ( length > 0 )
{
a = new T[length];
// Copy values from b to this.
for (int i = 0; i < length; ++i )
{
a[i] = b.a[i];
}
}
}
return *this;
}
Please note that you should implement the copy constructor also, and then use the copy swap idiam to implment the assignment operator.
Very relevant: What is the copy-and-swap idiom?
Hello everyone i'm trying to write an assignment operator for this class so i can assign an array like thisint[] = {0, 1, 2, 3} to my Tableau class
originally i wanted to do this
Tableau<T>& operator=(T arr[])
{
return Tableau(tab, sizeofarray);
}
because i already wrote a constructor that takes and array and the size as its argument
and i ran into a problem with the size of the the array i don't know how to find it
how can i find the size of the array or is there a better way to do this
template<typename T>
class Tableau
{
public:
Tableau(int s = 0) : size(s), ptr(new T[size])
{
for (int i = 0; i < size; i++)
{
ptr[i] = 0;
}
}
Tableau(T tab[], int s = 0) : size(s), ptr(new T[size])
{
for (int i = 0; i < size; i++)
{
ptr[i] = tab[i];
}
}
~Tableau()
{
delete[] ptr;
}
Tableau<T>& operator=( T tab[])
{
}
T commule()
{
T com = 0;
for (int i = 0; i < size; i++)
{
com += ptr[i];
}
return com;
}
T& operator[](const int index)
{
return ptr[index];
}
private:
int size;
T* ptr;
};
int main()
{
int k[] = { 8, 12, 5, 9, 55};
Tableau<int> TI(k, 2);
TI = k;
return 0;
}
You can use:
template <std::size_t N>
Tableau<T>& operator=(T (&arr)[N])
{
// This is not right.
// The returned value is a temporary.
// return Tableau(arr, N);
// Update the contents of the object.
// ...
// Then, return a reference to this object.
return *this;
}
With that member function template, when you invoke:
int k[] = { 8, 12, 5, 9, 55};
Tableau<int> TI(k, 2);
TI = k;
The operator= function is instantiated with N = 5 and k as the value of arr. Hence, you get the size of the array as well as the contents of the array.
However, it is worth pointing out that if you use:
int k[] = { 8, 12, 5, 9, 55};
int* k2 = k;
Tableau<int> TI(k, 2);
TI = k2;
it won't work. k2 is not an array. It is a pointer to an int, which happens to point to the first element of k.
This is example from a text book. We are creating vector using templates. in main function we copy the predefined array into vectors. Finally, we multiply two vectors. Although program compiles nicely the program fails to execute. Whats wrong with the code.
#include <iostream>
const int size = 3;
template<class T>
class vector
{
T* v;
public:
vector()
{
v = new T[size];
for (int i = 0; i < size; i++){
v[i] = 0;
}
}
vector(const T* a)
{
for (int i = 0; i < size; i++){
v[i] = a[i];
}
}
T operator * (const vector& y)
{
T sum = 0;
for (int i = 0; i < size; i++){
sum += this->v[i] * y.v[i];
}
return sum;
}
};
int main()
{
int x[3] = { 1, 2, 3 };
int y[3] = { 4, 5, 6 };
vector<int> v1;
vector<int> v2;
v1 = x;
v2 = y;
int R = v1 * v2;
std::cout << R;
return 0;
}
First of all in this constructor
vector(T *a)
{
for(int i=0;i<size;i++){
v[i]= a[i];
}
}
you did not allocate the array pointed to by v. Pointer v is not initialized. So the constructor has undefined behaviour.
And another potential problem is that you did not define the copy assignment operator.
In these statements
v1 = x; v2 = y;
temporary objects of type vector are created and after the assignment they will be deleted. Thus the new created objects will have invalid pointer v.
You have to define at least copy constructor, copy assignment operator and destructor.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Operator[][] overload
I have made class which contains an array containing (in one row) all the numbers from the given 2d array. For example given: {{1,2}{3,4}} the b field in the object of class T contains {1,2,3,4}. I would like to overload[][] operator for this class so it will work like that
T* t.....new etc.
int val = (*t)[i][j]; //I get t->b[i*j + j] b is an 1dimension array
class T{
public:
int* b;
int m, n;
T(int** a, int m, int n){
b = new int[m*n];
this->m = m;
this->n = n;
int counter = 0;
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
b[counter] = a[i][j];
counter++;
}
}
}
int main()
{
int m = 3, n = 5, c = 0;
int** tab = new int*[m];
for(int i = 0; i < m; i++)
tab[i] = new int[n];
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
tab[i][j] = c;
c++;
cout<<tab[i][j]<<"\t";
}
cout<<"\n";
}
T* t = new T(tab,3,5);
};
You cannot. You have to overload operator[] to return a proxy object, that in turn, overloads operator[] to return the final value.
Something like:
class TRow
{
public:
TRow(T &t, int r)
:m_t(t), m_r(r)
{}
int operator[](int c)
{
return m_t.tab[m_t.n*m_r + c];
}
private:
T &m_t;
int m_r;
};
class T
{
friend class TRow;
/*...*/
public:
TRow operator[](int r)
{
return TRow(*this, r);
}
};
Instead of saving a T& in TRow you could save directly a pointer to the row, that's up to you.
A nice feature of this solution is that you can use the TRow for other things such as operator int*().
In the case of a 2d array, you don't need to create a proxy type. Just use int*:
#include <iostream>
class T {
public:
int m, n;
int *b;
T(int m, int n) : m(m), n(n), b(new int[m*n]) {
}
int*operator[](std::size_t i) {
return &b[i*m];
}
};
int main () {
T t(2,2);
t[0][0] = 1;
t[0][1] = 2;
t[1][0] = 3;
t[1][1] = 4;
std::cout << t.b[0] << t.b[1] << t.b[2] << t.b[3] << "\n";
}