0

I am trying to learn about inheritance, and how private, protected, and public variables work.

My understanding is that a class's private variables can only be read by members of that class, and that protected variables can be read by members of that class, and by derived classes.

I am implementing some code to make sure that I understand this correctly, and I seem to be able to access variables that I didn't expect to be able to.

I have a class Polygon, and a derived class Triangle. I wrote a set of read() functions in the public areas of those classes to read their variables. These functions are overloaded so that with no arguments, read() will return the variables of the calling object, or alternatively, read(&Poly) can take another polygon as an argument and return the other polygon's variables.

#include <iostream>
using namespace std;

class Polygon;
class Triangle;

class Polygon {
private:
    int privatePoly = 1;
protected:
    int protectedPoly = 10;
public:
    int publicPoly = 100;


    // Setters
    void setPrivate (int x) { privatePoly = x; }
    void setProtected (int x) { protectedPoly = x; }

    // Read
    int readPrivate (const Polygon& inPoly) { return inPoly.privatePoly; }
    int readProtected (const Polygon& inPoly) { return inPoly.protectedPoly; }
    int readPublic (const Polygon& inPoly) { return inPoly.publicPoly; }
};

class Triangle : public Polygon {
private:
    int privateTriangle = 3;
protected:
    int protectedTriangle = privateTriangle*10;
public:
    int publicTriangle = privateTriangle*100;


    // Read Triangle variables
    int readPrivate_Tri () { return privateTriangle; }
    int readProtected_Tri () { return protectedTriangle; }
    int readPublic_Tri () { return publicTriangle; }

    int readPrivate_Tri (const Triangle& inTri) { return inTri.privateTriangle; }
    int readProtected_Tri (const Triangle& inTri) { return inTri.protectedTriangle; }
    int readPublic_Tri (const Triangle& inTri) { return inTri.publicTriangle; }

};

I instantiated one object of each type, Polygon P1, and Triangle T1, and tried to read P1's private variables from the derived class T1, expecting this to fail since private variables shouldn't be readable by derived classes. It didn't.

int main(int argc, const char * argv[]) {

    Polygon P1;
    Triangle T1;

    // To make sure T1's polygon variables are different from P1's.
    T1.setPrivate(2);
    T1.setProtected(20);

    // T1 reading P1
    cout << "T1.readPrivate(P1): " << T1.readPrivate(P1) << endl;
    cout << "T1.readProtected(P1): " << T1.readProtected(P1) << endl;
    cout << "T1.readPublic(P1): " << T1.readPublic(P1) << endl << endl;

    return 0;
}

This produces

T1.readPrivate(P1): 1
T1.readProtected(P1): 10
T1.readPublic(P1): 100

I thought perhaps this was related to the fact that the read functions were originally declared in the parent Polygon class (and that the private/protected specifiers referred to where the functions were declared rather than who the calling object was), so I gave the Triangle class its own copy of the readPolygon(&Polygon) variables. The following was added to the definition of the Triangle class:

// Read Polygon variables with separate function unique to Triangle class
int readProtected_P_from_T (const Polygon& inPoly) { return inPoly.protectedPoly; }
int readPublic_P_from_T (const Polygon& inPoly) { return inPoly.publicPoly; }

Where the readPublic_P_from_T() function was added to check the function format.

This doesn't compile, with the error: "'protectedPoly' is a protected member of 'Polygon'"

I expected this to work because I thought a derived class could see protected variables.

And I expected the first readPrivate function to not work, when called from the derived class.

Could someone please explain how these access specifiers work?

  • `public` is the API facing toward users of the object. `protected` is the API facing towards the classes that inherit from that class. `private` is the API internal to the class itself. This should all be in your book that you are learning from. – Eljay Aug 14 '19 at 02:42
  • `protected` in addition to providing access to members that inherit from that class, also make the members available to `friend` classes as well where needed (such as I/O overloading of `<<` and `>>`, etc...) See [access specifiers](https://en.cppreference.com/w/cpp/language/access). You may just want to bookmark and keep open [cppreference.com](https://en.cppreference.com/w/Main_Page), as it is one of the finest net references available. – David C. Rankin Aug 14 '19 at 03:10
  • @DavidC.Rankin Doesn't `friend` classes have full access (including `private`)? – iBug Aug 14 '19 at 03:15
  • @iBug - both, with a few caveats. See the link I posted for `access specifiers` above. – David C. Rankin Aug 14 '19 at 03:15
  • "I expected this to work because I thought a derived class could see protected variables." Yes, but no in this case. You can access the members that you have inherited, but not members of an object of that type. See [the question that Chipster linked](https://stackoverflow.com/q/6986798). – iz_ Aug 14 '19 at 03:50
  • It's very normal to have private members which can only be accessed and modified by other classes via public methods. It encapsulates the internal workings of your class and gives you a placeholder should you need additional processing when a member of the class is altered. – Mick Aug 14 '19 at 04:34

2 Answers2

0

Any function within a class can access its private variables. It can access protected and public variables from iherited classes as well.

If the function itself is public, anyone can call it.

Usually private variables are used for internal needs of the class by its member functions and are not intended for the public. However, public member functions can use them for doing a particular action.

In your case all member functions are public. Therefore, you can call them to access any internal data inside the class.

If you want to fail, try to access the member data directly without the function. For example

class A {
   int a = 0;
public:
   int b = 1;
   int getA() {
       return a;
   }
};


 A c1;
 cout << c1.a << c1.b;

the compiler will fail on the member access, because a is private.

On the other hand, if you use the getA() function, it will work, because the function itself can access private members:

cout << c1.getA() << c1.b;
Serge
  • 11,616
  • 3
  • 18
  • 28
  • I did indeed get the result you describe (as I'd hoped!) when trying to directly access the variables with the dot notation in main. My objection is not to being able to call T1.readPrivate() from main, but as to why a function called by an object of a derived class can read a variable in a parent class object. And if this is because the access depends on where the initial definition is, then why, when I define a read function in the derived class, can it not see the protected variables of the parents class (which I thought would be visible to the derived class?) – Dion Silverman Aug 14 '19 at 03:02
  • By "Any function within a class can access ...protected and public variables from inherited classes as well." Do you mean from classes it inherits from (parent classes) or that it can access protected variables of derived classes? – Dion Silverman Aug 14 '19 at 03:18
  • Yes, the function can access protected vars from the parent class. BTW, the member function themselves can also be declared as private or protected. Calling (accessing) them is also governed by the same access rules. – Serge Aug 14 '19 at 10:29
0

My understanding is that a class's private variables can only be read by members of that class, and that protected variables can be read by members of that class, and by derived classes.

That understanding is correct.

I instantiate one object of each type, Polygon P1, and Triangle T1, and tried to read P1's private variables from the derived class T1, expecting this to fail since private variables shouldn't be readable by derived classes. It didn't.

readPrivate() is a member of Polygon, so it has no problem reading Polygon's internals.

(Public) Inheritance allows Triangle to have these functions too, but since they are actually at the Polygon level, it doesn't have a problem.

This doesn't compile, with the error: "'protectedPoly' is a protected member of 'Polygon'"

You are running into this situation. That link explains that problem and its answer far better than I could, so I'll leave it right there.

Could someone please explain how these access specifiers work?

You seem to have a pretty good grasp on the subject already, except with a few minor discrepancies. However, if you wish to read up more on inheritance, here is a useful resource on it.