2

I've always wondered is there a way to have a class member without using getters that can only be modified by it's class?

What I'm thinking of is something like this.

class A 
{
    public:
        crazyconst int x;

        void doStuff()
        {
             // Gettin' stuff done
             x = someValue; // OK
        }
};

int main(int argc, char** argv)
{
     A a;
     a.x = 4; // ERROR
}

So it's visible, but read-only for everyone beside its class.

SpaceFace
  • 1,492
  • 3
  • 15
  • 29
  • 1
    Do you mean that int `y = a.x` in the `main` should be legal? If this is the case, pelase say so (or insert it in your example), because otherwise you'll get a lot of answers like "just use `private`!" – vsz Apr 26 '12 at 03:04
  • I think a few odd languages have done something like that, but not C/C++. – Hot Licks Apr 26 '12 at 03:04
  • have public int xMethod(){return x;} and x being private member. – Dhananjay Apr 27 '12 at 04:57

2 Answers2

6

Your class could have a public const reference to a private, non-const data member.

Edit: However, I should point out that doing this would prevent you from using the compiler-generated copy constructor and copy assignment operator.

jamesdlin
  • 81,374
  • 13
  • 159
  • 204
  • 1
    This is a good approach if you aren't worried about `const_cast`. – Ben Voigt Apr 26 '12 at 03:05
  • @BenVoigt: Why worry about `const_cast` in this specific case? – Alok Save Apr 26 '12 at 03:07
  • @Als, in main: `const_cast(a.x) = 4;` – chris Apr 26 '12 at 03:08
  • @chris: Why does that *worry* you? Casting away constness of reference to a non const data is perfectly fine use case for usage of `const_cast`. – Alok Save Apr 26 '12 at 03:09
  • @Als: Because the design specification was that only members of `A` can write to `a.x`. – Ben Voigt Apr 26 '12 at 03:12
  • @Als, the point is that the class should be in control of the member's value. The class should provide some method of setting its value with checking included, to rely on stability. – chris Apr 26 '12 at 03:12
  • @BenVoigt: AFAIU, the requirement is beyond the design specifications to being with. *A non-const member if `public` should be accessible and modifiable by users of the class.* The requirement is over this basic specification So I beleive non standard solution is warranteed – Alok Save Apr 26 '12 at 03:16
  • @Als, the intent is still to only allow the class to modify it, but provide a more user-friendly/C-like interface while keeping that encapsulation. – chris Apr 26 '12 at 03:18
  • 1
    But why worry about `const_cast` in *this specific case*. If you're worried about that, you might as well be worried about somebody doing `#define private public` before including your header. I'm not sure that it's a worthwhile goal to stop people who go out of their way to do stupid things. – jamesdlin Apr 26 '12 at 03:21
  • @Als: He explicitly asked for a member that is not modifiable by users of the class, only by members. Of course, in native code, such a restriction can never actually be enforced. – Ben Voigt Apr 26 '12 at 03:22
  • @BenVoigt: did you see Johannes' template code to gain access to any class member regardless of privacy ? C++ allows to defend against Murphy (somewhat...) but any sufficiently determined opponent can easily trump a protection. Therefore I believe this solution strikes a perfect balance. – Matthieu M. Apr 26 '12 at 08:29
  • @MatthieuM: I'm fully aware that using unsafely-derived pointers, access modifiers can be bypassed. I even said that in my previous comment. And I upvoted this answer. But there's still a difference between making it trivial to overwrite a value and requiring unusual effort. – Ben Voigt Apr 26 '12 at 14:38
4

The answer is no you can't do this without a getter of some sort. However, you can make the getter reusable and you can make the simple syntax of a field work (mostly), without parentheses.

(C++11 required)

template<typename Friend, typename FieldType>
class crazyconst
{
    FieldType value;
    friend Friend;
    FieldType& operator=(const FieldType& newValue) { return value = newValue; }
public:
    operator FieldType(void) const { return value; }
    FieldType operator()(void) const { return value; }
};

class A
{
public:
    crazyconst<A, int> x;

    void doStuff()
    {
        // Gettin' stuff done
        x = 5; // OK
    }
};

int main(int argc, char** argv)
{
    A a;
    int b = a.x;
    int c = a.x(); // also works
}

C++03 version: http://ideone.com/8T1Po

But beware, this will compile but not work as expected:

const int& the_x = a.x;
a.doStuff();
std::cout << the_x;

OTOH, this should be fine:

const auto& ref_x = a.x;
a.doStuff();
std::cout << ref_x;
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720