Const and Non-Const Operator Overloading

Operator [ ] overloading with const and non const versions

Whether or not you need two overloads depends on what interface you want to provide.

If you want to be able to modify elements even in const instances of Array, then yes, the single int& operator[](int index) const; is enough. This is what std::unique_ptr does.

But if you want elements of const Arrays to be read-only, and at the same time elements of non-const Arrays to be mutable, you need two overloads. std::vector does that.

Usually the second option is preferred.

Array operator [] overloading const and non-const versions

The non-const function will always be called on a non-const array, and the const function on a const array.

When you have two methods with the same name, the compiler selects the best-fitting one based on the type of the arguments, and the type of the implicit object parameter (arr).

I just answered a similar question the other day, you may find it helpful: https://stackoverflow.com/a/16922652/2387403

C++ overload operator twice, one return non-const reference and the other const reference, what is the preference?

These functions don't overload each other; they have the same signatures, and so the attempt to redefine the same function, which is an error. The return type is not part of a function's signature. To overload a function, you must declare a second function with the same name, but different parameters or const/volatile qualifiers - that is, qualifiers on the function, not the return type.

(They don't override each other either; overriding is what derived classes do to their base classes' virtual functions).

It's common to define a const and a non-const overload of a member function; the const overload must declare the function const, not just the return type:

T& operator()(par_list){blablabla}
const T& operator()(par_list) const {blablabla}
^^^^^

Now the first will be called if you apply () to a non-const object, and the second on a const object. For example:

Thingy nc;
Thingy const c;

nc(); // calls the first (non-const) overload
c(); // calls the second (const) overload

what does const mean when overloading operator in C++

It can be used for any member function, not only operators. It means, that this function will:

  • not be able to modify any data members (except mutable ones)
  • will not be able to call any non-const member functions

why must you provide the keyword const in operator overloads

A const parameter is const throughout the function using it, it does not change its constness outside of it.

In this case you want to declare a const argument so that your assignment operator accepts both non-const variables and const variables; the latter case, in particular, includes the result of expressions, which is a temporary const variable and which you generally want to support in assignments.

Force compiler to choose const operator overload

It doesn't have anything to do with the array being dynamically allocated. Your variable a is not const, so the non-const function will be called on it. If you had const B b(10); and did b[3], the const version would be called.

If you really want to, you can force the const version to be called by casting to a const reference:

static_cast<const A&>(a)[3]

(Or alternatively, create a reference variable and call it on that)

C++ operator + and * non-const overloading

You can use proxies instead of real values, and proxies can be constant, as they are not going to be changed. Below is a small example of how it might look like. Be aware that all the temporaries are still going to be created in that example but if you want to be smart, you can just save the operations, not the actual results of operations, and calculate only when someone wants to finally get result or a part of it. It might even speed up your code enormously as it helped APL

Also, you might want to make most of the members private.

#include <memory>
#include <iostream>

struct FunctionTreeProxy;
struct FunctionTree;

struct FunctionTreeProxy {
mutable std::auto_ptr<FunctionTree> ft;

explicit FunctionTreeProxy(FunctionTree * _ft): ft(_ft) {}
FunctionTreeProxy(FunctionTreeProxy const & rhs): ft(rhs.ft) {}

FunctionTreeProxy operator+(FunctionTree & rhs);
FunctionTreeProxy operator*(FunctionTree & rhs);
FunctionTreeProxy operator+(FunctionTreeProxy const & rhs);
FunctionTreeProxy operator*(FunctionTreeProxy const & rhs);
};

struct FunctionTree {
int i;
FunctionTree(int _i): i(_i) {}
FunctionTree(FunctionTreeProxy const & rhs): i(rhs.ft->i) {}

FunctionTree * add(FunctionTree & rhs) {
return new FunctionTree(i + rhs.i);
}

FunctionTree * mult(FunctionTree & rhs) {
return new FunctionTree(i * rhs.i);
}

FunctionTreeProxy operator+(FunctionTree & rhs) {
return FunctionTreeProxy(add(rhs));
}

FunctionTreeProxy operator*(FunctionTree & rhs) {
return FunctionTreeProxy(mult(rhs));
}

FunctionTreeProxy operator+(FunctionTreeProxy const & rhs) {
return FunctionTreeProxy(add(*rhs.ft));
}

FunctionTreeProxy operator*(FunctionTreeProxy const & rhs) {
return FunctionTreeProxy(mult(*rhs.ft));
}
};

FunctionTreeProxy FunctionTreeProxy::operator+(FunctionTree & rhs) {
return FunctionTreeProxy(ft.get()->add(rhs));
}

FunctionTreeProxy FunctionTreeProxy::operator*(FunctionTree & rhs) {
return FunctionTreeProxy(ft.get()->mult(rhs));
}

FunctionTreeProxy FunctionTreeProxy::operator+(FunctionTreeProxy const & rhs) {
return FunctionTreeProxy(ft.get()->add(*rhs.ft));
}

FunctionTreeProxy FunctionTreeProxy::operator*(FunctionTreeProxy const & rhs) {
return FunctionTreeProxy(ft.get()->mult(*rhs.ft));
}

int main(int argc, char* argv[])
{
FunctionTree a(1), b(2), c(3);

FunctionTree z = a + b * c;

std::cout << z.i << std::endl;

return 0;
}


Related Topics



Leave a reply



Submit