user1353535
user1353535

Reputation: 681

Calling constant function from another class object

Here is the code that i have

class A
{
public:
    void Func1() const;
};

class B
{
public:
    A* a;
    void Func2() const
    {
        // do something with 'a'
    }
};

void A::Func1() const
{
    B b;
    b.a = this;
    b.Func2();
}

Now obviously this is giving me an error in the line, because I'm trying to convert from const to non-const.

b.a = this;

Is there any way to call Func2 without having to cast away the constness of this. Since Func2 is a const function anyways, it will not change this.

Upvotes: 2

Views: 552

Answers (4)

Jon
Jon

Reputation: 437336

If class B is always going to work with *a as a const object then as others have said all it takes is to simply change the declaration to

public: const A* a

At this point I should mention that the constness of B::Func2 is a red herring because it has absolutely no relation to the constness of B::a. That B::Func2 is const means that it's not allowed to change the value of a; however, it is allowed to dereference a and mutate the resulting object.

Now, if class B has both const and non-const operations with respect to *a then your class design needs to change. It would be much better if you switched class B to use a const A* a as above, and added another class D : public B that encapsulates all the mutating operations. In addition, a should be hidden behind a property setter; this allows you to do things like

class B {
    const A* a;
public:
    void setA(const A* a) { this->a = a; }
    void Func2() const {}
};

class D : public B {
    A* a;
public:
    using B::setA;
    void setA(A* a) { 
        this->a = a;
        static_cast<B*>(this)->setA(const_cast<const A*>(a));
    }
    void Func3() { /* do something to D::a */ }
};

With this scheme both B and D keep independent, suitably typed pointers to the object to be accessed. If setA is called on a B, or on a D with a const A* parameter then only B::a is set. If setA is called on a D with an A*, then both B::a and D::a are properly set. This has become possible because by abstracting the member behind a setter you can then overload the setter on the constness of its parameter.

Upvotes: 1

Richard J. Ross III
Richard J. Ross III

Reputation: 55543

Yes, make the A * constant:

class B {
public:
    const A *a

...
};

Upvotes: 1

Luchian Grigore
Luchian Grigore

Reputation: 258568

Func2 may not change this, but b.a is not const and you're free to change it afterwards. There's no right way to do this, although workarounds exist, such as mutable or const_cast.

It's the sign of a faulty design.

Upvotes: 1

mfontanini
mfontanini

Reputation: 21900

You have to declare the A* as const:

class A
{
public:
    void Func1() const;
};

class B
{
public:
    const A* a;
    void Func2() const
    {
        // do something with 'a'
    }
};

void A::Func1() const
{
    B b;
    b.a = this;
    b.Func2();
}

Since in A::Func1, the this pointer is const.

Upvotes: 3

Related Questions