1

There is a rule about const methods. If the method is const, and we are trying to use another function at the same method, so it should be const as well. Otherwise, we will have a compilation error. I was trying to find the declaration of abs() function in math.h library, and here is what I found: Declarations of abs() It means that the abs() function is not const, but when I use it inside const method I am not having a compilation error. can somebody explain why is that?

class D:public B,C
{
public:
    D()
    {
        cout<<"This is constuctor D"<<endl;
    }

    int fun3() const;

    ~D()
    {
         cout<< "Destructor D"<<endl;
    }
};

int D::fun3() const
{
    int x=-3;

    return abs(x);
}
selbie
  • 100,020
  • 15
  • 103
  • 173
  • 12
    `abs()` is a free function. `const` doesn't mean anything for free functions. – πάντα ῥεῖ Mar 09 '19 at 17:14
  • 1
    *"If the method is const, and we are trying to use another function at the same method, so it should be const as well."* This is only necessary for non-static member function called on the same object as the said method. – HolyBlackCat Mar 09 '19 at 17:15
  • 1
    Note that since `abs()` accepts its parameter _by value_, it will always be working on a copy of the object you pass, and the original object will never be modified. If abs instead accepted a reference to an int: `abs(int&)` and you tried to pass a `const int`, you should except a compile error. – alter_igel Mar 09 '19 at 17:17
  • 2
    Another point: when you're inside a `const` member function, it means that the `this` object is `const`, and all its members are `const` by extension. In your function, `x` is just a local variable and not a member of `this`, and so this `const`-ness doesn't apply. – alter_igel Mar 09 '19 at 17:22
  • @alter igel Well if you try to make data member and pass it to abs() you still won't get any compilation error, so basically you can cancel the constness of the function – Valeri Grishin Mar 09 '19 at 17:28
  • 2
    @ValeriGrishin see my first comment. `abs()` accepts data _by value_, which means it receives _a copy_ of what you pass. This way, it can never modify what you pass it externally, and so it doesn't matter if what you pass is `const` or not. – alter_igel Mar 09 '19 at 17:41
  • `const` prevents changing (non-`mutable`) members of the object. It doesn't prevent changing non-members of the object, such as the `x` in your example. Even though `abs()` is not `const`, it accepts argument by value, so does not change the value seen by the caller. Try giving `D` a non-static member named `y` of type `int`, and do an assignment of `y = abs(x)` in your function, and you will find the assignment will be rejected. – Peter Mar 09 '19 at 18:31

4 Answers4

3

There is a misunderstanding here about the constraint of const member functions.

A const member function can call whatever function it wants, as long as it doesn't change the state of the object. So fun3() compiles perfectly well, since it doesn't change any member variable and it doesn't call any non-const member functions for the same object.

Important note: public B,C might not be what you think: it means that D inherits publicly from B and privately from C. If you want it to inherit publicly from C you must state public B, public C.

Christophe
  • 68,716
  • 7
  • 72
  • 138
  • If you will try to make _x as a member variable and apply abs(_x) at the code that I wrote you won't have any compilation error even though you are changing that member variable and this pointer by that. – Valeri Grishin Mar 09 '19 at 20:16
3

To start, unlearn what you think you know. Let's look at what it means to be a const member.

class D {
public:
    int fun2();
    int fun3() const;
};

What does this declare? There is a class called D. There are two member functions fun2 and fun3, each taking a hidden this parameter and no other parameters.

Hold on! A hidden parameter? Well, yes. You can use this within the function; its value has to come from somewhere. All non-static member functions have this hidden parameter. However, not all non-static member functions have the same type of hidden parameter. If I were to show the hidden parameter, the declarations would look like the following:

int D::fun2(D * this);
int D::fun3(const D * this);

Notice how the const exists inside this pseudo-declaration? That is the effect of declaring a const member function: this points to a const object rather than a non-const object.

Now back to the question. Can fun3 call fun2? Well, fun3 would pass its this pointer (a pointer-to-const-object) to fun2, which expects a pointer-to-object. That would mean losing constness, so it's not allowed.

Can fun3 call abs? Well, fun3 would pass an integer to abs. No problem here. The problem is losing the constness of this. As long as you avoid that, you're fine.

JaMiT
  • 14,422
  • 4
  • 15
  • 31
  • If you will try to make _x as a member variable and apply abs(_x) at the code that I wrote you won't have any compilation error even though you are changing that member variable and this pointer by that. – Valeri Grishin Mar 09 '19 at 20:31
  • @ValeriGrishin I don't understand. `abs(_x)` does not change the value of `_x`. So, right, still no error. – JaMiT Mar 09 '19 at 23:15
  • if _x is negative abs(_x) will be positive, it changes the value of _x. – Valeri Grishin Mar 10 '19 at 06:43
  • @ValeriGrishin No, it does not. If `_x` is negative, `abs(_x)` will be positive, yes. However, the positive value is not stored in `_x`. The statement `return abs(_x);` inside `fun3()` would cause `fun3()` to have a positive value, while `_x` remains negative. – JaMiT Mar 10 '19 at 10:03
0

const being applied to a method just means that the this pointer, i.e. the pointer to the instance on which the method is operating, is const. This implies that it cannot modify the fields and can only call const methods on it, not in general.

Calling a free function is perfectly acceptable, or even calling a non-const method on a different object of the same class, as long as such object is not const.

Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
0

Consider this

#include <iostream>

int f(int num) { return num+1; }
int fr(int& num) { return num+1; }
int fcr(const int& num) { return num+1; }

class D
{
public:
    int value= 0;

public:
    void f1() { value++; }
    int f2() const { return value; }
    int f3() { return value; }
    static void f4() { std::cout << "Hello" << std::endl; }
    void f5() const;
};

void D::f5() const
{
    // Prohibited:
    // f1(); // modifies this
    // f3(); // might modify this
    // value++; // modifies this->value, thus modifies this
    // value= 2; // modifies this->value, thus modifies this
    // value= abs(value); // modifies this->value, thus modifies this
    // fr(value); // takes value by reference and might modify it
    // 
    // Permitted:
    f2(); // const function, does not modify this
    std::cout << value << std::endl; // independent function, does not modify this; read access to this->value is const
    std::cout << abs(value) << std::endl; // independent function, does not modify this; read access to this->value is const
    f4(); // static function, does not modify this
    f(value); // function, does not modify this; takes value as read only (makes copy)
    fcr(value); // function, does not modify this; takes value as read only by reference

    D otherObject;
    otherObject.f1(); // modifies otherObject (non const), does not modify this
}

int main()
{
    const D d;
    d.f5();
}

Whenever you call a member function like f4() inside f5() you're passing an implicit this pointer equivalent to this->f4(). Inside f5(), as it is const, this is not of type D* but rather const D*. So you can't do value++ (equivalent to this->value++ for a const D*. But you can call abs, printf or whatever that does not take this and tries to modify it).

When you take this->value if this type is D* it's type is int and you're free to modify it. If you do the same with a const D*, its type becomes const int, you cannot modify it, but can copy it and access it as a const reference for reading.

Mirko
  • 1,043
  • 6
  • 12