can somebody ewxplain me how the compiler calls the operator casting:
operator ELEMENT()const {
return pArray->arr[index];
}
From line 6 in main:
(*ptr3)[0] = a1[0] + a2[1];
How adding two ELEMENT object with + operator even allowed? There is no + operator overloading in ELEMENT class.
Thanks,
Liron
#include <iostream>
using namespace std;
template<class ELEMENT> class Array
{
class Element
{
Array<ELEMENT>* pArray;
int index;
public:
Element(Array<ELEMENT>* p, int i)
: pArray(p), index(i) {}
const Element& operator=(const ELEMENT& e) {
pArray->set(index, e); // call copy-on-write
return *this;
}
operator ELEMENT()const {
return pArray->arr[index];
}
};
friend class Element;
ELEMENT* arr;
int size;
int* ref_counter;
void attach(const Array& a) {
arr = a.arr; size = a.size;
ref_counter = a.ref_counter;
++(*ref_counter);
}
void detach() {
if(--(*ref_counter) == 0) {
delete []arr;
delete ref_counter;
}
}
void set(int index, const ELEMENT& e) {
if(*ref_counter > 1) { // need copy-on-write!
Array temp = clone();
detach();
attach(temp);
}
arr[index] = e;
}
public:
explicit Array(int);
Array<ELEMENT> clone()const;
Array(const Array<ELEMENT>& a){attach(a);}
~Array(){detach();}
const Array& operator=(const Array<ELEMENT>& a) {
detach(); attach(a); return *this;
}
Element operator[](int index) {
return Element(this, index);
}
const ELEMENT& operator[](int index)const {
return arr[index];
}
};
template<class ELEMENT>
Array<ELEMENT>::Array(int size1)
: size(size1), ref_counter(new int(1))
{
arr = new ELEMENT[size];
}
template<class ELEMENT>
Array<ELEMENT> Array<ELEMENT>::clone()const {
Array temp(size);
for(int i=0; i<size; ++i) {
temp.arr[i] = arr[i];
}
return temp;
}
int main()
{
Array<int> a1(1), a2(2);
Array<int>* ptr3 = new Array<int>(3);
a2[0] = 1;
a2[1] = 2;
a1 = a2;
(*ptr3)[0] = a1[0] + a2[1];
(*ptr3)[1] = a1[1] + a2[0];
cout << (*ptr3)[0] << ", " << (*ptr3)[1] << endl;
delete ptr3;
return 1;
}
How adding two ELEMENT object with + operator even allowed? There is no + operator overloading in ELEMENT class.
ELEMENT is not a class, it's a type parameter. And in your example the type given for that parameter is int. Obviously int does have a + operator, so that works fine. If you tried to create an Array<SomeType> where SomeType did not have a + operator, you would get an error.
There is an Element class and that class does indeed have no + operator, but that class is implicitly convertible to ELEMENT (i.e. int in this case), so when you apply + to objects of the Element the compiler adds a call to that conversion operator and + is applied to the result.
Related
So I'm trying to write my own array template and everything works until i try to create a const object of my class template. in main.cpp I create the object with the copy contructor and I change it which I would expect to not work but it works. Help would be appreciated :D
main.cpp
# include "Array.hpp"
int main( void ) {
Array<int> l = 1;
l.setValue(5, 0);
const Array<int> abc(l);
std::cout << abc[0] << std::endl;
abc[0] = 3;
std::cout << abc[0] << std::endl;
return (0);
}
Array.tpp
#ifndef ARRAY_TPP
# define ARRAY_TPP
# include "Array.hpp"
template<class T>
class Array {
private:
int size_;
T *array_;
public:
Array() : size_(0), array_(new T[size_]) {};
Array(int n) : size_(n), array_(new T[size_]) {};
Array(Array const& src) : size_(src.size()), array_(new T[src.size()]) {
for (int i = 0; i < src.size(); ++i) {
array_[i] = src[i];
}
};
Array& operator=(Array const& copy) {
size_ = copy.size();
delete[] array_;
array_ = new T[size_];
for (int i = 0; i < size_; i++)
array_[i] = copy[i];
return (*this);
}
T& operator[](int n) const {
if (n < 0 || n >= size_)
throw std::out_of_range("out of range");
return (array_[n]);
}
int size(void) const { return (size_); };
void setValue(T value, int n) {
if (n < 0 || n >= size_)
throw std::out_of_range("out of range");
array_[n] = value;
}
~Array() { delete[] array_; };
};
#endif
The issue is this:
T& operator[](int n) const {
if (n < 0 || n >= size_)
throw std::out_of_range("out of range");
return (array_[n]);
}
Because this is declared to be a const method, it can be called on a const Array. Though, it returns a non-const reference to the element. Because Array stores the elements via a T *, only that pointer is const in a const Array while modifiying the elements via that pointer is "fine".
You need two overloads of operator[]:
T& operator[](int n);
const T& operator[](int n) const;
Error C2676 binary '[': 'collection::item' does not define this operator or a conversion to a type acceptable to the predefined operator
I read few posts and Microsoft VS site, but cannot understand how to fix the problem
template<typename T1, typename T2>
class collection {
private:
class item {
public:
T1 item; T2 key;
};
unsigned int top;
item array = new item[top];
public:
collection& operator[](unsigned int i) {
return array[i];
}
collection(int top) {
this->top = top;
}
void coutarr() {
for (int i = 0; array[i] != 0; i++) {
cout << array[i].item << endl;
}
}
void extendarray() {
item x = new item[top*2];
for (int i = 0; i < top; i++) {
x[i] = array[i];
}
delete []array;
swap(array, x);
top = top*2;
}
void addvar(int i, T1 item, T2 key) {
array[i].item = item; array[i].key = key; //Here 2 Errors
}
};
If someone can explain what shall I do, I'd be very grateful. Thanks.
Error C2676 binary '[': 'collection::item' does not define this operator or a conversion to a type acceptable to the predefined operator
this is because
item array = new item[top];
must be
item * array = new item[top];
but you also have to move the initialization in the constructor when top has a value
Out of that is was better that the constructor collection(int top) get an unsigned value being collection(unsigned top) or better collection(size_t top)
Copy contructor, operator= ... are missing while an attribute is a pointer
What about to check the validity of i in collection& operator[](unsigned int i) and void addvar(int i, T1 item, T2 key) to produce an exception when it is invalid ? addvar is also a strange name because it is a set, a add means the size is increased. You cannot access to an element on a const instance, add const collection& operator[](unsigned int i) const
In void extendarray() to double the size will not do a lot if the initial size is 0 ;-)
Just a guess: top is unititialized. That makes array an array with zero length at best (which is really bad) and invokes undefined behavior at worst.
It seems you mean at least something like the following
template<typename T1, typename T2>
class collection {
private:
class item {
public:
T1 item; T2 key;
};
unsigned int top;
item *array;
^^^^^^^^^^^^^
public:
auto & operator[](unsigned int i) {
^^^^
return array[i];
}
collection(unsigned int top) : top( top ), array( new item[top]{} )
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
}
~collection() { delete []array; }
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
collection( const collection & ) = delete;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
collection & operator =( const collection & ) = delete;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
void coutarr() {
for (int i = 0; array[i] != 0; i++) {
cout << array[i].item << endl;
}
}
void extendarray() {
item x = new item[top*2];
for (int i = 0; i < top; i++) {
x[i] = array[i];
}
delete []array;
swap(array, x);
top = top*2;
}
void addvar(int i, const T1 &item, const T2 &key) {
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
array[i].item = item; array[i].key = key; //Here 2 Errors
}
};
Of course you can futher develop the code.
I have my own Class Vector and I'd like to create an operator-- to delete last element in array. But in my implementation i got an error:
binary "--": Vector does not define this operator or a conversion to a
type acceptable to the predefined operator.
How do i declare it correctly?
class Vector {
private:
int *vect;
int size;
public:
void operator--();
}
void Vector::operator--() {
int *tmp = vect;
size--;
vect = new int(size);
for (int i = 0; i < size; i++) vect[i] = tmp[i];
delete[] tmp;
}
I should have declared it like this:
void operator--(int);
And implemented like this:
void Vector::operator--(int) {
if (size>1) size--;
else std::cout << "Only one element in vector.\n";
}
this (int) helps the compiler to differ prefix and postfix increments or decrements.
An example:
struct A {
void operator --(int) { std::cout << "Postfix\n"; }
void operator --() { std::cout << "Prefix\n"; }
};
int main()
{
A a;
a--;
--a;
}
Thanks to #PaulMcKenzie for the link.
I created a Container class and used the new keyword in combination with pointers to learn how it works and how I can use it.
template<typename T>
class Container {
private:
T value;
public:
Container(T value) {
this->value = value;
}
Container() {
}
virtual ~Container() {
}
T getValue() {
return value;
}
void setValue(T value) {
this->value = value;
}
void operator[](T value) {
this->value = value;
}
};
int main() {
std::vector<Container<int>*> arr(10);
for (int i = 0; i < 10; i++) {
Container<int> *a = new Container<int>;
a->setValue(i);
// a[i];
arr[i] = a;
std::cout << arr[i]->getValue() << std::endl;
delete a;
}
return 0;
}
The [] operator has the same code as setValue(), but it only prints the numbers from 0 to 9 if I use a->setValue(i) and with using a[i] it prints just a random number. Why?
See Sly_TheKing's answer (applying index operator to pointer).
The index operator is intended to access values at a specific offset to some reference. It should accept a signed or unsigned integer value and return some specific value. So the operator, to be valid, should look like this:
T& operator[](size_t index)
{
return value;
}
Actually, as you do not have anything you could apply an index to (the only valid index in your case would be 0 – or from another point of view, with above implementation, any index would return the same value, so &a[0] == &a[1] would apply - which might be syntactically correct, but violates the semantics of an index operator...), dereferencing operators would be more appropriate:
T& operator*() { return value; }
T& operator->() { return value; }
Possibly, you could add an assignment operator, too (would replace setValue):
Container& operator=(T const& value) { this->value = value; return *this; }
In line
Container<int> *a = new Container<int>;
you initialize a as pointer, so with this line
a[i];
you just access some memory with address stored in a and offset i * sizeof(container<int>)
So the correct usage would be
std::vector<Container<int>*> arr(10);
for (int i = 0; i < 10; i++) {
Container<int> *a = new Container<int>;
(*a)[i];
arr[i] = a;
std::cout << arr[i]->getValue() << std::endl;
delete a;
}
With (*a)[i]; you access operator[] you wrote in your class
After really hard search for answers...
I tried fo(u)r hours to get and set values to an array with Overloading the subscript operator “[ ]” but can't figure out why it won't work.
What I'm tring to do here is to set someType value to an array member (On Main "darr1[i] = i*10.0" for example) with overloading the [] and with overloading the = and to get someType value from an array member (On Main "<< darr1[i] << endl" for example) but can't figure out why just the overloading of: "Type & operator [] (int index)" is invoking.
My program doesn't get to the '=' overloading or to the second '[]' overloading at all..
here is my program (sorry for the long one):
#include <iostream>
#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
class AO1Array
{
private:
int _size;
protected:
int top;
int *B;
int *C;
AO1Array(int n);
~AO1Array();
bool isRealValue(int index)
{
if ((0 <= B[index] && B[index] < top) && (index == C[B[index]]))
return true;
return false;
};
};
AO1Array::AO1Array(int n)
{
_size = n;
top = 0;
B = new int[n];
C = new int[n];
}
AO1Array::~AO1Array()
{
delete[] B;
B = NULL;
delete[] C;
C = NULL;
}
template<class Type>
class GenericO1Array : AO1Array
{
public:
GenericO1Array(int size, Type initVal) : AO1Array(size)
{
_initVal = initVal;
Len = size;
A = new Type[size];
}
~GenericO1Array()
{
delete[] A;
A = NULL;
}
int Length() { return Len; }
Type & operator [](int index) const
{
if (AO1Array::isRealValue(index))
return A[index];
return _initVal;
}
Type & operator [] (int index)
{
if (AO1Array::isRealValue(index))
realValue = true;
else
realValue = false;
return A[index];
}
Type operator =(Type value)
{
if (realValue)
A[lastIndex] = _initVal;
else
{
AO1Array::C[top] = lastIndex;
AO1Array::B[lastIndex] = AO1Array::top++;
A[index] = value;
}
return *this;
}
private:
int Len;
int lastIndex;
bool realValue;
Type _initVal;
Type *A;
};
int main()
{
int n = 20;
GenericO1Array<double> darr1(n, 1.1);
GenericO1Array<long> iarr1(n, 2);
int i;
cout << "\nLength.darr1 = " << darr1.Length() << endl;
cout << "\nLength.iarr1 = " << iarr1.Length() << endl;
for (i = 0; i < n; i += 2)
{
darr1[i] = i*10.0;
iarr1[i] = i * 100;
} // for
cout << "\ndarr1 = " << endl;
for (i = 0; i < n; i++)
cout << "darr1[" << i << "] = " << darr1[i] << endl;
cout << "\niarr1 = " << endl;
for (i = 0; i < n; i++)
cout << "iarr1[" << i << "] = " << iarr1[i] << endl;
} // main
My program doesn't get to the '=' overloading
You are overloading the = assignment operator of Generic01Array itself, but nothing in your code is actually assigning values to your darr1 or iarr1 variables directly (there are no darr1 = ... or iarr = ... statements). That is why your = operator is not being invoked.
If you want something to happen when the user assigns a value to an element of your array, you need to create a proxy class and overload its = assignment operator, then have your [] operator return an instance of that proxy:
template<class Type>
class GenericO1Array : AO1Array
{
public:
class Proxy;
friend Proxy;
class Proxy
{
private:
Generic01Array& _arr;
int _index;
public:
Proxy(Generic01Array &arr, int index) : _arr(arr), _index(index) {}
operator Type() const
{
if (_arr.isRealValue(index))
_arr.realValue = true;
else
_arr.realValue = false;
return _arr.A[_index];
}
Proxy& operator=(const Type &value)
{
if (_arr.realValue)
_arr.A[_arr.lastindex] = _arr._initVal;
else
{
_arr.C[_arr.top] = _arr.lastIndex;
_arr.B[_arr.lastIndex] = _arr.top++;
_arr.A[_index] = value;
}
return *this;
}
};
...
Proxy operator [] (int index)
{
return Proxy(*this, index);
}
...
};
or to the second '[]' overloading at all..
You have two overloads of the [] operator, one that is const and the other is not. The const version of [] is breaking the const-ness of the operator by returning a non-const reference to the array's internal data. It should be returning a non-reference const value instead:
const Type operator [](int index) const
The non-const version of the [] operator can return a reference:
Type& operator [](int index)
You are not calling the [] operator on any const instances of your Generic01Array class, so only the non-const version of your [] operator should be getting invoked.