accessing a protected member of a base class in another subclass
When foo
receives a FooBase
reference, the compiler doesn't know whether the argument is a descendant of Foo
, so it has to assume it's not. Foo
has access to inherited protected members of other Foo
objects, not all other sibling classes.
Consider this code:
class FooSibling: public FooBase { };
FooSibling sib;
Foo f;
f.foo(sib); // calls sib.fooBase()!?
If Foo::foo
can call protected members of arbitrary FooBase
descendants, then it can call the protected method of FooSibling
, which has no direct relationship to Foo
. That's not how protected access is supposed to work.
If Foo
needs access to protected members of all FooBase
objects, not just those that are also known to be Foo
descendants, then Foo
needs to be a friend of FooBase
:
class FooBase
{
protected:
void fooBase(void);
friend class Foo;
};
How can I access base class's protected members through derived class?
There is not more to it than you already discovered. Derived instances may acces their protected members and those of other derived instances but not those of base class instances. Why? Because thats how protected
works by definition.
For more details I refer you to cppreference (emphasize mine):
A protected member of a class Base can only be accessed
1) by the members and friends of Base
2) by the members and friends (until
C++17) of any class derived from Base, but only when operating on an
object of a type that is derived from Base (including this)
Cannot access protected member of another instance from derived type's scope
The rule in [class.access.base] is:
A member
m
is accessible at the point R when named in classN
if [...]
m
as a member ofN
is protected, and R occurs in a member or friend of classN
, or in a member of a classP
derived fromN
, wherem
as a member ofP
ispublic
,private
, orprotected
There's a lot of letters in there. But there are basically two conditions:
R
is in a member or friend of the class. This handles thed.prot
example - we are in a member ofDerived
while accessing a protected member ofDerived
.R
is in a member of a derived class and the member being accessed is a member of the derived class instance. This handles theb.prot
example - we are in a member of a derived class, butprot
is not a member of the derived class.
In other words, Derived
can access Base
's protected members - but only in the case that it is accessing its own subobject's protected members. It cannot access other Base
object's protected members. This makes sense when you consider that this other Base
could easily be SomeOtherDerived
, in which case that's just another unrelated object to us that we have no special access privileges to.
Why can't I access a protected member from an instance of a base class?
You can access the protected
members of a base class only through a pointer or reference to an object of the derived type.
If you change
void copy_a_from_bar(bar& o){
a = o.a;
}
to
void copy_a_from_bar(bar& o){
foo& foo_ref = o;
a = o.a; // OK. Accessing it through `bar&`
a = foo_ref.a; // Not OK. Accessing it through `foo&`
}
you will see the same error.
This SO answer gives an indication of why allowing access to the protected
members of the base class will be a potential breach of the protected
status of the base class members.
Say you have:
class baz : public foo
{
void update_a(foo& f)
{
f.a = 20;
}
};
and use:
bar x;
baz z;
z.update_a(x);
If this were allowed, baz
will be able to change the values of members of bar
. That is not good.
Why can't a subclass of a subclass access protected member of its ancestor?
When you write
class Dog : Animal { … };
what you're really writing is
class Dog : private Animal { … };
because the default access specifier for classes defined with class-key class
is private
[class.access.base]/2 (fancy way of saying: if you have a class
that class will inherit everything to be private unless you explicitly say otherwise). Private inheritance means all protected and public members of the base class will be private in the derived class. Since Dog
inherited all the Animal
stuff privately, it's not accessible to BigDog
anymore (which, by the way, also inherits all the Dog
stuff privately). What you most likely wanted to write is
class Dog : public Animal { … };
and
class BigDog : public Dog { … };
Note: if you had a struct
, the default would be public
.
Access protected members of base class in grandchild class
Your problem is that you're inheriting from you base classes privately, so public and protected members of the base class get the same access control as private members of the derived class. While possible, private inheritance is a very specific tool and used rarely. In the vast majority of cases, you want public inheritance:
class SmallBox: public Box {
protected:
double height;
};
class TooSmall: public SmallBox {
public:
void setSmallWidth( double wid );
void setHeight(double hei);
double getSmallWidth( void );
double getHeight(void);
};
Done this way, protected members will be visible to all descendants (not just direct children) normally.
If, for some reason, you want to stick with private inheritance, you will have to "promote" the privately-inherited protected members back to protected:
class SmallBox:Box {
protected:
double height;
using Box::width; // make it protected again
};
class TooSmall:SmallBox {
public:
void setSmallWidth( double wid );
void setHeight(double hei);
double getSmallWidth( void );
double getHeight(void);
};
Accessing protected members in a derived class
A class can only access protected members of instances of this class or a derived class. It cannot access protected members of instances of a parent class or cousin class.
In your case, the Derived
class can only access the b
protected member of Derived
instances, not that of Base
instances.
Changing the constructor to take a Derived
instance will solve the problem.
Why can't I access a protected member variable of a base class passed into a function as an argument?
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 thepublic
access specifier, thepublic
members of the base class are accessible aspublic
members of the derived class andprotected
members of the base class are accessible asprotected
members of the derived class. If a class is declared to be a base class for another class using theprotected
access specifier, thepublic
andprotected
members of the base class are accessible asprotected
members of the derived class. If a class is declared to be a base class for another class using theprivate
access specifier, the public andprotected
members of the base class are accessible asprivate
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 classC
. If the access is to form a pointer to member (5.3.1), the nested-name-specifier shall denoteC
or a class derived fromC
. All other accesses involve a (possibly implicit) object expression (5.2.5). In this case, the class of the object expression shall beC
or a class derived fromC
.
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.
Related Topics
What Is the Status of N2965 - Std::Bases and Std::Direct_Bases
Constant References with Typedef and Templates in C++
Why There Is No Placement Delete Expression in C++
Declaring Multiple Object Pointers on One Line Causes Compiler Error
How to Set File Permissions (Cross Platform) in C++
How to Access a Local Variable in Outer Scope in C++
Why Is Memset() Incorrectly Initializing Int
Spirit Qi Attribute Propagation Issue with Single-Member Struct
Opengl - Mouse Coordinates to Space Coordinates
Detect If Program Is Running with Full Administrator Rights
Why Does 'Std::Vector<Int> B{2};' Create a 1-Element Vector, and Not a 2-Element One
Why Should the Assignment Operator Return a Reference to the Object
Forward Declare a Standard Container
How to Use String.Substr() Function
How to Get the Digits of a Number Without Converting It to a String/ Char Array