Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does "const" differ in C and C++?

Tags:

c++

c

constants

How does the const qualification on variables differ in C and C++?

from: Does "const" just mean read-only or something more?

"What prompted this question was this answer: https://stackoverflow.com/questions/4024318#4024417 where he states const "just" means read-only in C. I thought that's all const meant, regardless of whether it was C or C++. What does he mean?"

like image 498
Kim Sun-wu Avatar asked Dec 20 '10 02:12

Kim Sun-wu


2 Answers

const in C cannot be used to build constant expressions.

For example :

#include <stdio.h>
int main()
{
   int i = 2;
   const int C = 2;
   switch(i)
   {
      case C  : printf("Hello") ;
      break;

      default : printf("World");
   }
}

doesn't work in C because case label does not reduce to an integer constant.

like image 156
Prasoon Saurav Avatar answered Oct 06 '22 01:10

Prasoon Saurav


const means that you promise not to mutate the variable. It could still be changed.

class A {
  public:
    A(const int& a);
    int getValue() const;
    void setValue(int b);
  private:
    const int& a;
};
A::A(a) : a(a) {}
int A::getValue() const {
    return a;
}
void A::setValue(int b) {
    a = b;  // error
}

int main() {
    int my_a = 0;
    A a(my_a);
    std::cout << a.getValue() << std::endl;  // prints 0
    my_a = 42;
    std::cout << a.getValue() << std::endl;  // prints 42
}

No method A::* may change a, but main can. That much is identical between C and C++.


What C++ does have are a couple (limited) ways to bypass const, which are supposed to discourage programmers from discarding const inappropriately.

Take a class like this.

class A {
  public:
    A();
    int getValue();
  private:
    static int expensiveComputation();
    int cachedComputation;
};

A::A() : cachedComputation(0) {}

A::getValue() {
    if (cachedComputation == 0)
        cachedComputation = expensiveComputation();
    return cachedComputation;
}

cachedComputation implicitly means this->cachedComputation. Keep this in mind.

int main() {
    A a1;
    const A a2;
    std::cout << a1.getValue() << std::endl;
    std::cout << a2.getValue() << std::endl;  // error
}

a2.getValue() is illegal, because a non-const method is being called on a const A a2. One could cast away the const-ness…

    std::cout << ((A&)a2).getValue() << std::endl;            // C-style cast
    std::cout << const_cast<A&>(a2).getValue() << std::endl;  // C++-style cast

The second is preferred, because the compiler will check that only the const-ness is being casted, nothing else. However, this is still not ideal. Instead, there should be a new method added to the class.

class A {
  public:
    int getValue() const;
};

A::getValue() const {
    if (cachedComputation == 0)
        cachedComputation = expensiveComputation();  // error
    return cachedComputation;
}

Now there is a const method, so a2.getValue() is fine. However, the trailing const means that the method is given a const A *this pointer, not an A *this pointer like usual, making this->cachedComputation a const int & that cannot be mutated.

const_cast could be applied inside the method, but better would be to change this one member's declaration.

class A {
  private:
    mutable int cachedComputation;
};

Now, even with a const A *this, this->cachedComputation can be mutated without casting.

like image 27
ephemient Avatar answered Oct 06 '22 02:10

ephemient