I have an issue regarding access declarations under g++ (version 5.1).
class Base
{
public:
void doStuff() {}
};
class Derived : private Base
{
public:
// Using older access declaration (without using) shoots a warning
// and results in the same compilation error
using Base::doStuff;
};
template<class C, typename Func>
void exec(C *c, Func func)
{
(c->*func)();
}
int main()
{
Derived d;
// Until here, everything compiles fine
d.doStuff();
// For some reason, I can't access the function pointer
exec(&d,&Derived::doStuff);
}
g++ fails to compile the above code with:
test.cpp: In instantiation of ‘void exec(C*, Func) [with C = Derived; Func = void (Base::*)()]’: test.cpp:24:27: required from here
test.cpp:17:4: error: ‘Base’ is an inaccessible base of ‘Derived’ (c->*func)();
Even when the function itself can be called (d.doStuff();
) the pointer can't be used even though I declared the function as accessible from the outside.
Private inheritance is also important, to some extent, because the Derived
class chooses to expose only a certain set of members from base(s) which are interface implementations IRL.
NB : this is a question about the language, not class design.
You can use pointers to member functions in the same manner as pointers to functions. You can compare pointers to member functions, assign values to them, and use them to call member functions.
the constructor is the first function which get called. and we can access the this pointer via constructor for the first time. if we are able to get the this pointer before constructor call (may be via malloc which will not call constructor at all), we can call member function even before constructor call.
We declare the function pointer, i.e., void (*ptr)(char*). The statement ptr=printname means that we are assigning the address of printname() function to ptr. Now, we can call the printname() function by using the statement ptr(s).
Pointer-to-Member Operators The C++ language has specific operators to represent pointer-to-member access. The . * and ->* operator function returns specific class member values for the object that it represents on the left side of an expression while the right side specifies a class member.
The problem is that &Derived::doStuff
isn't actually a pointer to a member of class Derived
. From [expr.unary.op]:
The result of the unary
&
operator is a pointer to its operand. The operand shall be an lvalue or a qualified-id. If the operand is a qualified-id naming a non-static or variant memberm
of some classC
with typeT
, the result has type “pointer to member of classC
of typeT
” and is a prvalue designatingC::m
.
doStuff
is not a member of Derived
. It is a member of Base
. Hence it has type pointer to member of Base
, or void (Base::*)()
. What the using-declaration does here is simply an aid to overload resolution, from [namespace.udecl]:
For the purpose of overload resolution, the functions which are introduced by a using-declaration into a derived class will be treated as though they were members of the derived class.
That's why d.doStuff()
works. However, through the function pointer, you're trying to call a Base
member function on a Derived
object. There's no overload resolution here since you're using a function pointer directly, so the base class function would be inaccessible.
You might think you could just cast &Derived::doStuff
to the "correct" type:
exec(&d, static_cast<void (Derived::*)()>(&Derived::doStuff));
But you can't do that either according to [conv.mem], since again Base
is an inaccessible base of Derived
:
A prvalue of type “pointer to member of
B
of type cvT
”, whereB
is a class type, can be converted to a prvalue of type “pointer to member ofD
of type cvT
”, whereD
is a derived class (Clause 10) ofB
. IfB
is an inaccessible (Clause 11), ambiguous (10.2), or virtual (10.1) base class ofD
, or a base class of a virtual base class ofD
, a program that necessitates this conversion is ill-formed.
I guess the reason is that the member function is not really part of the derived class, but rather of the base class. This can be shown somehow empirically by inspecting the type of the member function pointer and comparing it with a pointer to the base member function:
cout << typeid(&Derived::doStuff).name() << endl
<< typeid(& Base::doStuff).name() << endl;
Live here.
I'm currently searching the standard for some background on this.
Barry's answer holds the respective parts of the standard.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With