Anju Maaka
Anju Maaka

Reputation: 274

Why does 'const' behave differently in these two cases?

I have a question about just why a certain thing can be compiled when done "in one step" but can't when done "in two steps". I have three classes;

class Time {
  int mTime;

  int Time::getTimeAsUnix() const {return mTime;}
}

class Travel {
  Time mTimestamp;

  const Time& Travel::getTime() const { return mTimestamp; }
  Time& Travel::getTime() { return mTimestamp; }
}

class Analysis : public Travel {

  int Analysis::getUnixTime() const {
    // Time& t = Travel::getTime();
    // return t.getTimeAsUnix();     // This does NOT compile

    return Travel::getTime().getTimeAsUnix();  // This compiles
  }
}

Anyone knows why, in the Analysis class, the non-commented approach compiles while the commented approach gives me an instant "c++ error: binding 'const Time' to reference of type 'Time&' discards qualifiers" when I try?

Aren't the two the exact same thing when executed??

Upvotes: 0

Views: 135

Answers (3)

Guillaume Racicot
Guillaume Racicot

Reputation: 41750

Okay, let's break down the working version:

int Analysis::getUnixTime() const { // (1)
    // (2) --------v        v----- (3)
    return Travel::getTime().getTimeAsUnix();
}

At (1), the function getUnixTime is defined to work on a constant instance. That means you can only call other constant functions and can't change any member variables.

At (2), Travel::getTime() is called. This call a non-static member function, depite its syntax. But that's okay, it's clear and calls the const version of the function, which return const Time&. A reference to a constant Time object.

At (3), the member function getTimeAsUnix gets called on a const Time&. This is perfect because Time has a member function named that way that is marked to work on constant objects.

So as you see, every objects are constant and you only call constant function.


What went wrong when you broke down the code in two lines?

Let's take a look at the first line in the body of you function:

Time& t = Travel::getTime();

As we stated, Travel::getTime() calls a non-static member function. Since this is a constant object (you're in a const function) then the const version of getTime gets called, just as before.

The return type of the const getTime is const Time&.

Then you do Time& t =. This is where you error is. const Time& cannot be modified. A Time& can be modified. If you refer to a constant object using a mutable reference, then you'd be able to mutate constant object. The language prohibit that!

To fix this, simply use constant references:

const Time& t = Travel::getTime();

Upvotes: 1

Vlad from Moscow
Vlad from Moscow

Reputation: 310930

In this function definition where you shall remove Analysis::

  int Analysis::getUnixTime() const {
     Time& t = Travel::getTime();
     return t.getTimeAsUnix();  
  }

there is called the function

const Time& Travel::getTime() const { return mTimestamp; }

that returns a constant reference. It is this overloaded function is used because the function getUnixTime declared as a const member function.

However the constant reference is assigned to a non-constant reference

     Time& t = Travel::getTime();

so the compiler issues an error.

Upvotes: 4

NathanOliver
NathanOliver

Reputation: 180414

The line

Time& t = Travel::getTime();

needs to be

const Time& t = Travel::getTime();

for it to work. The reason this is needed is because you are inside a const-qualified function. When you are in a const-qualified function all members of the class are considered to be const. That means when you call getTime you call the

const Time& Travel::getTime() const { return mTimestamp; }

version of the function. Trying to assign a const Time& to a Time& wont work because you would be stripping away the constness of the return type.

Upvotes: 5

Related Questions