error: 'void Base::output()' is protected within this context - c++

I'm confused about the errors generated by the following code.
In Derived::doStuff, I can access Base::output directly by calling it.
Why can't I create a pointer to output() in the same context that I can call output()?
(I thought protected / private governed whether you could use a name in a specific context, but apparently that is incomplete?)
Is my fix of writing callback(this, &Derived::output); instead of callback(this, Base::output) the correct solution?
#include <iostream>
using std::cout; using std::endl;
template <typename T, typename U>
void callback(T obj, U func)
{
((obj)->*(func))();
}
class Base
{
protected:
void output() { cout << "Base::output" << endl; }
};
class Derived : public Base
{
public:
void doStuff()
{
// call it directly:
output();
Base::output();
// create a pointer to it:
// void (Base::*basePointer)() = &Base::output;
// error: 'void Base::output()' is protected within this context
void (Derived::*derivedPointer)() = &Derived::output;
// call a function passing the pointer:
// callback(this, &Base::output);
// error: 'void Base::output()' is protected within this context
callback(this, &Derived::output);
}
};
int main()
{
Derived d;
d.doStuff();
}
Edit: I'd love to know where this is in the stardard, but mostly I'm just trying to wrap my head around the concept. I think my problem is that callback doesn't have access to protected members of Derived, but it is able to call Derived::output if you pass it a pointer. How is a protected member of Derived that comes from Derived different from a protected member of Derived that comes from Base?

In short, it's "because the standard says so." Why? I don't know, I've emailed a couple of the standards guys, but haven't received a response, yet.
Specifically, 11.5.1 (from C++0x FCD):
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)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 (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.
Edit:
Also, you'll see that you change the code to the following, according to what the standard specifies, it will compile (and run) cleanly:
void (Base::*derivedPointer)() = &Derived::output;

Edit: I'm not sure if this is a "Where is this in the standard?" question or a "Why is it designed that way?" question, this answers the latter (I don't have a copy of the standard itself to play with)
I believe this is because a function with protected or friend access to base would be able to circumvent access protection by passing the function pointer to methods which should not have access to base's private members.
In this example, callback does not have access to base, and therefore should not be able to call one of it's private functions.

Related

If a private virtual function is overridden as a public function in the derived class, what are the problems?

using namespace std;
#include <cstdio>
#include <iostream>
class One{
private:
virtual void func(){
cout<<"bark!"<<endl;
}
};
class Two: public One{
public:
void func(){
cout<<"two!"<<endl;
}
};
int main(){
One *o = new Two();
o->func();
}
Why is there an error on o->func()?
I don't know the mechanism behind it... In my opinion, o->func() should call the func() in the derived class, which is public, so there wouldn't be problems, but it says:
error: ‘virtual void One::func()’ is private
Accessibility check is performed based on the static type of the object. The type of o is One*. This means that if One::func() is private, then o->func() won't compile.
On the other hand, which virtual member function will be called (i.e. dynamic dispatch) happens at run-time, based on the dynamic type of the object. So if One::func() is public, o->func() will call Two::func(), because o is pointing to an object of type Two.
For your sample code and use case, making One::func() private is just meaningless. But note that there's a famous idiom called Non-Virtual Interface, which makes use of private virtual member functions of base class.
Other suggestions:
Don't forget to delete o;
Add a virtual destructor in the base class One. Otherwise delete o; will lead to undefined behavior; e.g. the destructor of Two might not be invoked.
class One {
public:
virtual ~One() {}
// ...
};
A subclass can't ease inheritance restriction,
even though func is virtual, it is still the inheritance restrictions remain.
please see this answer for compliated view of inheritance restrictions :
Difference between private, public, and protected inheritance
Please check Access specifiers and virtual functions.
From standard :
§11.5 [class.access.virt] The access rules (Clause 11) for a virtual
function are determined by its declaration and are not affected by the
rules for a function that later overrides it.
Access is checked at the call point using the type of the expression
used to denote the object for which the member function is called. The
access of the member function in the class in which it was defined is
in general not known.
If name lookup determines a viable function to be a virtual function, the access specifier of the virtual function is checked in the scope of the static type of the object expression used to name the function. At run time, the actual function to be called could be defined in the derived class with a completely different access specifier. This is because 'access specifiers' are a compile time phenomenon.
Since access specifier of function func() is checked in the scope of One *o, and it is private in class One, it produces error.
If Onedeclares func() as public, and Two declares it private, there won't be any errors. See this Private function invoked and it works. Could any of you reason it please

