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 ]
Related
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 ]
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
}
To begin with, I know about C++ Standard (ISO/IEC 14882:2003): Section 11.5, Paragraph 1, and this is not that case (but compliler apparently does not think so).
I try to call protected base class method in derived class method through this pointer, static-casted to base class pointer and have in MSVC2008 error C2248: 'A::f' : cannot access protected member declared in class 'A'.
I have to do this in context of 'curiously recurring template pattern', but I can reproduce this error in simplier code, as follows:
class B
{
protected:
void f(){}
};
class D : public B
{
public:
void g()
{
f(); // ok
this->f(); // ok
static_cast<B*>(this)->f(); // C2248 in MSVC2008
dynamic_cast<B*>(this)->f(); // C2248
((B*)this)->f(); // C2248
}
};
D d; d.g();
It seems that compiler think of casted this pointer as a pointer to other instance, yeah?
The compiler is wrong in this case, what do you think?
Ok, my real code is more like that:
template<class T>
class B
{
public:
void g()
{
f(); // error C3861: 'f': identifier not found
this->f(); // error C3861: 'f': identifier not found
// static_cast to derived class
static_cast<T*>(this)->f(); // C2248 in MSVC2008
}
};
class D : public B<D>
{
protected:
void f(){}
};
I cast this to derived class, and I can't use this->f();
By the way, I see that this code is unsafe for usage like class E : public B<D> {...};: compilable, but static_cast makes wrong cast.
The compiler is correct. To explicitly access the B::f member function, you can write:
this->B::f();
The relevant language is:
c++11
11.4 Protected member access [class.protected]
[...] Access to a protected member is granted because the reference occurs in a friend or member of some
class C. [...] Access to a protected member [...] involve[s] 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.
Thus protected member access via a cast to the base class B violates this grant, and is disallowed. It is also unnecessary for the reason that you can use this->B::f() as above.
In the case with your actual CRTP motivation, you are correct that you cannot call f() without a static_cast, since D is not a base class of B<D> (the inheritance relationship is in the other direction). Since D is not a base class of B<D>, you cannot call its protected methods from B<D> anyway. One simple workaround is to friend B<D> to D and use the static_cast on the this pointer:
template<typename T>
class B {
public:
void g() {
static_cast<T *>(this)->f();
}
};
class D : public B<D>
{
friend class B<D>;
...
If giving B access to the private parts of D worries you, you can move the private parts to another base class and isolate the CRTP mechanism in D:
template<class T> class B {
public:
void g() {
static_cast<T*>(this)->f();
}
};
class C {
private:
void h();
protected:
void f(){ std::cout << "D::f\n"; }
};
class D: protected C, public B<D>
{
friend class B<D>;
};
Here B<D> is prevented from calling C::h as friendship is neither inherited nor transitive.
I think the compiler is right.
Suppose the following:
void g()
{
B *b1 = this;
B *b2 = GetUnrelatedB();
b1->f(); //Error?
b2->f(); //Error!
}
The b1 case is equivalent to your static_cast but it would be very strange that b1 will be allowed and b2 will not.
Citing your paragraph 11.5:
[...] the access must be through a pointer to, reference to, or object of the derived class itself.
But static_cast<B*>(this) is of type B*, not D*, no matter that the object itself is the same. Actually, the value of the pointer is irrelevant to this issue, only the type of the expression:
void g()
{
B *b2 = GetUnrelatedB();
static_cast<D*>(b2)->f(); //ok!
}
But, how would the compiler know that you are inside a class derived from B once you apply static_cast on this? In my (humble) opinion, if I create a B object, I expect not to be allowed to call private or protected B methods on the B object, since we don't want to violate encapsulation. It would not matter where the B object is created, as long as it's outside of the B class methods.
why isnt a derived class not permissioned to access its protected base class member when its templatized?
class MyBase {
protected:
int foo;
};
template<typename Impl>
class Derived : public Impl {
public:
int getfoo() {
return static_cast<Impl*>(this)->foo;
}
};
The compiler complains foo is protected. why?
error: int MyBase::foo is protected
You are accessing foo through an MyBase* instead of a Derived<MyBase>*. You may only access protected members through your own type, not through the base type.
Try this instead:
int getfoo() {
return this->foo;
}
From the C++ 2003 standard, 11.5/1 [class.protected]: "When a friend or a member function of a derived class references a protected nonstatic member function or
protected nonstatic data member of a base class … the access must be through a
pointer to, reference to, or object of the derived class itself (or any class derived from that class)"
I am confused: I thought protected data was read/writable by the children of a given class in C++.
The below snippet fails to compile in MS Compiler
class A
{
protected:
int data;
};
class B : public A
{
public:
B(A &a)
{
data = a.data;
}
};
int main()
{
A a;
B b = a;
return 0;
}
Error Message:
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
demoFail.cpp
demoFail.cpp(12) : error C2248: 'A::data' : cannot access protected member declared in class 'A'
demoFail.cpp(4) : see declaration of 'A::data'
demoFail.cpp(2) : see declaration of 'A'
What am I doing wrong?
According to TC++PL, pg 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.
Of course, here's an easy way to fix this for your case:
class A
{
protected:
int data;
};
class B : public A
{
public:
B(const A &a)
: A(a)
{
}
};
int main()
{
A a;
B b = a;
return 0;
}
The C++ Standard says about protected non-static members at 11.5/1
When a friend or a member function of a derived class references a protected nonstatic member function or protected nonstatic data member of a base class, an access check applies in addition to those described earlier in clause 11. Except when forming a pointer to member (5.3.1), the access must be through a pointer to, reference to, or object of the derived class itself (or any class derived from that class) (5.2.5). If the access is to form a pointer to member, the nested-name-specifier shall name the derived class (or any class derived from that class).
In addition to fixing things mentioned earlier by others (constructor of B is private), i think rlbond's way will do it fine. However, a direct consequence of the above paragraph of the Standard is that the following is possible using a member pointer, which arguably is a hole in the type system, of course
class B : public A {
public:
B(A &a){
int A::*dataptr = &B::data;
data = a.*dataptr;
}
};
Of course, this code is not recommended to do, but shows that you can access it, if you really need to (I've seen this way being used for printing out a std::stack, std::queue, std::priority_queue by accessing its protected container member c)
You just shouldn't copy an A object in a B constructor. The intention is to leave the initialization of A's members to it's own constructor:
struct A {
A( const A& a ): data( a.data ) {}
protected: int data;
};
struct B : public A {
B( const A& a ): A( a ) {}
};
The constructor of B is private. If you do not specify anything, in a class, the default modifier is private (for structs it is public). So in this example the problem is that you cannot construct B. When you add public to constructor B anoter problem arises:
B has the right to modify the part of A it derives from but not another A like in this case.
You could do following:
class A
{
public:
A()
: data(0)
{
}
A(A &a)
{
data = a.data;
}
protected:
int data;
};
class B : public A
{
public:
B(A &a)
: A(a)
{
}
};
int main()
{
A a;
B b = a;
return 0;
}