2
#include <iostream>

using namespace std;

class R {
protected:
    int a;
public:
    int read(void) {
        return a;
    }
};

class RW : public R {
public:
    void write(int _a) {
        a = _a;
    }
};

int main(void) {
    int a;
    R *r = (R *)&a;
    RW *rw = (RW *)&a;

    rw->write(1);
    cout << dec << r->read() << endl;
    cout << dec << rw->read() << endl;

    return 0;
}

I want to make a class that can only read (class R) and a class can read and write (class RW). Is there any reason I should not do this in oop? and also any reason not to use the 'protected' here? Please help me, thanks for any replies!

P.S. I don't want to define duplicated 'private int a;' on both classes, because the offset of 'int a in class RW' and size of 'class RW' is not the same to the 'class R' anymore.

JSK
  • 45
  • 5
  • You could achieve the same thing with a single class by making `read` a `const` function. – Mark Ransom Dec 28 '21 at 04:51
  • @Mark Ransom Thanks for the first reply! but in my understanding if I make a single class then I have to open the write function as well. I want to hide write function. any read is welcomed. – JSK Dec 28 '21 at 05:00
  • 1
    When you have a single class you would just use const and non-const versions of it. While the `write` function would still be visible on the const object, you wouldn't be able to call it. The compiler would give you an error. – Mark Ransom Dec 28 '21 at 05:03
  • @Mark Ransom aha... I got it. That's more efficient way and not tricky way to achieve the goal. But could you also answer if my way is that tricky in oop and cpp? isn't that 'RW has R' relationship? – JSK Dec 28 '21 at 05:08
  • @Mark Ransom And when I merged them into one RW class and then defined a const RW object, the read is also not available. – JSK Dec 28 '21 at 05:18
  • The `read` function has to be marked `const` to be usable from a const object. And by the way there was nothing wrong with your original approach, I was just trying to point out that C+ has a better way. – Mark Ransom Dec 28 '21 at 05:30
  • @Mark Ransom your way is great and working well. Thanks. – JSK Dec 28 '21 at 05:34
  • One more thing I just noticed - you can't just cast a pointer to `int` to a pointer to your class. That could lead to undefined behavior. If you must, you could make the member a pointer or reference and initialize it in the constructor. – Mark Ransom Dec 28 '21 at 05:40
  • @Mark Ransom I have checked they have the same size and it works fine. What could be the problem? I am gonna use (class RW *) and (class R *) to cast a shared memory which is already placed in physical memory. – JSK Dec 28 '21 at 06:09

1 Answers1

2

any reason not to use the 'protected' here?

protected member variables are sometimes discouraged in favor of protected member functions that accesses private member variables - and you don't need duplicate as if you make it private in R. You could add a protected member function to write to it instead.

class R {
public:
    int read() const { // not `void` and add `const`
        return a;
    }

protected:
    void write(int A) {
        a = A;
    }

private:
    int a;
};

class RW : public R {
public:
    void write(int A) {
        R::write(A);
    }
};

Without any added validation in R::write, the above basically does the same as your code, but a is private.

Your original version is not wrong though. As can be seen here: Should you ever use protected member variables? there's no definite "no, you should never use protected member variables".

One may argue that if they are only protected, one can just inherit the class and treat them as public and if changing such member variables doesn't require any validation of any sort, they could be made public to start with. One would have to look at it from case to case.

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108