Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I access a protected member variable of a base class passed into a function as an argument?

This answer seems to suggest it should work so why does my example kick up a compiler error:

class Class1
{
protected:
    long m_memberVar;
};

class SubClass1: public Class1
{
public:
    void PrintMember(Class1 memberToPrintFrom)
    {
        Console::Write("{0}", memberToPrintFrom.m_memberVar); // <-- Compiler error: error C2248: 'BaseClassMemberAccess::Class1::m_memberVar' : cannot access protected member declared in class 'BaseClassMemberAccess::Class1'
    }
};

[Edit] - changed subclass to a public inheritance on Need4Sleep's suggestion but it makes no difference.

like image 423
Jon Cage Avatar asked Dec 05 '12 12:12

Jon Cage


People also ask

How do you access protected members of base class?

The protected members are inherited by the child classes and can access them as its own members. But we can't access these members using the reference of the parent class. We can access protected members only by using child class reference.

Can you access a protected member of a base class from a member function of the derived class derived in private mode?

Protected members in a class are similar to private members as they cannot be accessed from outside the class. But they can be accessed by derived classes or child classes while private members cannot.

Is Protected members are accessible to the member of derived class?

Protected members that are also declared as static are accessible to any friend or member function of a derived class. Protected members that are not declared as static are accessible to friends and member functions in a derived class only through a pointer to, reference to, or object of the derived class.


3 Answers

In this answer I'll assume that you used public inheritance in your code (which was missing from the question).


[C++11: 11.2/1]: If a class is declared to be a base class (Clause 10) for another class using the public access specifier, the public members of the base class are accessible as public members of the derived class and protected members of the base class are accessible as protected members of the derived class. If a class is declared to be a base class for another class using the protected access specifier, the public and protected members of the base class are accessible as protected members of the derived class. If a class is declared to be a base class for another class using the private access specifier, the public and protected members of the base class are accessible as private members of the derived class.

This covers the case where you're accessing a member of the same object.

However, it's a little curiosity of protected member access that in order to access a protected member of another object, it has to be located within the definition of the same type or a more derived type; in your case, it is in a less-derived type (i.e. a base):

[C++11: 11.4/1]: An additional access check beyond those described earlier in Clause 11 is applied when a non-static data member or non-static member function is a protected member of its naming class (11.2) As described earlier, access to a protected member is granted because the reference occurs in a friend or member of some class C. If the access is to form a pointer to member (5.3.1), the nested-name-specifier shall denote C or a class derived from C. All other accesses involve a (possibly implicit) object expression (5.2.5). In this case, the class of the object expression shall be C or a class derived from C.

That is, you'd have to run this code from within a Class1 member function.

Bjarne mentions this in his book The C++ Programming Language (Sp. Ed.) on page 404:

A derived class can access a base class' protected members only for objects of its own type [...] This prevents subtle errors that would otherwise occur when one derived class corrupts data belonging to other derived classes.

like image 62
Lightness Races in Orbit Avatar answered Sep 18 '22 07:09

Lightness Races in Orbit


Protected members of a base class can be accessed by the derived class only through its self (this) or through another object of the same class, but not generically through the base class. That is the access, and the purpose is that the use of the member is considered restricted to the implementation detail of the class, and as your class is dealing with the base class, it would not know the meaning of the member in this particular case.

There is a workaround you can use to get access which is to provide a protected getter and setter in the base class, often static, that will fetch it or set it for you.

class Class1
{
     protected:
       long m_memberVar; // could even be private

       static long getMemberVar( Class1 const& inst )
       {
          return inst.m_memberVar;
       }

       static long setMemberVar( Class1 & inst, long val )
       {
          inst.m_memberVar = val;
       }

};

And now derived classes (but not general classes) can use the getter and setter methods.

like image 43
CashCow Avatar answered Sep 19 '22 07:09

CashCow


You can also take advantage of the fact that a derived object can be converted to the base object type and that an object can access protected and private members of any object of it's own type. If the base object has an assignment operator that can guarantee all desired members are correctly copied, you can do something like this:

class Class1
{
protected:
    long m_memberVar;
};

class SubClass1 : public Class1
{
public:
    void PrintMember(Class1 memberToPrintFrom)
    {
        SubClass1 tmpSC;
        auto tmpC1 = dynamic_cast<Class1*>(&tmpSC);
        *tmpC1 = memberToPrintFrom;

        cout << tmpSC.m_memberVar << endl;
    }
};

This isn't efficient, but will allow you to get at the base class member without having to add functions to the base class. This is using object slicing to replace the base portion of the temporary derived object with the passed base object's values.

like image 43
bsruth Avatar answered Sep 18 '22 07:09

bsruth