This question already has answers here:
Protected data in parent class not available in child class?
(4 answers)
Closed 6 years ago.
Can anyone explain to me why (as in, "why is the language this way?") the following code has a compile error at the second line of B::C::bar?
class A
{
public:
struct D
{
void call_foo (A &a)
{
a.foo ();
}
};
protected:
void foo () {}
};
class B : public A
{
struct C : public A::D
{
void bar (A &a, B &b)
{
b.foo (); // OK
a.foo (); // Error. Huh?
call_foo (a); // Ugly workaround
}
};
};
It seems that a method can safely use a protected method in a parent class if and only if the type of the base pointer is exactly the enclosing type (rather than some parent type).
This seems kind of odd. Why is the language that way?
The struct C is nested inside class B, it's regared as a member so it has the same access rights as any other member. So yes it could access the protected members of the base class A. But note that you could only access the protected members of A through an object of type B; you can't do that through a A. That makes sense, because the members of derived class should only be possible to access the protected members inherited from the base class; these members belong to the derived class. But accessing the protected members of the base class directly should not be allowed; they belong to the base class (or the other derived class).
The rule is not special for the inner class, it's also true for the member functions of B.
§11.4/1 Protected member access [class.protected]
(emphasis mine)
An additional access check beyond those described earlier in Clause
[class.access] is applied when a non-static data member or non-static
member function is a protected member of its naming class
([class.access.base])115 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
([expr.unary.op]), the nested-name-specifier shall denote C or a class
derived from C. All other accesses involve a (possibly implicit)
object expression ([expr.ref]). In this case, the class of the object
expression shall be C or a class derived from C. [ Example:
class B {
protected:
int i;
static int j;
};
class D1 : public B {
};
class D2 : public B {
friend void fr(B*,D1*,D2*);
void mem(B*,D1*);
};
...
void D2::mem(B* pb, D1* p1) {
pb->i = 1; // ill-formed
p1->i = 2; // ill-formed
i = 3; // OK (access through this)
B::i = 4; // OK (access through this, qualification ignored)
int B::* pmi_B = &B::i; // ill-formed
int B::* pmi_B2 = &D2::i; // OK
j = 5; // OK (because j refers to static member)
B::j = 6; // OK (because B::j refers to static member)
}
...
— end example ]
Related
Why the derived class Derived_from_Private is illegal?
i noticed the member function has an reference to Base, but why it cannot have an reference to Base class?
class Base {
public:
void pub_mem(); // public member
protected:
int prot_mem; // protected member
private:
char priv_mem; // private member
};
struct Pub_Derv : public Base {
// legal
void memfcn(Base &b) { b = *this; }
};
struct Priv_Derv : private Base {
// legal
void memfcn(Base &b) { b = *this; }
};
struct Prot_Derv : protected Base {
// legal
void memfcn(Base &b) { b = *this; }
};
struct Derived_from_Public : public Pub_Derv {
// legal
void memfcn(Base &b) { b = *this; }
};
struct Derived_from_Private : public Priv_Derv {
// illegal
void memfcn(Base &b) { b = *this; }
};
struct Derived_from_Protected : public Prot_Derv {
// legal
void memfcn(Base &b) { b = *this; }
};
The expression
b = *this;
needs to invoke an implicit conversion from *this to an lvalue of type Base in order to call the implicitly declared Base::operator=(const Base&). This conversion goes through the path Derived_from_Private -> Priv_Derv -> Base. Since Priv_Derv has Base as a private base, Derived_from_Private does not have access to the second link.
Priv_Derv inherits privately Base. This means that only the class itself knows that it's also a Base and only the member functions of Priv_Derv can use members of Base.
You can later let Derived_from_Private inherit publicly from Priv_Derv. It's legal. But unfortunately, due to the former private inheritance, it's as if Derived_from_Private doesn't have Base as base class.
Therefore your member function will fail to compile:
void memfcn(Base &b) { b = *this; }
*this is a Derived_from_Private, but it's illegal to convert it to a Base class, because there is no known relation with that class due to the private inheritance.
Inheritance can provide both subtyping and structural extension.
When you inherits privately from a base class you have no subtyping, only structural extension. Then (in your problematic case) when you write b = *this alas *this is not of the type Base because you have used private inheritance of it.
Private inheritance is usually used (that doesn't mean it's a good practice) to easily construct very simple composition (has a base, but not is a base).
A name of a class is inserted into the scope of itself as a public member. This is so-called injected-class-name. Name lookup for Base in the derived class Derived_from_Private will find its injected-class-name instead of the normal one. Because the injected-class-name of Base is treated as a public member of Base, thus is treated as a private number of Priv_Derv, it is inaccessible in Derived_from_Private.
Quoted from [class.access.spec] paragraph 5:
[ Note: In a derived class, the lookup of a base class name will find the injected-class-name instead of the name of the base class in the scope in which it was declared. The injected-class-name might be less accessible than the name of the base class in the scope in which it was declared. — end note ] [ Example:
class A { };
class B : private A { };
class C : public B {
A* p; // error: injected-class-name A is inaccessible
::A* q; // OK
};
— end example ]
In this answer to the question "Why can't my object access protected members of another object defined in common base class?", one can read:
You can only access protected members from your own base class instance.
Either I don't get it correctly or the following MCVE (live on coliru) proves it wrong:
struct Base { void f(); protected: int prot; };
struct Derived : Base { void g(); private: int priv; };
void Base::f()
{
Base b;
b.prot = prot;
(void) b;
}
void Derived::g()
{
{
Derived d;
(void) d.priv;
}
{
Derived& d = *this;
(void) d.priv;
}
{
Derived d;
(void) d.prot; // <-- access to other instance's protected member
}
{
Derived& d = *this;
(void) d.prot;
}
// ---
{
Base b;
(void) b.prot; // error: 'int Base::prot' is protected within this context
}
{
Base& b = *this;
(void) b.prot; // error: 'int Base::prot' is protected within this context
}
}
In the light of the two errors I get to wonder: why can I access to another Derived instance's protected member from the scope of Derived but cannot access to another Base instance's protected member from the same scope regardless of the fact that Derived devires from Base? Tl; dr: what makes protected more "private" than private in this case?
Notes:
please don't close this question as a duplicate of the linked question;
better title suggestion are welcome.
The rule in [class.access.base] is:
A member m is accessible at the point R when named in class N if [...]
m as a member of N is protected, and R occurs in a member or friend of class N, or in a member of a class P derived from N, where m as a member of P is public, private, or protected
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 the d.prot example - we are in a member of Derived while accessing a protected member of Derived.
R is in a member of a derived class and the member being accessed is a member of the derived class instance. This handles the b.prot example - we are in a member of a derived class, but prot 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.
class safe_bool_base {
protected:
void this_type_does_not_support_comparisons() const {}
};
template <typename T=void> class safe_bool : public safe_bool_base {
public:
void func() {
&safe_bool::this_type_does_not_support_comparisons;
&safe_bool_base::this_type_does_not_support_comparisons;
}
};
template<> class safe_bool<void> : public safe_bool_base {
public:
void func() {
&safe_bool::this_type_does_not_support_comparisons;
&safe_bool_base::this_type_does_not_support_comparisons;
}
};
Error Message:
zzz.cpp: In member function 'void safe_bool<void>::func()':
zzz.cpp:7:10: error: 'void safe_bool_base::this_type_does_not_support_comparison
s() const' is protected
void this_type_does_not_support_comparisons() const {}
^
zzz.cpp:22:24: error: within this context
&safe_bool_base::this_type_does_not_support_comparisons;
^
I wonder why protected member can not be visited in the template specialization. The codes are meaningless and just for testing.
When public inherite from the base class, its protected members become the derived class' protect members, which could be accessed in derived class' member functions. Note they're only accessed through the derived class itself (and its derived classes). But the protected members can't be accessed through the base class. That why &safe_bool::this_type_does_not_support_comparisons; works but &safe_bool_base::this_type_does_not_support_comparisons; doesn't.
From the standard, 11.4/1 Protected member access
[class.protected]:
(emphasie mine)
An additional access check beyond those described earlier in Clause
[class.access] is applied when a non-static data member or non-static
member function is a protected member of its naming class
([class.access.base])114 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
([expr.unary.op]), the nested-name-specifier shall denote C or a class
derived from C. All other accesses involve a (possibly implicit)
object expression ([expr.ref]). In this case, the class of the object
expression shall be C or a class derived from C. [ Example:
class B {
protected:
int i;
static int j;
};
class D1 : public B {
};
class D2 : public B {
friend void fr(B*,D1*,D2*);
void mem(B*,D1*);
};
...
void D2::mem(B* pb, D1* p1) {
pb->i = 1; // ill-formed
p1->i = 2; // ill-formed
i = 3; // OK (access through this)
B::i = 4; // OK (access through this, qualification ignored)
int B::* pmi_B = &B::i; // ill-formed
int B::* pmi_B2 = &D2::i; // OK
j = 5; // OK (because j refers to static member)
B::j = 6; // OK (because B::j refers to static member)
}
...
— end example ]
Note the statement int B::* pmi_B = &B::i; // ill-formed in the sample code from the standard, basically it's the same case of your code. BTW it has nothing to do with template specialization.
It seems that a protected member from a template policy class is inaccessible, even with a class hierarchy which seems correct.
For instance, with the following code snippet :
#include <iostream>
using namespace std;
template <class T>
class A {
protected:
T value;
T getValue() { return value; }
public:
A(T value) { this->value = value; }
};
template <class T, template <class U> class A>
class B : protected A<T> {
public:
B() : A<T>(0) { /* Fake value */ }
void print(A<T>& input) {
cout << input.getValue() << endl;
}
};
int main(int argc, char *argv[]) {
B<int, A> b;
A<int> a(42);
b.print(a);
}
The compiler (clang on OS X, but gcc returns the same type of error) returns the following error :
Untitled.cpp:18:21: error: 'getValue' is a protected member of 'A<int>'
cout << input.getValue() << endl;
^
Untitled.cpp:25:5: note: in instantiation of member function 'B<int, A>::print' requested here
b.print(a);
^
Untitled.cpp:8:7: note: can only access this member on an object of type 'B<int, A>'
T getValue() { return value; }
^
1 error generated.
The strange thing is that the last note from the compiler is totally correct but already applied since the b object is of type 'B<int, A>'. Is that a compiler bug or is there a problem in the code ?
Thanks
You have misunderstood the meaning of protected access.
Protected members are callable by derived classes. But only on the base object contained inside the class itself.
For example, if i simplify the problem, using :
class A {
protected:
void getValue(){}
};
class B : protected A
{
public:
void print(A& input)
{
input.getValue(); //Invallid
}
};
getValue cannot be called on a "A" object other than the "A" object inside the class itself.
This for example is valid.
void print()
{
getValue(); //Valid, calling the base class getValue()
}
As pointed out by Dan Nissenbaum and shakurov. This is however also valid:
void print(B& input)
{
input.getValue();
}
This is because we explicitly say that input is a object of B. And the compiler know that all that objects of B has protected access to getValue. In the case when we pass a A&, the object might as-well be a type of C, wich could be derrived from A with private access.
Let's forget for a minute about the template and look at this:
class A {
protected:
int value;
int getValue() { return value; }
public:
A(int value) { this->value = value; }
};
class B : protected A {
public:
B() : A(0) { /* Fake value */ }
void print(A& input) {
cout << input.getValue() << endl;
}
};
The print() method's implementation is wrong because you can't access non-public member of A inside B. And here's why: from within B, you can only access non-public members of B. Those members may be either inherited or not — it doesn't matter.
On the other hand, A& input may not be a reference to an instance of B. It may be a reference to another subclass (which may well have getValue() inaccessible).
Member functions of a derived class have access to protected base class members within any object of its type that is passed as an argument so long as the explicitly declared class of the object passed as an argument is that of the the derived class (or a further derived class).
Objects explicitly passed as the base class type cannot have their protected members accessed within the derived class's member functions.
In other words, if we have:
class A
{
protected:
int x;
}
class B : public A
{
void foo(B b)
{
b.x; // allowed because 'b' is explicitly declared as an object of class B
}
void goo(A a)
{
a.x; // error because 'a' is explicitly declared as having *base* class type
}
};
...then the line a.x is not allowed because the explicit type of the argument is A, but the rule for protected access only applies to objects explicitly defined as the same class as the class attempting to access the member. (...Or a class derived from it; i.e., if class Cderives from B, then passing an object explicitly declared as an object of class C will also have x accessible within B member functions.)
The reason for this is given by shakurov when he writes (paraphrasing)
A& input might not be a reference to an instance of B. It may be a
reference to another subclass (which may well have getValue()
inaccessible)
An excellent explication of this answer is also given here: accessing a protected member of a base class in another subclass.
As a matter of interest, I believe that this comes from the C++ standard here:
11.4 Protected member access [class.protected] 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)115 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.
Don't get distracted by the template. It has nothing to do with the error. The line in main that the compiler is complaining about creates an object of type B<int, a> and tries to access a protected member. That's not legal, regardless of the type. You can only use protected members from inside a member function or friend function. For example:
struct S {
protected:
void f();
};
int main() {
S s;
s.f(); // error: attempts to call a protected member function
}
I am confused about the meaning of access modifiers with respect to inheritance. What is the difference between inheritance involving the private, protected and public keywords?
what are Access Specifiers?
There are 3 access specifiers for a class/struct/Union in C++. These access specifiers define how the members of the class can be accessed. Of course, any member of a class is accessible within that class(Inside any member function of that same class). Moving ahead to type of access specifiers, they are:
Public - The members declared as Public are accessible from outside the Class through an object of the class.
Protected - The members declared as Protected are accessible from outside the class BUT only in a class derived from it.
Private - These members are only accessible from within the class. No outside Access is allowed.
An Source Code Example:
class MyClass
{
public:
int a;
protected:
int b;
private:
int c;
};
int main()
{
MyClass obj;
obj.a = 10; //Allowed
obj.b = 20; //Not Allowed, gives compiler error
obj.c = 30; //Not Allowed, gives compiler error
}
Inheritance and Access Specifiers
Inheritance in C++ can be one of the following types:
Private Inheritance
Public Inheritance
Protected inheritance
Here are the member access rules with respect to each of these:
First and most important rule Private members of a class are never accessible from anywhere except the members of the same class.
Public Inheritance:
All Public members of the Base Class become Public Members of the derived class &
All Protected members of the Base Class become Protected Members of the Derived Class.
i.e. No change in the Access of the members. The access rules we discussed before are further then applied to these members.
Code Example:
Class Base
{
public:
int a;
protected:
int b;
private:
int c;
};
class Derived:public Base
{
void doSomething()
{
a = 10; //Allowed
b = 20; //Allowed
c = 30; //Not Allowed, Compiler Error
}
};
int main()
{
Derived obj;
obj.a = 10; //Allowed
obj.b = 20; //Not Allowed, Compiler Error
obj.c = 30; //Not Allowed, Compiler Error
}
Private Inheritance:
All Public members of the Base Class become Private Members of the Derived class &
All Protected members of the Base Class become Private Members of the Derived Class.
An code Example:
Class Base
{
public:
int a;
protected:
int b;
private:
int c;
};
class Derived:private Base //Not mentioning private is OK because for classes it defaults to private
{
void doSomething()
{
a = 10; //Allowed
b = 20; //Allowed
c = 30; //Not Allowed, Compiler Error
}
};
class Derived2:public Derived
{
void doSomethingMore()
{
a = 10; //Not Allowed, Compiler Error, a is private member of Derived now
b = 20; //Not Allowed, Compiler Error, b is private member of Derived now
c = 30; //Not Allowed, Compiler Error
}
};
int main()
{
Derived obj;
obj.a = 10; //Not Allowed, Compiler Error
obj.b = 20; //Not Allowed, Compiler Error
obj.c = 30; //Not Allowed, Compiler Error
}
Protected Inheritance:
All Public members of the Base Class become Protected Members of the derived class &
All Protected members of the Base Class become Protected Members of the Derived Class.
A Code Example:
Class Base
{
public:
int a;
protected:
int b;
private:
int c;
};
class Derived:protected Base
{
void doSomething()
{
a = 10; //Allowed
b = 20; //Allowed
c = 30; //Not Allowed, Compiler Error
}
};
class Derived2:public Derived
{
void doSomethingMore()
{
a = 10; //Allowed, a is protected member inside Derived & Derived2 is public derivation from Derived, a is now protected member of Derived2
b = 20; //Allowed, b is protected member inside Derived & Derived2 is public derivation from Derived, b is now protected member of Derived2
c = 30; //Not Allowed, Compiler Error
}
};
int main()
{
Derived obj;
obj.a = 10; //Not Allowed, Compiler Error
obj.b = 20; //Not Allowed, Compiler Error
obj.c = 30; //Not Allowed, Compiler Error
}
Remember the same access rules apply to the classes and members down the inheritance hierarchy.
Important points to note:
- Access Specification is per-Class not per-Object
Note that the access specification C++ work on per-Class basis and not per-object basis.
A good example of this is that in a copy constructor or Copy Assignment operator function, all the members of the object being passed can be accessed.
- A Derived class can only access members of its own Base class
Consider the following code example:
class Myclass
{
protected:
int x;
};
class derived : public Myclass
{
public:
void f( Myclass& obj )
{
obj.x = 5;
}
};
int main()
{
return 0;
}
It gives an compilation error:
prog.cpp:4: error: ‘int Myclass::x’ is protected
Because the derived class can only access members of its own Base Class. Note that the object obj being passed here is no way related to the derived class function in which it is being accessed, it is an altogether different object and hence derived member function cannot access its members.
What is a friend? How does friend affect access specification rules?
You can declare a function or class as friend of another class. When you do so the access specification rules do not apply to the friended class/function. The class or function can access all the members of that particular class.
So do friends break Encapsulation?
No they don't, On the contrary they enhance Encapsulation!
friendship is used to indicate a intentional strong coupling between two entities.
If there exists a special relationship between two entities such that one needs access to others private or protected members but You do not want everyone to have access by using the public access specifier then you should use friendship.
The explanation from Scott Meyers in Effective C++ might help understand when to use them:
Public inheritance should model "is-a relationship," whereas private inheritance should be used for "is-implemented-in-terms-of" - so you don't have to adhere to the interface of the superclass, you're just reusing the implementation.