I am trying to define some operators.
I do it according to this documentation:
http://courses.cms.caltech.edu/cs11/material/cpp/donnie/cpp-ops.html
Is there an operator that should be defined twice?
I think that it's the index operator. am I right? I defined it such as:
int operator [] (const int power) const{
// here there is some code
}
Assuming I implement it correctly, what's about the operator that should have be defined twice?
Does it support the next things?
a[1] = 3;
cout << a[1]; // I defined the << operator
any help appreciated!
I think that it's the index operator. am I right?
Almost. It is called the subscript operator, and it must accept one single argument. Your operator accepts two, and that makes your code illegal.
Does it support the next things?
Supposing you have a properly written operator [] (without knowing some context from the logic of your application I cannot tell how to write one), then both the instructions you mention should be supported.
However, in order for this:
a[1] = 3;
To be legal (if a fundamental type is returned), operator [] should return an lvalue reference - therefore, int& and not int. Of course, this means the object to which the lvalue reference is bound cannot be a local object or a temporary, because that would mean returning a dangling reference.
int& operator [] (const int power) { // <== The function cannot be "const" if you
// ^ // are returning a non-const lvalue ref
// to a data member or element of a data
// member array
// here there is some code
}
You may also want a const version of the subscript operator:
int operator [] (const int power) const {
// No need to use a int const& ^^^^^
// here, that is basically the This member function can be const, since it is
// same as returning an int by neither modifying the object on which it is
// value invoked, nor returns any non-const lvalue ref
to a data member or an element of data member
// here there is some code
}
You may want to have both a const and a non-const versions of the operator:
int operator[](int index) const { ... }
int& operator[](int index) { ... }
This will permit both usages given in your example. It will also permit the second usage even if a is const.
To support assignment there are two options
The indexing operator [] returns a reference
The indexing operator [] returns a proxy object that implements assignment
The first case is the simplest, but doesn't allow you to distinguish between read and write operations. The second method is a bit more complex but allows more control:
An example of approach (2) is the following
struct MyArray {
std::vector<int> v;
MyArray(int n) : v(n) {}
struct ItemRef {
MyArray& a;
int index;
ItemRef(MyArray& a, int index)
: a(a), index(index)
{}
int operator=(int x) {
printf("Writing to element %i\n", index);
a.v[index] = x;
return x;
}
operator int() {
printf("Reading element %i\n", index);
return a.v[index];
}
};
ItemRef operator[](int index) {
if (index < 0 || index >= int(v.size()))
throw std::runtime_error("Invalid index");
return ItemRef(*this, index);
};
};
Related
I am beginner in cpp language.
Recently I saw in a many classes declare twice the same function with a little different such as:
int& operator[](size_t i) {
assert(i<size());
return _buf[i];
}
const int& operator[](size_t i) const {
assert(i<size());
return _buf[i];
}
What is the different between the function? why I need the first one? and in which cases the first function will be work and in which cases the second function will be work?
On of those is const the other isnt. Let me put it in some context:
struct Foo{
int value = 0;
int& operator[](size_t i) {
std::cout << "non-const\n";
return value;
}
const int& operator[](size_t i) const {
std::cout << "const\n";
return value;
}
};
The const version will be called on const instances while the non-const will be called on non-const instances. E.g.
int main(){
Foo f;
int x = f[0];
f[0] = 3; // OK
const Foo g;
int x = g[0];
//g[0] = 3; // NOT OK
}
...will print
non-const
const
Indeed both methods should be the same and the major difference is the const version returning a const reference while the non-const returns a reference that allows to modify the value.
As you correctly observed, apart from the constness and the return type, the two are identical. To avoid duplicate code, sometimes it can make sense to use a small trick and write the const version in terms of the non-const:
const int& operator[](size_t i) const {
std::cout << "const\n";
return const_cast<Foo*>(this)->operator[](i);
}
See here for the full example.
Usually you don't want to let users change your objects somehow if they are marked as const.
It means that if you have a class which provides operator[], you don't want to let users change the internal state of objects of this class via operator[] if these objects are const.
That's why you have two overloads. If the object is const, then the version
const int& operator[](size_t i) const
is called. This version returns const int&, so you can't do any modification.
In opposite, if the object is not marked as const, then
int& operator[](size_t i)
is called and you are free to modify the internal state of the object via the reference returned.
The differences are the const keyword:
int& operator[](size_t i) { (1)
const int& operator[](size_t i) const { (2)
The first function return a reference to the object, which means that you can modify the object (for example by doing foo[0] = bar.
The second use the const keyword twice: const int& means that you return a const reference that you can't modify. The second const is here to specify that this function will not modify the object.
You need those two version because (1) is used when you want to modify an element of the collection and (2) is used on const object:
you can do this:
void foo(std::vector<int> const& v) {
int j = v[0];
}
because vector as an operator that look like (2)
The first overload states that the subscript operator can modify internals of the class instance, the later states that internals of the class instance are read-only and thus, can't be modified.
Effectively, it means that this pointer points to either const or non-const object.
Previously:
You tagged your question with C which is not correct, as C does not offer any class member functions and thus AFAIK, const after the global function declaration is illegal.
It means your class is providing the support for two things,
Non Const Object
Const Object
int& operator[](size_t i) will be called for Non const object, because there is no const qualifier at the end.
const int& operator[](size_t i) const will be called for const object, because there is const qualifier at the end.
I've written the following code and run into a problem with overloading operator [].
Here's the code for testmain.cpp:
#include"test.hpp"
int main()
{
C tab = C(15);
bool b = tab[2];
return 0;
}
And here's the header file test.hpp:
#ifndef _test_
#define _test_
class C
{
friend class ref;
int s;
public:
class ref
{
public:
bool v;
ref();
ref(bool x);
ref& operator = (ref a);
ref& operator = (bool x);
};
C();
C(int a);
bool operator[] (int i) const ;
ref operator[] (int i);
};
#endif ///_test_
When I attempt to compile the code, I get the following error:
testmain.cpp: In function ‘int main()’:
testmain.cpp:6:16: error: cannot convert ‘C::ref’ to ‘bool’ in initialization
Looks like the compiler automatically assumes that my indexing operator[] will always return an object of type ref and ignores the operator[] that returns boolean type variable.
Is it possible to fix the code so that the compiler "knows" when to use appropriate overloaded operator[]?
The overload returning bool is const, so will only be used when applied to a constant C object. Yours is not const, so the non-const overload is chosen.
One solution is to make ref implicitly convertible to bool:
operator bool() const {return v;}
so that you can read a bool value in the same way using either overload.
You have two implementations of operator[]...one for const objects and one for non-const objects. Your main has a non-const instance of C, so it's invoking the non-const operator, which returns a ref.
I have this class definition:
class foo{
public:
foo();
foo(const int& var);
foo(const foo& var);
~foo();
const foo operator +(const foo& secondOp) const;
private:
int a;
//plus other values, pointers, e.t.c.
};
Also I have made this implementation for '+' operator overloading:
const foo foo::operator +(const foo& secondOp) const{
//I want here to check if i have one operand or two...
if ((FIRST_OPERAND.a!=0) && (secondOp.a==0)){
cout << "ERROR, second operand is zero";
return FIRST_OPERAND;
}
else if ((FIRST_OPERAND.a==0) && (secondOp.a!=0)){
cout << "ERROR, first operand is zero";
return secondOp;
}
}
When i write in main():
foo a(2);
foo b;
foo c;
//I want here to print the ERROR and
//return only the values of a
c = a + b;
Ηow can i return the value of the first operand if the second operand is zero and vice versa?
You're almost there. Since it's a member function, the first operand is *this, so replace FIRST_OPERAND.a with this->a or just a.
However, it might be better to make it a non-member function to allow conversions on both operands (i.e. to be able to write a + 2 or 2 + a). It will need to be a friend in order to access the private member(s).
friend foo operator +(const foo& firstOp, const foo& secondOp);
Also, it's best not to return a const value as that prevents moving from the return value.
It is the compiler that checks the syntaxical correctness of the program. It is unable to distinguish whether you indeed wanted to write
c = a;
that is to do the assignment or you wanted to write
c = a + b;
The both statements are correct.
It is a so-called logical error. The compiler is unable to see what we thoght.
For your line c = a; The assignment operator is implemented by the compiler (just shallow copying the object memory).
That is the reason your code compiles "without the second operand".
If you wish to disallow using the assignment operator - hide it. E.g. by implementing with the private access modifier.
You have to define this function as a friend function
friend Int operator + (int first, Int &second);
this function can perform obj + 2 or 2 + obj.
Int operator + (int first, Int& second){
second.a += first;
return second;
}
The title basically says it all. I mainly want to do this so that I can create an object (say, a custom string object) that can initialize the parameters of other functions in other APIs. Here's an example of me trying to get a custom integer class to work:
#include <iostream>
using namespace std;
class test
{
public:
int member;
test(int i) : member(i) {}
friend int &operator=(int &i, test t);
};
int &operator=(int &i, test t)
{
return (i = t.member);
}
int main()
{
int i;
test t = 90;
cout << (i = t);
return 0;
}
Unfortunately I receive an error saying that operator= needs to be a member function. I understand the C++ standard's goal in preventing static and non-member overloads for the assignment operator from being implemented, but is there any other way to do this? Thanks for any help/suggestions!
This is not done with an assignment operator but with an overloaded typecast. This would make your main function work like expected:
#include <iostream>
using namespace std;
class test
{
public:
int member;
test(int i) : member(i) {}
operator int() const {return member;}
};
int main()
{
int i;
test t = 90;
cout << (i = t);
return 0;
}
What you are trying to do needs an conversion operator
operator int()
{
return this->member;
}
For the class you are trying to write(containing only integer members), You do not need to overload the = operator.
= operator is one of the member functions that is generated by the compiler by default for every class. Caveat is, it does a simple bit by bit copy(shallow copy) of class members, since you have only integers it should be good enough for you.
You would need to overload the = operator if you had dynamically allocated pointers as member functions, because in that case a shallow copy of those pointers would result in all the objects containing a member pointer pointing to the same dynamic memory location & if one of the object finishes it lifetime, other objects are left with a dangling pointer.
As #Tony, aptly points in out comments Shallow copy is usually bad but not always. See his comments for a scenario.
If at all you want to overload the assignment operator check out the Copy and Swap Idiom to do it right way.
You should also check out the Rule of Three.
Try this:
class test
{
public:
int member;
test(int i) : member(i) {}
operator int() {return this->member;}
};
int main(void)
{
int i;
test t = 90;
cout << (i = t);
return 0;
}
The assignment operator cannot be a friend function. The assignment operator can only be declared as a non-static member function. This is to ensure that it receives the L-value as its first operand. The same is true for the [], (), and -> operators. In your case, since int is an build-in type, you cannot use member function. You can implement operator int() to cast your user-defined type to int.
I define two versions of overloaded operator[] function in a class array. ptr is a pointer to first element of the array object.
int& array::operator[] (int sub) {
return ptr[sub];
}
and
int array::operator[] (int sub) const {
return ptr[sub];
}
Now, if I define a const object integer1 the second function can only be called..... but if I make a non-const object and then invoke as below:
cout << "3rd value is" << integer1[2];
which function is called here?
In your second example, the non-const version will be called, because no conversion is required, and a call that requires no conversion is a better match than one that requires a conversion.
Ultimately, however, you have a basic problem here: what you really want is behavior that changes depending on whether you're using your object as an rvalue or an lvalue, and const doesn't really do that. To make it work correctly, you normally want to return a proxy object, and overload operator= and operator T for the proxy object:
template <class T>
class myarray {
T *ptr;
class proxy {
T &val;
proxy &operator=(proxy const &p); // assignment not allowed.
public:
proxy(T &t) : val(t) {}
operator T() const { return val; }
proxy &operator=(T const&t) { val = t; return *this; }
};
proxy const operator[](int sub) const { return proxy(ptr[sub]); }
proxy operator[](int sub) { return proxy(ptr[sub]); }
// obviously other stuff like ctors needed.
};
Now we get sane behavior -- when/if our array<int> (or whatever type) is const, our operator[] const will be used, and it'll give a const proxy. Since its assignment operators are not const, attempting to use them will fail (won't compile).
OTOH, if the original array<int> was not const, we'll get a non-const proxy, in which case we can use both operator T and operator=, and be able to both read and write the value in the array<int>.
Your const version should return const int& not int, so that the semantics are just the same between the two functions.
Once you've done that, it doesn't matter which one is used. If the const version has to be used because your object has a const context, then it will be... and it won't matter as you're not trying to modify anything. Otherwise, it'll use the non-const version... but with just the same effect.