0
class A{
    private:
        int a;
    public:
        const int &ref = a;
};

int main() {
    A obj;
    obj.a = 20;     // error cause private
    obj.ref = 30;   // not private but const so ERROR
    return 0;
}

I'm trying to make a member variable accessible but read only through the interface. Currently I've tried this approach and it seems to compile fine. I made a const reference to my original variable int a and made it public. Is there anything that's wrong with this practice that I might be missing out? Or is this example safe and sound to use for practical purposes?

Nothing wrong with providing a member function with const correctness applied (and I've used that too and intend to do so always), but I'm asking is there any thing wrong with this way if I have to provide a variable that is only read-only.

Thankyou :)

  • 5
    What's wrong with the good old accessor function? `int A::get_a() const noexcept { return this->a; }` – 5gon12eder Jan 20 '16 at 17:15
  • 1
    The better practice is to use getters and setters to access your class members. You have more control on the access logics – Pooya Jan 20 '16 at 17:16
  • 6
    Doesn't adding the `const int&` member break copy semantics for the class? – James Adkison Jan 20 '16 at 17:18
  • @JamesAdkison could you explain a bit on that... –  Jan 20 '16 at 17:20
  • 2
    @JamesAdkison Important point (another point is increasing the size of the class, needlessly) –  Jan 20 '16 at 17:21
  • @oopaewem `A obj1; A obj2; obj1 = obj2;` This creates 2 objects then copies 1 to the other but it won't work with a `const &` data member. – James Adkison Jan 20 '16 at 17:23

2 Answers2

3

The standard way to do this in C++ is by making the actual member private but including a public 'getter' method for the interface, as below:

class A{
    private:
        int a;
    public:
        int get_a() const { return a; }

        A() : a(20) {}
};

int main() {
    A obj;
    int n = obj.get_a(); // n = 20
    return 0;
}

The user cannot set the value of A::a but can use A::get_a to retrieve its value.

Archimaredes
  • 1,397
  • 12
  • 26
3
class A{
    private:
        int a;
    public:
        const int &ref = a;
};

is there any thing wrong with this way if I have to provide a variable that is only read-only

There are at least a couple drawbacks with this design decision for class A.

1: Class Size

Also as Dieter Lücking mentions in a comment:

increasing the size of the class, needlessly

2: Copy Semantics

It breaks the compiler generated copy assignment operator. For example, the following code behavior is generally desirable but doesn't work.

A obj1;

// ...

A obj2;

// make changes to 'obj2'

// Update 'obj1' with the changes from 'obj2'
obj1 = obj2; // This copy doesn't work!

More information:

There are certain rules when using references:

  1. A reference must be initialized when it is created. (Pointers can be initialized at any time.)
  2. Once a reference is initialized to an object, it cannot be changed to refer to another object. (Pointers can be pointed to another object at any time.)
  3. You cannot have NULL references. You must always be able to assume that a reference is connected to a legitimate piece of storage.

It may be possible to implement a custom assignment operator but that's more code to maintain (i.e., another drawback in my opinion).

#include <iostream>

class A
{
private:
    int a;

public:
    explicit A(int value) : a(value) {}

    A& operator=(const A& other)
    {
        a = other.a;
        return *this;
    }

    const int& ref = a;
};

int main()
{
    A obj1(10);
    std::cout << "1: " << obj1.ref << "\n";

    A obj2(20);
    std::cout << "2: " << obj2.ref << "\n";

    obj1 = obj2;
    std::cout << "1: " << obj1.ref << "\n";

    return 0;
}

The idiomatic way to address this issue is to use a proper accessor function.

class A {
    private:
        int a;

    public:
        int getA() const { return a; }
};
Community
  • 1
  • 1
James Adkison
  • 9,412
  • 2
  • 29
  • 43
  • I just tried ideone and [found](http://ideone.com/KXlNSP) that indeed copy semantics would be broken. Could you include the reason too? Or should I post another question for them? Thanks :) –  Jan 20 '16 at 17:40
  • @oopaewem I updated the answer and provided some additional references. – James Adkison Jan 20 '16 at 17:56
  • `it may be possible to implement a custom assignment operator`: No it is impossible (only if the reference is a pointer, it would be possible, but ugly again) –  Jan 20 '16 at 18:25
  • @DieterLücking I didn't think it was possible either but I tried the [following](http://ideone.com/pA0CBB) and it appeared to work correctly (i.e., the custom assignment operator ignores the `const int&` data member). I've removed that comment from my answer but I'm curious why my example code seems to work? – James Adkison Jan 20 '16 at 18:35
  • @James Adkison I am wrong (I was thinking about non internal references). That makes the answer wrong, too –  Jan 20 '16 at 18:45
  • @DieterLücking I tried to delete the answer but it won't let me. How would you recommend I proceed? – James Adkison Jan 20 '16 at 18:52
  • @DieterLücking For now, I just tried to update the answer. Is there a way for a moderator to delete the answer? – James Adkison Jan 20 '16 at 18:56
  • @JamesAdkison Place a big "This is wrong, but accepted" in your answer –  Jan 20 '16 at 18:57
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/101216/discussion-between-james-adkison-and-dieter-lucking). – James Adkison Jan 20 '16 at 18:57