• Advertisement
Sign in to follow this  

overloading const and the subscript operator

This topic is 2649 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've been working through a link provided by a moderator regarding const stuff. I have got through most of it on my own, hard work but I did it. There are some parts of the next bit of code that I am not too sure of particularly the subscript operator:

class Fred { ... };

class MyFredList {
public:
Fred const& operator[] (unsigned index) const;
Fred& operator[] (unsigned index);
...
};




I have never seen this before. Exactly how does the following line work:

Fred const& operator[] (unsigned index) const;


I would appreciate some insight into this before I proceed with my next queries, thanks.

Share this post


Link to post
Share on other sites
Advertisement
Thanks for the quick reply. That's actually the link I'm reading through and I'm referring to what's going on at part 18[12].

Share this post


Link to post
Share on other sites
Quote:
Original post by adder_noir
I have never seen this before. Exactly how does the following line work:

Fred const& operator[] (unsigned index) const;


I would appreciate some insight into this before I proceed with my next queries, thanks.


You have an operator overload that takes an unsigned index. The const at the end is saying that this method does not mutate the state of the MyFredList. It returns a reference to the constant Fred object that you index.


MyFredList temp;
DisplayFred(temp[0]);
DisplayFred(const Fred & blah) {
cout << ...
}


Since you have both const and non-const versions, the compiler will use the const version when it can, and fall back on the non-const version if you need to mutate the state of your stored Fred objects.

Share this post


Link to post
Share on other sites
What about it are you confused about? The first const?, the second? or the operator []?

The first is the same as saying const Fred&, AFAIK, which specifies that the reference to fred is immutable, though I believe a references are already const, someone more knowledgeable will correct me if I'm wrong.

The second const specifies that this member function does not modify any part of the MyFredList object.

EDIT:: Triple Ninja'd

Share this post


Link to post
Share on other sites
Quote:
Original post by adder_noir
I have never seen this before. Exactly how does the following line work:

Fred const& operator[] (unsigned index) const;


I would appreciate some insight into this before I proceed with my next queries, thanks.


It allows the compiler to select the appropriate operator depending on its usage:

class Array {
public:
int& operator[] ( int idx ) {
return arr[idx];
}

const int& operator[] ( int idx ) const {
return arr[idx];
}

private:
int arr[10];
};

// With our custom class ...
void func1( const Array& a ) {
a[0] = 1; // Error, can't use int& Array::operator[], since a is const
cout << a[0]; // Ok, calls const int& Array::operator[] const
}

void func2( Array& a ) {
a[0] = 1; // Ok, calls int& Array::operator[]
cout << a[0]; // Ok, calls const int& Array::operator[] const
}

// With a raw array...
void test1( const int* arr ) {
arr[0] = 1; // Error
cout << arr[0]; // Ok
}

void test2( int* arr ) {
arr[0] = 1; // Ok
cout << arr[0]; // Ok
}

int main() {
Array myArray;

func1( myArray );
func2( myArray );

int anotherArr[10];

test1( anotherArr );
test2( anotherArr );
}


Share this post


Link to post
Share on other sites
Quote:
though I believe a references are already const
No. In fact, with a reference, it is now possible to modify the original object (as you have a reference, not a value copy). Return by reference avoids copying semantics. It doesn't provide constancy.

Share this post


Link to post
Share on other sites
Quote:
Original post by oler1s
Quote:
though I believe a references are already const
No. In fact, with a reference, it is now possible to modify the original object (as you have a reference, not a value copy). Return by reference avoids copying semantics. It doesn't provide constancy.


I meant that the reference itself is a reference to the fred object it is initialized to, and cannot be used to refer to another fred object. I suppose this means instead that the reference returned cannot be used to call non const member functions?

Share this post


Link to post
Share on other sites
Quote:
Original post by Burnt_Fyr
The first is the same as saying const Fred&, AFAIK, which specifies that the reference to fred is immutable, though I believe a references are already const, someone more knowledgeable will correct me if I'm wrong.


You can't change which variable/object is being referenced once its been initialized, but the variable or object you are referencing can be const or non-const.

Share this post


Link to post
Share on other sites
Great replies chaps thanks! Just need to print them off and then study through them. I intend to be back on later to ask more questions thanks ;o)

Share this post


Link to post
Share on other sites
Quote:
Original post by Rycross
Since you have both const and non-const versions, the compiler will use the const version when it can, and fall back on the non-const version if you need to mutate the state of your stored Fred objects.


I'm fairly sure that the compiler will only use the const version if the instance being called upon is const.

It works by the usual function overloading mechanism. Under the hood, the this pointer is implicitly passed as the first parameter and the const-ness of the this pointer will be how the compiler decides which overload to use.


void a::f();
void a::f() const;


can be thought of as an overload like:


void a::f(a *this);
void a::f(const a *this);


So unless the instance is actually const, the non-const version will be called.

Share this post


Link to post
Share on other sites
Very good replies thanks I have took the time to work through them all. It looks to me like specifying an operator overload is rather like specifying a function. It takes a parameter of sorts, has the curly braces {} to capture specific instructions, and can return a value.

I put some of the code written here into my IDE and it worked well. The error messages all flagged up where they should have.

I have made a recent post along similar lines to this one lately and it seems the same thing is going on here. The compiler will choose the most appropriate 'function' (in this case an operator overload) depending upon the type of parameter that is passed to it, in this case the discerning factor being whether or not it is a constant variable.

Is this assessment correct? Can someone/anyone confirm this for me? Thanks so much ;o)

Share this post


Link to post
Share on other sites
An overloaded operator is a function, just with a funky name and syntactic sugar for calling it. If you felt like it you could use the function name rather than the operator to call the function. Ex:


#include <iostream>

class Fred {};

class MyFredList {
public:
Fred const& operator[] (unsigned index) const {
std::cout << "Fred const& operator[] (unsigned index) const\n";
return f;
}
Fred& operator[] (unsigned index) {
std::cout << "Fred & operator[] (unsigned index)\n";
return f;
}

Fred f;
};



int main(int, char **) {
MyFredList l;
const MyFredList & cl = l;
l.operator[](5);
l[5];
cl.operator[](5);
cl[5];
}

Share this post


Link to post
Share on other sites
I see! SO here the syntax 'operator[]' is kind of like a function name. Thanks Si that's very interesting and informative ;o)

Share this post


Link to post
Share on other sites
I also noticed here that there is only one actual instance of the class MyFredList called 'l'. The other variable 'cl' I noticed is a reference to a constant MyFredList, yet it is assigned to reference the variable 'l' which is a non-const MyFredList.

So surely in this case, the thing that causes the discrimination is the type of variable through which an instance of MyFredList is accessed.

When accessed through its regular handle 'l' the mutator operator overload is called.

Yet when accessed through a reference to const 'cl' the compiler chooses the inspector operator overload based on the type of variable 'cl' is - a reference to const, thus the inspector function/operator overload is called.

Am I correct here? Thanks.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement