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
Related
The goal I set to myself is to overload operator+ (adding class objects). It turns out that this sum can be just interpreted as the sum of two vectors. But when it comes to the method operator+, I find it difficult to return the object. I've read similar topics and even try to apply some sugestions but with no success, unfortunatelly. I enclose some of my code.
template<class Y>
class myVect {
public:
myVect(int n = 1);
~myVect();
myVect(const myVect& a);
myVect& operator= (const myVect&);
myVect& operator+ (const myVect&);
void display(const myVect& a);
private:
int size;
Y* data;
template<class U> friend class myClass;
};
template<class Y> // constructor
myVect<Y>::myVect(int n) {
size = n;
data = new Y[size];
cout << endl << "Pass the elements" << " " << size << "\n";
for (int i = 0; i < size; i++) {
cin >> *(data + i);
}
}
template <class Y> // deconstructor
myVect<Y> :: ~myVect() {
delete[] data;
}
template<class Y> // copy constructor
myVect<Y> ::myVect(const myVect & a) {
size = a.size;
data = new Y[size];
for (int i = 0; i < size; i++) {
*(data + i) = *(a.data + i);
}
}
template<class Y> //ASSIGMENT OPERATOR
myVect<Y> & myVect<Y> :: operator= (const myVect<Y> & a) {
if (this != &a) {
delete[] data;
size = a.size;
data = new Y[size];
for (int i = 0; i < size; i++) {
*(data + i) = *(a.data + i);
}
}
return *this;
}
The method operator+ is a follows:
template<class Y>
myVect<Y>& myVect<Y> ::operator+ (const myVect<Y>& a) {
if (this->size != a.size) {
cout << endl << "not able to perform that operation - wrong dimensions" << endl;
}
else {
myVect<Y> newObj(this->size);
for (int i = 0; i < this->size; i++) {
*(newObj.data + i) = *(this->data + i) + *(a.data + i);
}
}
return newObj;
}
The error I get is 'newObj': identifier not found. I believe it's due to deconstructor. I tried to put the class myVect into a new class (encapsulate it) and contruct the return method but it didn't change antything - the type of the error is still the same. Do you know how to solve this problem?
Anyway, if it is the destructor fault, does that mean that newObj is deleted before its return?
The problem can be reduced to this:
int foo()
{
if (true) // In reality, some meaningful condition
{
int x = 4;
}
return x;
}
The variable is scoped to the if block. It doesn't exist outside of it.
You'll have to move its declaration out of the conditional, and do whatever else is required to make that work… or return from inside the condition, and do something else (throw an exception?) otherwise.
For example, given the above demonstration:
int foo()
{
int x = 0; // Or some other value
if (true) // In reality, some meaningful condition
{
x = 4;
}
return x;
}
or:
int foo()
{
if (true) // In reality, some meaningful condition
{
int x = 4;
return x;
}
throw std::runtime_error("For some reason I have no value to give you!");
}
Your next problem will be that you are trying to return a local variable by reference. You cannot do that. Return it by value instead, which is anyway idiomatic for what you're doing.
You've declared your object inside of a block, so it won't exist in the outside scope. This would normally free you up to reuse variable names across different branches; try making a newObj inside the if part of the statement and watch it not throw an error, for example.
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.
Here I want to get rid of insert function by overloading [] and = operators.
By overloading [] operator, I have successfully returned the address of the required location where I want to insert the value.
#include<iostream>
using namespace std;
#define const maxSize = 30;
class ARRAY
{
private:
int *ar;
int end;
public:
ARRAY()
{
ar = new int[40];
end = -1;
}
void insert(int value)
{
end += 1;
ar[end] = value;
}
void insert(int value, int index)
{
if (index<30 && index >-1)
{
int tempEnd = end;
for (int i = end; i >= index; --i)
{
ar[tempEnd + 1] = ar[tempEnd];
tempEnd -= 1;
}
end += 1;
ar[index] = value;
}
else
cout << "\nOVERFLOW";
}
void remove(int index)
{
if (index >= 0 && index <= end)
{
for (int i = index; i < end; ++i){
ar[i] = ar[i + 1];
}
end -= 1;
//do something
}
else
cout << "\nNothing gonna happens";
}
void display()
{
for (int i = 0; i <=end; ++i)
cout << "\n" << ar[i];
}
int* operator[](int at)
{
if (at < 40){
end++;
return (&ar[at]);
}
}
//Here I want to do = operator overloading, How can I do this?
};
int main()
{
ARRAY arr;
arr.insert(1);
arr.insert(2);
arr.insert(3);
arr.insert(4);
arr.insert(5);
arr[5] = 10;
arr.display();
return 0;
}
You can achieve the desirable behavior by changing the return type of your operator[]:
int& operator[](int at)
In your original code it returns pointer to the array element, which, even if changed, does not do anything with the value stored in the array. With your original code, you could write something like this to change the element's value:
*(arr[5]) = 10;
which looks unobvious.
If you return reference instead of pointer, you can directly change the value it references to.
You do not need to overlaod the assignment operator '=' for your purpose. Only overload the access operator '[]'.
That should look something like this:
returntype& operator [](int indexvariable);
That is going to give you a reference to an instance of returntype and therefore you wont need to overload the assignment operator of your returntype in your case.
Then you can write:
arr[5] = 23;
You can achieve pretty much any desirable behavior with some trickery.
In your case, if you want some specific action for operator= (e.g. check bounds & insert a new element), you can introduce a helper class, that will hold a reference to an array and an index, and then overload the operator= for that class:
class ArrayIndex
{
ARRAY& array;
int index;
public:
ArrayIndex(ARRAY& a, int i) : array(a), index(i) {}
void operator=(int value)
{ array.insert(value,index); }
};
And of course you tweak your ARRAY's operator[] to return the ArrayIndex object.
If you don't want the insertion or any unusual actions, and only want to access the elements, then operator[] returning the reference (int&) will suffice.
Following the comment OP left on akexeykuzmin0's response, I suggest to alter your operator[] to return a handler to your element.
#include <iostream>
struct ARRAY
{
struct Handler
{
int* _ptr;
Handler(int* ptr) : _ptr(ptr) {}
int& operator*() { return *_ptr; }
operator int*() { return _ptr; }
int& operator=(int const& value) { *_ptr = value; return **this; }
};
int _value;
ARRAY(int n) : _value(n) {}
Handler operator[](size_t) { return Handler(&_value); }
};
int main() {
ARRAY arr(42);
std::cout
<< std::hex << &arr._value << "\n"
<< std::dec << arr._value << "\n"
<< *arr[0] << "\n\n";
arr[0] = 137;
std::cout
<< std::hex << &arr._value << "\n"
<< std::dec << arr._value << "\n"
<< *arr[0] << "\n\n";
int* pvalue = arr[0];
*pvalue = 0;
std::cout
<< std::hex << &arr._value << "\n"
<< std::dec << arr._value << "\n"
<< *arr[0] << "\n\n";
}
Output
g++ -std=c++17 -O2 -Wall -Werror main.cpp && ./a.out
0x7ffd682844f0
42
42
0x7ffd682844f0
137
137
0x7ffd682844f0
0
0
Live demo on coliru
This handler can be implicitly converted to a int* and you can overload the operator= on it.
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.