Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to have a public member, unmodifiable from outside the class, without accessor wrapper function?

Tags:

c++

c++17

As far as I know, this seems to be impossible in a straightforward way. Making the member const makes it const for everyone. I would like to have a read-only property, but would like to avoid the typical "getter". I'd like const public, mutable private. Is this at all possible in C++? Currently all I can think of is some trickery with templates and friend. I'm investigating this now.

Might seem like a stupid question, but I have been surprised by answers here before.

like image 429
rubenvb Avatar asked Feb 18 '17 17:02

rubenvb


2 Answers

A possible solution can be based on an inner class of which the outer one is a friend, like the following one:

struct S {
    template<typename T>
    class Prop {
        friend struct S;
        T t;
        void operator=(T val) { t = val; }
    public:
        operator const T &() const { return t; }
    };

    void f() {
        prop = 42;
    }

    Prop<int> prop;
};

int main() {
    S s;
    int i = s.prop;
    //s.prop = 0;
    s.f();
    return i, 0;
}

As shown in the example, the class S can modify the property from within its member functions (see S::f). On the other side, the property cannot be modified in any other way but still read by means of the given operator that returns a const reference to the actual variable.

like image 68
skypjack Avatar answered Oct 24 '22 12:10

skypjack


There seems to be another, more obvious solution: use a public const reference member, pointing to the private, mutable, member. live code here.

#include <iostream>

struct S {
  private:
    int member;
  public:
    const int& prop;
    S() : member{42}, prop{member} {}
    S(const S& s) : member{s.member}, prop{member} {}
    S(S&& s) : member(s.member), prop{member} {}
    S& operator=(const S& s) { member = s.member; return *this; }
    S& operator=(S&& s) { member = s.member; return *this; }
    void f() { member = 32; }
};

int main() {
    using namespace std;

    S s;
    int i = s.prop;

    cout << i << endl;
    cout << s.prop << endl;

    S s2{s};

    // s.prop = 32; // ERROR: does not compile
    s.f();

    cout << s.prop << endl;
    cout << s2.prop << endl;

    s2.f();
    S s3 = move(s2);

    cout << s3.prop << endl;

    S s4;
    cout << s4.prop << endl;
    s4 = s3;
    cout << s4.prop << endl;
    s4 = S{};
    cout << s4.prop << endl;
}
like image 3
Massa Avatar answered Oct 24 '22 12:10

Massa