Given a simple class that overloads the '[ ]' operator:
class A
{
public:
int operator[](int p_index)
{
return a[p_index];
}
private:
int a[5];
};
I would like to accomplish the following:
void main()
{
A Aobject;
Aobject[0] = 1; // Problem here
}
How can I overload the assignment '=' operator in this case to work with the '[ ]' operator?
You don't overload the = operator. You return a reference.
int& operator[](int p_index)
{
return a[p_index];
}
Make sure to provide a const version as well:
const int& operator[](int p_index) const
{
return a[p_index];
}
Make it return a reference:
int & operator[](int p_index)
{
return a[p_index];
}
Note that you will also want a const version, which does return a value:
int operator[](int p_index) const
{
return a[p_index];
}
The problem here is you are returning the value which is contained in vaiable a.
In main you are trying to assign int variable which is not available.
You would have seen compilation error "error C2106: '=' : left operand must be l-value" like this.
Means the value cannot be assigned to a variable which is not available.
Please change return type of operator [] overloading function into reference or pointer it will work fine.
Related
I have one doubt on prefix operator overloading .
my sample program:
class ABC {
int i;
public:
const ABC& operator++() { i=i+1; return *this;}
};
int main() {
ABC ob ; //let value of i =5;
++ob; // value of i will be 6
return 0;
}
but I could do the same thing by overloading like below
void operator++() { i=i+1;}
this gives me same result when calling ++ob
APMK ++ob converted as ob.operator++().
My doubt is what happens to the return value. Does the compiler creates code like:
ob = ob.operator++();
Thanks in advance
why do we have to return const reference from unary prefix operator overloading
You don't have to. Typically you return non-const reference, but you could make it return anything. You shouldn't, but you could. The built in pre-increment works how returning non-const reference works, so it makes the most sense to do that.
The reason to return a reference to an object is to make the behavior the same as for integers (for built in types).
std::cout << ++i;
std::cout << i++;
If i is an integer this will work. This will only work in a class if you return a reference to the object (Assuming you have defined operator<< for your class).
class ABC {
int i;
public:
ABC(int x = 0) : i(x) {}
const ABC& operator++() { i=i+1; return *this;}
ABC operator++(int) { ABC result(*this);i=i+1; return result;}
friend std::ostream& operator<<(std::ostream& out, ABC const& val)
{
return out << val.i;
}
};
With this definition then your class will behave the same way that an integer will behave in the above situation. Which makes it very useful when using template as you can now do a drop in replacement for integer with your type.
Note normally I would return just a reference (not a const reference).
/*const*/ ABC& operator++() { i=i+1; return *this;}
^^^^^^^^^
see: https://stackoverflow.com/a/3846374/14065
But C++ allows you do anything and you can return whatever is useful or has appropriate meaning for the situation. You should consider what is meaningful for your class and return a value that is appropriate. Remember the Principle of lease surprise
class A
{
public:
int v;
A * p;
A& operator*(const A& a)
{
return this->v*a.v// here is a red line under this say error initial value of reference to non-const must be an value
}
~A()
{
this;
}
};
int main()
{
A a;
a.p = new A;
delete a.p;
return 0;
system("pause");
return 0;
}
overloading * operator I cannot use this to represent the object itself. Why this happened.
Surely it says that it must be an lvalue. You're trying to return a reference to a temporary. This is bad karma.
Besides, it's not at all what you want. The multiplication operator should definitely return a value, not a reference.
Not sure what your constructor looks like, but assuming it takes an integer:
A operator * (A const& other) const
{
return A{ v * other.v};
};
Edit:
And actually you should go a step further:
struct A
{
A& operator *= (A const& other) { v *= other.v; return *this; }
A(int i) : v(i) {}
private:
int v;
}
A operator * (A lh, A const& rh)
{
A res{std::move(lh)};
res *= rh;
return res;
}
this->v*a.v evaluates to an int. An int cannot be converted to an A&.
Use
A operator*(const A& a) // Return a value, not a reference.
{
A res;
res.v = this->v*a.v;
return res;
}
You should make the member function a const member function too since it does not modify the object.
A operator*(const A& a) const
{
A res;
res.v = this->v*a.v;
return res;
}
The result of this->v * a.v is an rvalue, a temporary unnamed value. As a temporary, it cannot bind to a non-const reference. Only lvalues can bind to non-const references. That's what the error "initial value of reference to non-const must be an lvalue" is referring to.
However, you don't want to return a const reference either, you want to return the value by value:
A operator*(const A& a) { … }
^ remove &
Note: this will not fix your code completely as you're trying to return an int where you declared to return an A, and int isn't implicitly convertible to A in your current code.
I am learning templates and operator overloading. I have written some code but I am confused... Let me explain...
template <class T>
class tempType
{
public:
T value;
bool locked;
tempType():locked(false)
{
value = 0;
}
T operator=(T val)
{
value=val;
return value;
}
tempType<T> operator=(tempType<T> &val)
{
value=val.value;
return *this;
}
operator T()
{
return value;
}
};
And I did...
int main(void)
{
tempType<int> i;
tempType<bool> b;
tempType<float> f;
i.value = 10;
i = i + f;
return 0;
}
What code I need to write in order to execute
tempType<T> operator=(tempType<T> &val){}
Also, I why operator T() is required?
Unless you implement move semantics, operator= should always take a const & reference to the source value. It should also return a reference to the modified object.
tempType & operator=(T const & val)
{
value=val;
return * this;
}
operator T is an implicit conversion function which allows any tempType object to be treated as an object of its underlying type T. Be careful when specifying implicit conversions that they won't conflict with each other.
An implicit conversion function usually shouldn't make a copy, so you probably want
operator T & ()
{
return value;
}
operator T const & () const
{
return value;
}
Given these, you shouldn't need another overload of operator = because the first overload will simply be adapted by the conversion function to a call such as i = b;.
If a series of conversions will result in the operator=(T const & val) being called, you should avoid also defining operator=(tempType const & val) because the overloads will compete on the basis of which conversion sequence is "better," which can result in a brittle (finicky) interface that may refuse to do seemingly reasonable things.
I think I know all the answers so I might as well post full response.
To override default operator= you should declare it as tempType<T> operator=(const tempType<T> &val){}. Now you need to call the method explicitly via i.operator=(other_i).
If you correct the declaration you can use it like this:
tempType<int> i;
tempType<int> other_i;
i = other_i; // this is what you just defined
The operator T() is called a conversion operator. It is kind of reverse or counter part of the conversion constructor which in your case would be tempType(const &T value).
It is used to convert a class object into a given type. So in your case you would be able to write:
tempType<int> i;
int some_int;
some_int = i; // tempType<int> gets converted into int via `operator int()`
template <class T>
class tempType
{
public:
T value;
bool locked;
tempType() : value(), locked(false)
{
value = 0;
}
//althought legal, returning something different from tempType&
//from an operator= is bad practice
T operator=(T val)
{
value=val;
return value;
}
tempType& operator=(const tempType &val)
{
value=val.value;
return *this;
}
operator T()
{
return value;
}
};
int main(void)
{
tempType<int> a;
tempType<int> b;
a = b;
return 0;
}
in the code, a = b calls the operator.
As for the second question, the operator T() is not needed "by default". In your example, it is used when you write i+f:
i is converted to an int
f is converted to a float
the operation (+) is performed
T tempType<int>::operator=(T val) is called for the assignement
Here's a simplified version of my problem. I have a property class. It has data like has_initalized and such which i removed for this example.
When i call a function which uses T its fine. However T& isnt so i decided to write a T& version of it. But this causes all functions which uses plain T to get a compile error. Why is T& interfering with that? For this example how do i get both functions (Q and W) to work without changing main()?
template <class T>
class Property {
T v;
Property(Property&p) { }
public:
Property() {}
T operator=(T src) { v = src; return v; }
operator T() const { return v; }
operator T&() const{ return v; }
T operator->() { return v; }
};
class A{};
void Q(A s){}
void W(A& s){}
int main(){
Property<A> a;
Q(a);
W(a);
}
There is nothing in the overloading rules of C++ which allows the compiler to choose between operatorT() and operatorT&() in the call to Q. So removing the
operator T() const { return v; }
will also remove the ambiguity. But then you'll have a problem because returning a non const reference to a member in a const function is not possible.
For your Q, you can use both conversion functions. You can make the compiler prefer one over the other by making one non-const.
operator T() const { return v; }
operator T&() { return v; }
Now for Q, the operator T& is taken. This way will also fix the call to W to get a non-const reference. You can also return a const reference from the other
operator T const&() const { return v; }
operator T&() { return v; }
This way will still prefer the second conversion function for Q, but if your object a is const and you initialize a const reference, you won't always require to copy v.
Let's say I have a container class called MyContainerClass that holds integers.
The [] operator, as you know, can be overloaded so the user can more intuitively access values as if the container were a regular array. For example:
MyContainerClass MyInstance;
// ...
int ValueAtIndex = MyInstance[3]; // Gets the value at the index of 3.
The obvious return type for operator[] would be int, but then the user wouldn't be able to do something like this:
MyContainerClass MyInstance;
MyInstance[3] = 5;
So, what should the return type for operator[] be?
The obvious return type is int& :)
For increased elaboration:
int &operator[](ptrdiff_t i) { return myarray[i]; }
int const& operator[](ptrdiff_t i) const { return myarray[i]; }
// ^ could be "int" too. Doesn't matter for a simple type as "int".
This should be a reference:
int &
class MyContainerClass {
public:
int& operator[](unsigned int index);
int operator[](unsigned int index) const;
// ...
};
Returning a reference lets the user use the result as an lvalue, as in your example MyInstance[3] = 5;. Adding a const overload makes sure they can't do that if MyInstance is a const variable or reference.
But sometimes you want things to look like that but don't really have an int you can take a reference to. Or maybe you want to allow multiple types on the right-hand side of MyInstance[3] = expr;. In this case, you can use a dummy object which overloads assignment:
class MyContainerClass {
private:
class Index {
public:
Index& operator=(int val);
Index& operator=(const string& val);
private:
Index(MyContainerClass& cont, unsigned int ind);
MyContainerClass& m_cont;
unsigned int m_ind;
friend class MyContainerClass;
};
public:
Index operator[](unsigned int ind) { return Index(*this, ind); }
int operator[](unsigned int ind) const;
// ...
};
int&
returning a reference allows you too use the returned value as a left-hand side of the assignment.
same reason why operator<<() returns an ostream&, which allows you to write cout << a << b;