0

I want to return a const reference so I cannot change the object itself but I can call their non-const methods. But I don't know how to do it.

With pointers is easy, I can choose between a const pointer (const myclass*) or a pointer to const values (myclass const*). But with references it seems not working the same way, all I've got it is a reference to a const object so I cannot call non-const methods.

I'm sure I'm doing something wrong.

class A {
   int a;
public:
   auto get() const { return a; }
   auto set(int i) -> void { a = i; }
};

class B {
  A a_;
public:
  auto get() const -> const A& { return a_; }
};

I can do:

B b;
cout << b.get().get();

But not:

B b;
b.get().set(100); // compiler error

I don't want

class B {
  A a_;
public:
  auto get() -> A& { return a_; }
};

B b;
A a;
b.get() = a; // I don't want this!
Victor Marzo
  • 713
  • 5
  • 10
  • 5
    "*I want to return a const reference so I cannot change the object itself but I can call their non-const methods*". These are contradictory requirements. – cigien Oct 16 '20 at 12:02
  • 3
    See [What is the xy problem?](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). Why do you think you need this? What is the actual problem you are trying to solve? – 463035818_is_not_an_ai Oct 16 '20 at 12:03
  • 2
    You can't change which object a reference refers to, so a "const reference to non-const" (`T& const`) in the manner of `T* const` would be meaningless. – molbdnilo Oct 16 '20 at 12:06
  • @molbdnilo you can have a `const T&` that references a (non-const) `T`, but I think thats the wrong direction for this question – 463035818_is_not_an_ai Oct 16 '20 at 12:07
  • 1
    If you want to be able to modify the object through its members, but not assign to it, you can't do that with pointers either (unless you make it entirely non-assignable). – molbdnilo Oct 16 '20 at 12:18
  • 2
    *"I want to return a const reference so I cannot change the object itself"* - You say this but then your example tries to change the object by calling `set(100)`...? – Galik Oct 16 '20 at 12:19
  • `b.get() = a` *doesn't change the object itself* by the way. It just calls `b.get().operator=(a);` which overwrites all the members of b with the ones from a, but b is still b and not a. – user253751 Oct 16 '20 at 12:33
  • _"I can choose between a const pointer (const myclass*) or a pointer to const values (myclass const*)."_ -- The two declarations are the same thing. A "const pointer" would be `myclass * const` so that `const` applies to `*` rather than to `myclass`. See [What is the difference between const int*, const int * const, and int const *?](https://stackoverflow.com/questions/1143262/what-is-the-difference-between-const-int-const-int-const-and-int-const) – JaMiT Oct 16 '20 at 13:34
  • Hmm... are you trying to ask about [Changing References in C++](https://stackoverflow.com/questions/9695657/changing-references-in-c)? – JaMiT Oct 16 '20 at 13:39

2 Answers2

1

Problems returning a const reference (no a reference to a const)

There is technically no such thing as const reference. References do not have top level cv-qualifiers. Const reference colloquially means a reference to const.

I want to return a ... reference so I cannot change the object itself

Objects cannot be modified through references to const, so that would work.

... but I [want to] call their non-const methods.

Non-const member functions can be called only through references to non-const. There is no category of reference that can satisfy both of your wants. They are contradictory.

With pointers is easy, I can choose between a const pointer (const myclass*) or a pointer to const values (myclass const*).

Those do not achieve what you want either. You can modify the pointed object through a const pointer (to non-const), and you cannot call const member functions of the pointed object through a (non-const) pointer to const. Neither achieves your both wants.


P.S. Returning a const (or volatile) qualified pointer - or any other built-in type - is meaningless because function calls to such function are prvalue expressions and prvalues of non-class types do not have cv-qualifiers, so the qualifiers of such return type would always be ignored. This is not to be confused with returning pointer to cv-qualified types which is meaningful.

eerorika
  • 232,697
  • 12
  • 197
  • 326
1

You can't have "partial mutability" in that way, not without removing assignment completely from A.
(Despite your claim that this is easy with pointers, that situation is exactly the same - you need to either disallow b.get()->set(100) or allow *b.get() = a.)

One thing you can do is add a level of indirection by way of a proxy object:

class A_Setter
{
public:
    A_Setter(A* a): the_a(a) {}
    A_Setter& operator=(const A_Setter&) = delete;

    void set(int x) { the_a->set(x); }
private:
    A* the_a;
};

class B {
    A a_;
public:
    A_setter get() { return A_setter(&a_); }
};

Now b.get().set(100); will compile, not b.get() = a;.

molbdnilo
  • 64,751
  • 3
  • 43
  • 82