C++ protected: fail to access base's protected member from within derived class

Admittedly, this question title sounds pretty much exactly the same as the question you neighbour Mike has repeatedly asked. I found quite a few questions worded the same way, but none was what my question is about.
First of all, I'd like to clarify a few points for the context of this question:
1, c++ access control works on a class basis rather than instance basis. Therefore, the following code is completely valid.
class Base
{
protected:
int b_;
public:
bool IsEqual(const Base& another) const
{
return another.b_ == b_; // access another instance's protected member
}
};
2, I completely understand why the following code is NOT valid - another can be a sibling instance.
class Derived : public Base
{
public:
// to correct the problem, change the Base& to Derived&
bool IsEqual_Another(const Base& another) const
{
return another.b_ == b_;
}
};
Now time to unload my real question:
Assume in the Derived class, I have an array of Base instances. So effectively, Derived IS A Base(IS-A relation), and Derived consists of Base(Composite relation). I read from somewhere that this(refers to the design of both IS-A and Has-A) is a design smell and I should never have a scenario like this in the first place. Well, the mathematical concept of Fractals, for example, can be modelled by both IS-A and Has-A relations. However, let's disregard the opinion on design for a moment and just focus on the technical problem.
class Derived : public Base
{
protected:
Base base_;
public:
bool IsEqual_Another(const Derived& another) const
{
return another.b_ == b_;
}
void TestFunc()
{
int b = base_.b_; // fail here
}
};
The error message has already stated the error very clearly, so there's no need to repeat that in your answer:
Main.cpp:140:7: error: ‘int Base::b_’ is protected
int b_;
^
Main.cpp:162:22: error: within this context
int b = base_.b_;
Really, according to the following 2 facts, the code above should work:
1, C++ access control works on class basis rather than instance basis(therefore, please don't say that I can only access Derived's b_; I can't access a stand alone Base instance's protected members - it's on class basis).
2, Error message says "within this context" - the context is Derived(I was trying to access a Base instance's protected member from within Derived. It's the very feature of a protected member - it should be able to be accessed from within Base or anything that derives from Base.
So why is the compiler giving me this error?
The access rules could in principle have provided an exemption for this special case, where it's known that Base is the most derived class, the dynamic type of the object. But that would have complicated things. C++ is sufficiently complicated.
A simple workaround is to provide a static protected accessor function up in Base.
A more hack'ish workaround is to use the infamous type system loophole for member pointers. But I'd go for the static function, if I had to stick with the basic design. Because I think like there's not much point in saving a few keystrokes when the resulting code is both hard to get right in the first place, and hard to understand for maintainers.
Concrete example:
class Base
{
protected:
int b_;
static
auto b_of( Base& o )
-> int&
{ return o.b; }
public:
auto IsEqual( const Base& another ) const
-> bool
{
return another.b_ == b_; // access another instance's protected member
}
};
2, Error message says "within this context" - the context is Derived(I was trying to access a Base instance's protected member from within Derived. It's the very feature of a protected member- it should be able to be accessed from within Base or anything that derives from Base.
Okay, had to go to the standard for this one.
So you're asking, "Why isn't it possible?" The answer: Because of how the standard really defines protected member access:
§ 11.4
Protected member access
[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...As described
earlier, access to a protected member is granted because the reference occurs in a friend or member of some class C.
(emphasis mine)
So let's go over your examples to see what's what.
class Base
{
protected:
int b_;
public:
bool IsEqual(const Base& another) const
{
return another.b_ == b_; // access another instance's protected member
}
};
No problem. another.b_ is Base::b_, and we're accessing it from a member function Base::IsEqual(const Base&) const.
class Derived : public Base
{
public:
// to correct the problem, change the Base& to Derived&
bool IsEqual_Another(const Base& another) const
{
return another.b_ == b_;
}
};
Here, we're accessing Base::b_ again, but our context is a member function Derived::IsEqual_Another(const Base&) const, which isn't a member of Base. So no go.
Now for the alleged culprit.
class Derived : public Base
{
protected:
Base bases_[5];
public:
bool IsEqual_Another(const Derived& another) const
{
return another.b_ == b_;
}
void TestFunc()
{
int b = bases_[0].b_; // fail here
}
};
bases_[0].b_ is accessing the protected Base::b_, inside the context of Derived::TestFunc(), which isn't a member (or friend...) of Base.
So looks like the compiler is acting in accordance with the rules.
I am just turning my comments into an answer because I find the issue interesting. In particular that in the following minimal example D doesn't compile baffled me:
class B { protected: int i; };
class D : public B { int f(B &b){ return b.i; } };
After all, a D is a B and should be able to do all that a B can do (except access B's private members), shouldn't it?
Apparently, the language designers of both C++ and C# found that too lenient. Eric Lippert commented one of his own blog posts saying
But that’s not the kind of protection we’ve chosen as interesting or valuable. "Sibling" classes do not get to be friendly with each other because otherwise protection is very little protection.
EDIT:
Because there seems to be some confusion about the actual rule laid forth in 11.4 I'll parse it and illustrate the basic idea with a short example.
The purpose of the section is laid out, and what it applies to (non-static members).
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)
The naming class in the example below is B.
Context is established by summarising the chapter so far (it defined access rules for protected members). Additionally a name for a "class C" is introduced: Our code is supposed to reside inside a member or friend function of C, i.e. has C's access rights.
As described earlier, access to a protected member is
granted because
the reference occurs in a friend or member of some
class C.
"Class C" is also class C in the example below.
Only now the actual check is defined. The first part deals with pointers to members, which we ignore here. The second part concerns your everyday accessing a member of an object, which logically "involve a (possibly implicit) object expression".
It's just the last sentence which describes the "additional check" this whole section was for:
In this case, the class of the object expression
[through which the member is accessed -pas]
shall be C or a class derived from C.
The "object expression" can be things like a variable,
a return value of a function, or a dereferenced pointer.
The "class of the object expression" is a compile time
property, not a run time property; access through one
and the same object may be denied or granted depending
on the type of the expression used to access the member.
This code snippet demonstrates that.
class B { protected: int b; };
class C: public B
{
void f()
{
// Ok. The expression of *this is C (C has an
// inherited member b which is accessible
// because it is not declared private in its
// naming class B).
this->b = 1;
B *pb = this;
// Not ok -- the compile time
// type of the expression *pb is B.
// It is not "C or a class derived from C"
// as mandated by 11.4 in the 2011 standard.
pb->b = 1;
}
};
I initially wondered about this rule and assume the following rationale:
The issue at hand is data ownership and authority.
Without code inside B explicitly providing access (by making C a friend or by something like Alf's static accessor) no other classes except those who "own" the data are allowed to access it. This prevents gaining illicit access to the protected members of a class by simply defining a sibling and modifying objects of the original derived class through the new and before unknown sibling. Stroustrup speaks of "subtle errors" in this context in the TCPPL.
While it would be safe to access (different) objects of the original base class from a derived class' code, the rule is simply concerned with expressions (a compile time property) and not objects (a run time property). While static code analysis may show that an expression of some type Base actually never refers to a sibling, this is not even attempted, similar to the rules concerning aliasing. (Maybe that is what Alf meant in his post.)
I imagine the underlying design principle is the following: Guaranteeing ownership and authority over data gives a class the guarantee that it can maintain invariants related to the data ("after changing protected a always also change b"). Providing the possibility to change a protected property from by a sibling may break the invariant -- a sibling does not know the details of its sibling's implementation choices (which may have been written in a galaxy far, far away). A simple example would be a Tetragon base class with protected width and height data members plus trivial public virtual accessors. Two siblings derive from it, Parallelogram and Square. Square's accessors are overridden to always also set the other dimension in order to preserve a square's invariant of equally long sides, or they only just use one of the two. Now if a Parallelogram could set a Square's width or height directly through a Tertragon reference they would break that invariant.
This has nothing to do with bases_ being protected in Derived, it is all about b_ being protected in Base.
As you have already stated, Derived can only access protected members of its base class, not of any other Baseobjects. Not even if they are members of Derived.
If you really need access, you can make Derived a friend on Base.
Ok, I've been bothered by this wicked thing for a night. Endless discussions and the ambiguity of clause 11.4(as quoted by Yam marcovic)
§ 11.4 Protected member access
[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...As described earlier, access to a protected member is granted because the reference occurs in a friend or member of some class C.
have burned me out. I decided to resort to the gcc source code(gcc 4.9.2 in my case) to check how those gcc guys understood the clause 11.4, and what check exactly the C++ standards wants to do and how those checks are supposed to be done.
In gcc/cp/search.c:
/* Returns nonzero if it is OK to access DECL through an object
indicated by BINFO in the context of DERIVED. */
static int protected_accessible_p (tree decl, tree derived, tree binfo)
{
access_kind access;
/* We're checking this clause from [class.access.base]
m as a member of N is protected, and the reference occurs in a
member or friend of class N, or in a member or friend of a
class P derived from N, where m as a member of P is public, private
or protected.
Here DERIVED is a possible P, DECL is m and BINFO_TYPE (binfo) is N. */
/* If DERIVED isn't derived from N, then it can't be a P. */
if (!DERIVED_FROM_P (BINFO_TYPE (binfo), derived))
return 0;
access = access_in_type (derived, decl);
/* If m is inaccessible in DERIVED, then it's not a P. */
if (access == ak_none)
return 0;
/* [class.protected]
When a friend or a member function of a derived class references
a protected nonstatic member of a base class, an access check
applies in addition to those described earlier in clause
_class.access_) Except when forming a pointer to member
(_expr.unary.op_), the access must be through a pointer to,
reference to, or object of the derived class itself (or any class
derived from that class) (_expr.ref_). 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). */
if (DECL_NONSTATIC_MEMBER_P (decl))
{
/* We can tell through what the reference is occurring by
chasing BINFO up to the root. */
tree t = binfo;
while (BINFO_INHERITANCE_CHAIN (t))
t = BINFO_INHERITANCE_CHAIN (t);
if (!DERIVED_FROM_P (derived, BINFO_TYPE (t)))
return 0;
}
return 1;
}
The most interesting part is this:
if (DECL_NONSTATIC_MEMBER_P (decl))
{
/* We can tell through what the reference is occurring by
chasing BINFO up to the root. */
tree t = binfo;
while (BINFO_INHERITANCE_CHAIN (t))
t = BINFO_INHERITANCE_CHAIN (t);
if (!DERIVED_FROM_P (derived, BINFO_TYPE (t)))
return 0;
}
1) derived in the code is the context, which in my case is the Derived class;
2) binfo in the code represents the instance whose non-static protected member is access, which in my case is base_, Derived's protected data member Base instance;
3) decl in the code represents base_.b_.
What gcc did when translating my code in question was:
1) check if base_.b_ is non-static protected member? yes of course, so enter the if;
2) climb up the inheritance tree of base_;
3) figure out what actual type base_ is; of course, it's Base
4) check if the result in 3) which is Base, derives from Derived. Of course that's a negative. Then return 0 - access denied.
Apparently, according to gcc's implementation, the "additional check" requested by the C++ standard is the type check of the instance through which the protected member gets accessed. Although the C++ standard did not explicitly mention what check should be done, I think gcc's check is the most sensible and plausible one - it's probably the kind of check the C++ standard wants. And then the question really boils down to the rationale for the standard to request an additional check like this. It effectively makes the standard contradict itself. Getting rid of that interesting section(It seems to me that the C++ standard is asking for inconsistency deliberately), the code should work perfectly. In particular, the sibling problem won't occur as it will be filtered by the statement:
if (!DERIVED_FROM_P(BINFO_TYPE(t), derived))
return 0;
Regarding the kind of protection(protected does not work purely on class, but on BOTH class AND instance) mentioned by Peter and the post(by Eric Lippert) he shared, I personally totally agree with that. Unfortunately, by looking at the C++ standard's wording, it doesn't; if we accept that the gcc implementation is an accurate interpretation of the standard, then what the C++ standard really asks for is, a protected member can be accessed by its naming class or anything that derives from the naming class; however, when the protected member is accessed via an object, make sure the owner object's type is the same as the calling context's type. Looks like the standard just wants to make an exception for the clarification point 1 in my original question.
Last but not least, I'd like to thank Yam marcovic for pointing out clause 11.4. You are the man, although your explanation wasn't quite right - the context does not have to be Base, it can be Base or anything derived from Base. The catch was in the type check of the instance through which the non-static protected member was accessed.
There are a couple of long answers, and quotes from the standard that are correct. I intend on providing a different way of looking at what protected really means that might help understanding.
When a type inherits from a different type, it gets a base sub-object. The protected keyword means that any derived type can access this particular member within the sub-object that it contains due to the inheritance relationship. The keyword grants access to specific object(s), not to any object of type base.

