Policy inheritance and inaccessible protected members - c++

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
}

Related

why this definition of a derived class is illegal?

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 ]

Call private method from the world in c++

I realy don't understand why it works, but below code shows an example of calling private method from the world without any friend classes:
class A
{
public:
virtual void someMethod(){
std::cout << "A::someMethod";
}
};
class B : public A
{
private:
virtual void someMethod(){
std::cout << "B::someMethod";
}
};
int main(){
A* a = new B;
a->someMethod();
}
outputs:
B::someMethod
Doesn't it violates encapsulation rules in C++? For me this is insane. The inheritance is public, but the access modifier in derived class is changed to private, thus the someMethod() in class B is private. So in fact, doing a->someMethod(), we are directly calling a private method from the world.
Consider the following code, a modification of the code in the original question:
class A
{
public:
virtual void X(){
std::cout << "A::someMethod";
}
};
class B : public A
{
private:
virtual void Y(){
std::cout << "B::someMethod";
}
};
int main(){
A* a = new B;
a->X();
}
It's easy to understand that it's legit to call X(). B inherits it from A as a public member. Theoretically if X() would call Y() this would be legit as well of course, although this is not possible because X() is declared in A which doesn't know Y(). But actually this is the case if X = Y, i.e. if both methods have the same name.
You may think of it as "B inherits a public method from A, that calls a private method (of B) with the same name".
a is a pointer to an A object where the method is public, so this is not a violation. Since, you have used virtual, the VTABLE is taken into account and you get the output as B::someMethod.
For me this is quite simple.
As you are allowed to asign any dynamic type inheritance of a class to an object of the parrent-class it would be vise versa.But as you are assigning the Child to its parrent object pointer this could be bad as if the class of B where bigger as A.
If a program attempts to access the stored value of an object through an lvalue of other than one of the following types the behavior is undefined:
the dynamic type of the object,
a cv-qualified version of the dynamic type of the object,
a type that is the signed or unsigned type corresponding to the dynamic type of the object,
a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type of the object,
an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union),
a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,
a char or unsigned char type.
So as in your code you aren't fitting this conditions, but as B has the sime size as A, it would be possible to run it. But it is undefined behavior.
And as you creat a new B the memory block a is pointing to has the method of printing B and not A.
The access control specifiers (public, protected and private) do not apply to member functions or data members. They apply to member function and data member names. And that works. If you can refer to the member without the name, you can access it.
That's precisely what's happening here. You're calling B::someMethod, but you're calling it using the name A::someMethod, which is public. No problem.
You're suggesting a private member function shouldn't be callable from outside of the class (disregarding friends for the moment). How would your desired semantics work in the following case?
Shared library hider:
hider.h:
typedef void (*FuncType)();
class Hider {
private:
static void privFunc();
public:
static void pubFunc();
FuncType getFunction() const;
};
hider.cpp
#include <cstdlib>
#include <iostream>
#include "hider.h"
void Hider::privFunc() {
std::cout << "Private\n";
}
void Hider::pubFunc() {
std::cout << "Public\n";
}
FuncType Hider::getFunction() const {
if (std::rand() % 2) {
return &pubFunc;
} else {
return &privFunc;
}
}
Application using library hider
#include "hider.hpp"
int main()
{
Hider h;
FuncType f = h.getFunc();
f();
}
What about the call to f()? Should it fail at runtime 50% of the time with some form of access control violation?
As suggested by DyP in the comments, a more realistic scenario is the well-known "template method" design pattern:
class Container
{
public:
void insert(const Item &item) {
preInsert();
data.insert(item);
postInsert();
}
private:
std::vector<Item> data;
virtual void preInsert() = 0;
virtual void postInsert() = 0;
};
class ThreadSafeContainer : public Container
{
private:
std::mutex m;
virtual void preInsert() {
m.lock();
}
virtual void postInsert() {
m.unlock();
}
};
Your semantics would mean this code wouldn't compile.

Calling protected base class method via this pointer casted to base class in derived class (C++)

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.

How to access protected base class function, from derived class through base class ptr

I have abstract class A, from which I inherit a number of classes. In the derived classes I am trying to access protected function in A trough A pointer. But I get a compiler error.
class A
{
protected:
virtual void f()=0;
};
class D : public A
{
public:
D(A* aa) :mAPtr(aa){}
void g();
protected:
virtual void f();
private:
A* mAPtr; // ptr shows to some derived class instance
};
void D::f(){ }
void D::g()
{
mAPtr->f();
}
The compiler error says : cannot access protected member A::f declared in class A.
If I declare mAPtr to be D*, instead A* everything compiles. And I don't understand why is this.
Relying on private access works on unrelated instances of the same type.
Relying on protected access works on unrelated instances of the same type (and of more derived types).
However, relying on protected access does not work on unrelated instances of a base type.
[n3290: 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).
So D or something derived from D, but not A.
It's an oft-questioned cute oddity about C++ that nonetheless is designed to try to avoid pitfalls. After all, you don't know what type *mAPtr really has.
A class containing a protected section means that this class allows derived classes to manipulate their base class in any way they choose (as far as the protected interface allows).
Class D objects can manipulate their own A part. In doing say they probably want to maintain some invariants.
Suppose there is (or will be in the future!) another class E, also inherited from A. Class E objects also can manipulate their own A part, and they may be enforcing different invariants.
Now, if a class D object was allowed to manipulate the A part of any object, it can't ensure the invariants. A D object may do something to the A part of an E object that breaks that E object. That's why it is not allowed.
But if you really want to, perhaps a way to call A::f, without exposing it to everybody, would be via a friend function.
class A;
namespace detail
{
void call_f(A*);
}
class A
{
friend void detail::call_f(A*);
private:
virtual void f() = 0;
};
namespace detail
{
void call_f(A* a) { a->f(); }
}
class D: public A
{
public:
void g() { detail::call_f(mAPtr); }
private:
void f() {}
A* mAPtr;
};
This relies on users being disciplined enough to stay out of namespaces whose name clearly indicates that it contains implementation details.
You forgot using ; after class declaration:
class A
{
protected:
virtual void f()=0;
};
class D : public A
{
public:
void g();
protected:
void f();
private:
A* mAPtr; // ptr shows to some derived class instance
};
Besides, you don't need to store base class pointer.