What's the reason for protected member accessibility additional check in C++?

I just run to this issue, and know from the C++ standard define it as following (emphasize mine)
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.
Code snippet:
class Base
{
protected:
int i;
};
class Derived : public Base
{
public:
// I cannot define it as void memfunc(Derived* obj) because of signature requirement.
void memfunc(Base* obj)
{
obj->i = 0; // ERROR, cannot access private member via Base*
Derived* dobj = (Derived*)(obj);
dobj->i = 0; // OK
}
};
So what's the reason for this check? Why C++ standard bother to limit access protected member via base class pointer?
Not Duplicate to: Accessing protected members in a derived class, I want to ask for the reason to prohibit it in standard.
Just because you derive from a Base doesn't mean you should be allowed to access protected member of any other class deriving from Base. Imagine a class Derived2 provided by a library which inherits from Base. This way you'll be able to get a base object of Derived2 and do whatever you want with it in the code of Derived.
So basically the standard ensures that you only modify protected members that you inherited and not mess with the integrity of unrelated siblings classes.

Function templates and Private Inheritance

I recently ran into a problem when using a private inheritance scheme in which the base class defined a template method and the (privately) derived class made that method public via a using declaration under the public access specifier. The template was designed to take the address of a function and invoke that function pointer. However, upon attempting to pass the name of the function to the derived class template method, I receive an error message that states that the base-class method cannot access a private member declared in the derived class. Here is a code segment that models the issue:
class A
{
public:
template<class T> void Funct(T pFunct) { }
};
class B : private A
{
public:
using A::Funct;
};
void Show(void) { }
int main(void)
{
B b;
b.Funct(Show);
}
The exact resulting error message is: 'A::Funct' : cannot access private member declared in class 'B'
I am able to resolve the issue simply by:
1)Preceding the function argument name with the address-of operator:
b.Funct(&Show);
2)Explicitly qualifying the template type argument:
b.Funct<void(*)(void)>(Show)
If the Show() function were a template as well, I would need to explicitly qualify the template using the proper template type arguments used to instantiate Show.
My question is not how to solve the problem but why the error message is being generated. Why does instantiating Funct() with Show versus with &Show cause the compiler to do two different things. And why does instantiating Funct() with Show cause the Funct() method to attempt to access the private data in class B (which I'm assuming is the A subobject in class B)?
Compiles fine with Comeau Online. Ergo, compiler bug. Report it.
Cheers & hth.,
bcc32 gives error: error bccE2247: 'Funct<void (*)()>(void (*)())' is not accessible in function main()
I believe this is a compiler bug.

Why can I access a derived private member function via a base class pointer to a derived object?

#include<iostream>
using namespace std;
class base
{
public:
virtual void add() {
cout << "hi";
}
};
class derived : public base
{
private:
void add() {
cout << "bye";
}
};
int main()
{
base *ptr;
ptr = new derived;
ptr->add();
return 0;
}
Output is bye
I dont have a problem with how this is implemented. I understand you use vtables and the vtable of derived contains the address of the new add() function. But add() is private shouldn't compiler generate an error when I try to access it outside the class? Somehow it doesn't seem right.
add() is only private in derived, but the static type you have is base* - thus the access restrictions of base apply.
In general you can't even know at compile time what the dynamic type of a pointer to base will be, it could e.g. change based on user input.
This is per C++03 §11.6:
The access rules (clause 11) for a virtual function are determined by its declaration and are not affected by the rules for a function that later overrides it.
[...] Access is checked at the call point using the type of the expression used to denote the object for which the member function is called [...]. The access of the member function in the class in which it was defined [...] is in general not known.
Access modifiers, such as public, private and protected are only enforced during compilation. When you call the function through a pointer to the base class, the compiler doesn't know that the pointer points to an instance of the derived class. According to the rules the compiler can infer from this expression, this call is valid.
It is usually a semantic error to reduce the visibility of a member in a derived class. Modern programming languages such as Java and C# refuse to compile such code, because a member that is visible in the base class is always accessible in the derived class through a base pointer.
To add a little to Georg's answer:
Remember that the compiler has no control over and cannot guarantee anything about derived classes. For example, I could ship my type in a library and derive from it in an entirely new program. How is the library compiler supposed to know that derived might have a different access specifier? The derived type didn't exist when the library was compiled.
In order to support this, the compiler would have to know access specifiers at runtime and throw an exception if you attempted to access a private member.