Weird compiler error and template inheritance

Could someone explain me why this code:
class safe_bool_base
{ //13
protected:
typedef void (safe_bool_base::*bool_type)() const;
void this_type_does_not_support_comparisons() const {} //18
safe_bool_base() {}
safe_bool_base(const safe_bool_base&) {}
safe_bool_base& operator=(const safe_bool_base&) { return *this; }
~safe_bool_base() {}
};
template <typename T=void> class safe_bool : public safe_bool_base
{
public:
operator bool_type() const
{
return (static_cast<const T*>(this))->boolean_test() ? &safe_bool_base::this_type_does_not_support_comparisons : 0;
}
protected:
~safe_bool() {}
};
template <> class safe_bool<void> : public safe_bool_base
{
public:
operator bool_type() const
{
return (boolean_test() == true) ? &safe_bool_base::this_type_does_not_support_comparisons : 0; //46
}
protected:
virtual bool boolean_test() const = 0;
virtual ~safe_bool() {}
};
Produces the following compiler error ?
c:\project\include\safe_bool.hpp(46) : error C2248: 'safe_bool_base::this_type_does_not_support_comparisons' : cannot access protected member declared in class 'safe_bool_base'
c:\project\include\safe_bool.hpp(18) : see declaration of 'safe_bool_base::this_type_does_not_support_comparisons'
c:\project\include\safe_bool.hpp(13) : see declaration of 'safe_bool_base'
Since both safe_bool templates derive from safe_bool_base, I don't understand why one can't access a protected member of the base class.
Am I missing something ?
This should probably help (reproducible in a non template situation also)
struct A{
protected:
void f(){}
};
struct B : A{
void g(){&A::f;} // error, due to Standard rule quoted below
};
int main(){
}
VS gives "'A::f' : cannot access
protected member declared in class
'A'"
For the same code, Comeau gives
"ComeauTest.c", line 7: error:
protected function "A::f" (declared at
line 3) is
not accessible through a "A" pointer or object void g(){&A::f;}
^
"ComeauTest.c", line 7: warning:
expression has no effect void
g(){&A::f;}
Here is the fixed code which achieves the desired intentions
struct A{
protected:
void f(){}
};
struct B : A{
void g(){&B::f;} // works now
};
int main(){
}
So, why does the first code snippet not work?
This is because of the following rule in the C++ Standard03
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.102) 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).
So change the return within operator functions as follows
return (boolean_test() == true) ? &safe_bool<void>::this_type_does_not_support_comparisons : 0; //46
return (static_cast<const T*>(this))->boolean_test() ? &typename safe_bool<T>::this_type_does_not_support_comparisons : 0;
EDIT 2: Please ignore my explanations. David is right. Here is what it boils down to.
struct A{
protected:
int x;
};
struct B : A{
void f();
};
struct C : B{};
struct D: A{ // not from 'C'
};
void B::f(){
x = 2; // it's own 'A' subobjects 'x'. Well-formed
B b;
b.x = 2; // access through B, well-formed
C c;
c.x = 2; // access in 'B' using 'C' which is derived from 'B', well-formed.
D d;
d.x = 2; // ill-formed. 'B' and 'D' unrelated even though 'A' is a common base
}
int main(){}
I don't think this is anything to do with templates. Your example code can be reduced to this, and it still gives the equivalent error:
class A
{
protected:
typedef void (A::*type)() const;
void foo() const {}
};
class B : public A
{
public:
operator type() const
{
return &A::foo;
}
};
I believe the issue is you can't return member-function pointers to protected members in the public interface. (Edit: not true...)
Chubsdad's answer clarifies your question of why there's an error for the template specialization.
Now the following C++ standard rule
14.7.2/11 The usual access checking rules do not apply to names used to specify explicit
instantiations. [Note: In particular, the template arguments and names used in the function
declarator (including parameter types, return types and exception specifications) may be
private types or objects which would normally not be accessible and the template may be a
member template or member function which would not normally be accessible. — endnote]
would explain why the generic template instantiation wouldn't throw an error. It will not throw even if you have private access specifier.