Ambiguity while referencing privately inherited method from of base class [duplicate] - c++

I am unable to understand the output of the following C++ snippet.
Should not objc.fn() call A's fn() since B's fn() is private and should not be visible in C. However, the answer is: the call to fn() is ambiguous. How?
#include<iostream>
using namespace std;
class A{
public:
void fn() { cout << "1"; }
};
class B{
void fn() { cout << "2"; }
};
class C: public A, public B {};
int main(){
C objc;
objc.fn();
return 0;
}

According to the book C++ Templates: The Complete Guide Appendix B.1,
At a very high level, a call to a named function can be processed in
the following way:
The name is looked up to form an initial overload set.
If necessary, this set is tweaked in various ways (for example,
template deduction occurs).
Any candidate that doesn't match the call at all (even after
considering implicit conversions and default arguments) is
eliminated from the overload set. This results in a set of so-called
viable function candidates.
Overload resolution is performed to find a best candidate. If there
is one, it is selected; otherwise, the call is ambiguous.
The selected candidate is checked. For example, if it is an
inaccessible private member, a diagnostic is issued.
As you can see, the access authority is checked at last, so the call to fn() is ambiguous will be reported firstly at step #4.

Consider this:
class D {
void fn1() {}
public:
void fn2() {}
};
int main() {
D d;
d.fn2(); // Compiles fine
d.fn1(); // Error: fn1 is private
}
Notice that the error for d.fn1() is about fn1 being private, not that fn1 is unknown or invisible in this scope. By the same token, B::fn is indeed visible in C.
We get this behavior because the compiler does name resolution the same for public and private members. Only after the name has been resolved does the accessibility check come into play.
It is the same for your case: Which fn do you mean? Only after you have answered that question can the compiler tell you if you have access to that fn or not.

As I suspected, this code gives an ambiguous reference and does not compile. As you have declared both functions with the same signature, the compiler doesn't know which of the functions to select, giving a complaint at compilation time.
$ make pru
g++ pru.cc -o pru
pru.cc: In function ‘int main()’:
pru.cc:15:8: error: request for member ‘fn’ is ambiguous
pru.cc:9:9: error: candidates are: void B::fn()
pru.cc:6:9: error: void A::fn()
make: *** [pru] Error 1
I think you can select which function to use, placing the A::fn() selector. Even if, as it is the case in this example, one of the functions is private, you have two functions to select from (you could make the call from inside a B method and you'll get the same error ---in that case you have visibility to both methods).

The correct answer has already been given by #songyuanyao.
Checking access specifiers at the last was designed by the C++ Standard Committee.
Had it not been so, the following things would have occurred :
If one modifies their code in future and change the access specifier of their functions, it may break the compilation of the dependent classes.
More horrible yet, you may start calling a totally unrelated function, and would remain oblivious..!!
Let us assume that access specifiers prevent a function from participating in overload resolution, then :
class A{
public:
void fn() { cout << "1"; }
};
class B{
void fn() { cout << "2"; }
};
class C: public A, public B {};
int main(){
C objc;
objc.fn(); // A::fn() is being invoked
return 0;
}
Now we modify the code:
class A{
void fn() { cout << "1"; }
};
class B{
public:
void fn() { cout << "2"; }
};
Nothing else has been touched, and suddenly
objc.fn(); // B::fn() is being invoked
The caller of your function has no idea that his underlying function is not the same anymore.
This is blasphemy !!
To prevent all such mishaps from happening, the Standard Committee took this design decision.

Related

Why does the member function name lookup stay in the parent class?

Motivation, if it helps: : I have struct member functions that are radial-basis-function kernels. They are called 1e06 x 15 x 1e05 times in a numerical simulation. Counting on devirtualization to inline virtual functions is not something I want to do for that many function calls. Also, the structs (RBF kernels) are already used as template parameters of a larger interpolation class.
Minimal working example
I have a function g() that is always the same, and I want to reuse it, so I pack it in the base class.
The function g() calls a function f() that is different in derived classes.
I don't want to use virtual functions to resolve the function names at runtime, because this incurs additional costs (I measured it in my code, it has an effect).
Here is the example:
#include <iostream>
struct A
{
double f() const { return 0; };
void g() const
{
std::cout << f() << std::endl;
}
};
struct B : private A
{
using A::g;
double f() const { return 1; };
};
struct C : private A
{
using A::g;
double f() const { return 2; };
};
int main()
{
B b;
C c;
b.g(); // Outputs 0 instead of 1
c.g(); // Outputs 0 instead of 2
}
I expected the name resolution mechanism to figure out I want to use "A::g()", but then to return to "B" or "C" to resolve the "f()" function. Something along the lines: "when I know a type at compile time, I will try to resolve all names in this type first, and do a name lookup from objects/parents something is missing, then go back to the type I was called from". However, it seems to figure out "A::g()" is used, then it sits in "A" and just picks "A::f()", even though the actual call to "g()" came from "B" and "C".
This can be solved using virtual functions, but I don't understand and would like to know the reasoning behind the name lookup sticking to the parent class when types are known at compile time.
How can I get this to work without virtual functions?
This is a standard task for the CRTP. The base class needs to know what the static type of the object is, and then it just casts itself to that.
template<typename Derived>
struct A
{
void g() const
{
cout << static_cast<Derived const*>(this)->f() << endl;
}
};
struct B : A<B>
{
using A::g;
double f() const { return 1; };
};
Also, responding to a comment you wrote, (which is maybe your real question?),
can you tell me what is the reasoning for the name lookup to stick to the base class, instead of returning to the derived class once it looked up g()?
Because classes are intended to be used for object-oriented programming, not for code reuse. The programmer of A needs to be able to understand what their code is doing, which means subclasses shouldn't be able to arbitrarily override functionality from the base class. That's what virtual is, really: A giving its subclasses permission to override that specific member. Anything that A hasn't opted-in to that for, they should be able to rely on.
Consider in your example: What if the author of B later added an integer member which happened to be called endl? Should that break A? Should B have to care about all the private member names of A? And if the author of A wants to add a member variable, should they be able to do so in a way that doesn't potentially break some subclass? (The answers are "no", "no", and "yes".)

Restricting functions that can be passed to another function in C++

I have a class containing several very similar functions and a couple other functions that take those interchangeably functions as input.
A simpler example:
class functions{
public:
int a();
int b();
int F(int (*f)() ); //f can only be a() or b()
};
Before I put them in a class, I had something like
if(f!=a || f!=b) cout<<"error";
With the class, it seems to just get more complicated, since I believe I now need to pass a class instance or something to get rid of my error: invalid use of member function
I have just started to learn about enumerated lists, and it seems like that would do the job if I was dealing with normal variables. Can I create an enum of functions?
What is the best way to restrict functions that can be passed to another function?
I'm pursuing the static cast method, but still needing help with int F( int(*f)() );
int functions::F(int (functions::*f)() )
{
if(f==functions::a)
//gives error: invalid operands of types 'int (functions::*)()'
// and 'int (int(*)()' to binary operator =='
int x=f();
//gives error: must use ‘.*’ or ‘->*’ to call pointer-to-member
//function in 'f(...)'
int y=(functions.*f)();
//gives error: expected primary-expression before ‘.*’ token
return 0;
}
It really depends on what you want to achieve:
I'd say largely that this sort of restriction is best validated by code review rather than coding...
The other solution is to not use that construct at all, and making a Fa() and Fb() function that calls the (private) a() and b() member functions.
And the remainder of the question is "how do I call a member function of a class" -the answer to which depends highly on whether Functions has member variables that are used in a() and b() or not. If there are no member functions, then declaring the a() and b() members as static will work. On the other hand, if you want to use a "member function pointer", the syntax is int (Functions::*f) and &Functions::a respectively, and the call has to be made using an instance of Functions. so if we have Functions fun, you'd do fun.*f(). Or (*this).*f(), insice F().
You may wrap the accepted function in a class:
#include <iostream>
class Functions
{
public:
int a() { return 0; }
int b() { return 1; }
};
class Accept
{
public:
typedef int (Functions::*AcceptFunction)();
int apply(Functions& object, AcceptFunction function) {
return (object.*function)();
}
};
int main()
{
Functions functions;
Accept accept;
std::cout << accept.apply(functions, &Functions::b) << std::endl;
}
(Feel free to bundle it by making Functions a nested class in Accept)

How can I choose the correct overload?

Consider the following c++ code
class A
{
public:
void doStuff() {};
void callStuff()
{
doStuff(true);
doStuff();
};
private:
void doStuff(bool doIt = false) {};
};
int main()
{
A a;
a.doStuff();
a.callStuff();
return 0;
}
Not surprisingly, GCC gives several errors when compiling this:
overload.cpp: In member function ‘void A::callStuff()’:
overload.cpp:8:10: error: call of overloaded ‘doStuff()’ is ambiguous
doStuff();
^
overload.cpp:8:10: note: candidates are:
overload.cpp:4:12: note: void A::doStuff()
void doStuff() {};
^
overload.cpp:11:12: note: void A::doStuff(bool)
void doStuff(bool doIt = false) {};
^
overload.cpp: In function ‘int main()’:
overload.cpp:17:17: error: call of overloaded ‘doStuff()’ is ambiguous
a.doStuff();
^
overload.cpp:17:17: note: candidates are:
overload.cpp:4:12: note: void A::doStuff()
void doStuff() {};
^
overload.cpp:11:12: note: void A::doStuff(bool)
void doStuff(bool doIt = false) {};
^
I have several questions:
How can I tell the compiler which overload I want to use? Will I be forced to remove one of them?
If I have to remove one of them, how can I find this problem at compile time without trying to call the overload? As long as I am not calling them everything should compile fine so I might only find out later that I am unable to call an overload that I have added once I am trying to call it.
Why does the second error occur? The main function should not be able to access the private overload so it should know which one to use.
How can I tell the compiler which overload I want to use? Will I be
forced to remove one of them?
You can't, just remove or rename one of them.
If I have to remove one of them, how can I find this problem at
compile time without trying to call the overload? As long as I am not
calling them everything should compile fine so I might only find out
later that I am unable to call an overload that I have added once I am
trying to call it.
You can't either. The ambiguity is only detected when you try to call the member function using no arguments. Even if you could perform some compile time checks, there would have to be very specific, and it would be easier to just remove or rename one of the overloads.
Why does the second error occur? The main function should not be able
to access the private overload so it should know which one to use.
Unfortunately, overload resolution occurs before access specifiers are taken into account. Therefore, the compiler doesn't even take into account the fact that one of the overloads is private: the ambiguous call is found before that even happens. I don't really know why this happens this way, but that's what the standard says.
The cause of all your woes are related to your function definitions and their corresponding calls.
So, firstly, the compiler is correct in that your function calls are ambiguous, hence your errors - as it can't distinguish which version is required based on your usage. While member functions can be overloaded, with same name on the same scope, they must have different signatures (a member function's signature is comprised of the member function's name and the type and order of the member function's parameters).
Hence:
void doStuff() {};
void doStuff(bool doIt = false) {};
when called like this:
doStuff();
are equivalent, leading to an ambiguous function call as the compiler can't determine if you want to call:
void doStuff();
or
void doStuff(boo doIt = false);
with a unsupplied parameter value. Function visibility doesn't get to be checked because of the same problem.
The only around this is to change the name of one of the functions or the signature of the functions (while keeping the same name).
Hence, something like this is perfectly legal:
class A
{
public:
void doStuff() {};
void callStuff()
{
doStuff(1, true);
doStuff();
};
private:
void doStuff(int i, bool doIt = false) {};
};
int main()
{
A a;
a.doStuff();
a.callStuff();
return 0;
}
Thus:
Change the name of one of the functions or its signature as well as its corresponding function call.
You can't because it's an ambiguous call. The only solution is to make the suggested changes described above.
What mfontanini said:
Unfortunately, overload resolution occurs before access specifiers are
taken into account. Therefore, the compiler doesn't even take into
account the fact that one of the overloads is private: the ambiguity
is found before that even happens.
See this link for additional reference:
http://www.learncpp.com/cpp-tutorial/77-default-parameters/
You need to remove the default parameters “bool doIt = false”.
class A
{
public:
void doStuff() {};
void callStuff()
{
doStuff(true);
doStuff();
};
private:
//void doStuff(bool doIt = false) {};
void doStuff(bool doIt) {};
};
int main()
{
A a;
a.doStuff();
a.callStuff();
return 0;
}

Inheritance, pseudo polymorphism

Whilst digging through the STL sources (DinkumWare, SGI, STLport, etc..) and trying to make sense of their implementation choices (it's going well), I came across something I feel is a bit odd or rather ive never run into before.
Generally when one wishes to overload a member function in a derived class, you would prepend the base class member function signature with the virtual keyword, however at various points in the STL source this is not the case.
Here is a cut-down version of what I'm seeing in the STL implementations:
template <typename T> class A {
public:
void func( ) { std::cout << "inside A func( )" << std::endl; }
};
template <typename T> class B : public A<T> {
public:
void func( ) { std::cout << "inside B func( )" << std::endl; }
};
The compiler seems fine with this pseudo-polymorphism, where as I was expecting an error something along the lines of:
error C2535: 'void B<T>::func(void)': member function already defined or declared
Would someone be kind enough to explain what is going on here?
PS: This also seems to work without the classes being templates too.
'Regards
Without the virtual keyword - when redefining a function, you are hiding the super's function.
In your case, by redifining func(), you tell the compiler there is a new function for B, which is different from A's.
Though, because it is not declared virtual, you will see this affect only if you invoke func() from a variable of type B. A variable of type A which holds a B, will invoke A's func().
A *a = new B;
a->func()
will invoke the first [A's] method.
To invoke B's method, you need the type to be B:
B *b = new B;
b->func()
The B<T>::func member simply shadows A<T>::func. When you call p->func() where A<T> *p points to a B<T>, A<T>::func is called, so there's no polymorphism.
#include <iostream>
struct A
{
void func() { std::cout << "Hello!\n"; }
};
struct B : public A
{
void func() { std::cout << "Goodbye!\n"; }
};
int main()
{
B b;
A *p = &b;
p->func();
b.func();
}
(Demo)
In the C++ standard, there's at least one place where this shadowing/name hiding is exploited: std::ifstream::rdbuf hides its ancestor's method by that name and actually changes its return type.
There clearly is no error because these functions are just overloads: A::func() has a signature taking an A object (a reference or a pointer) as first argument while B::func() has a signature taking a B object as first argument. That is, this is just overloading of two functions with different argument but the function name.
This is done in a few places to produce a different return type from a function which is essentially trivially forwarding to another function (at least, these are the places I can think of). This is just to make life a bit easier for users although it is actually more confusing than anything else. The examples I can think of (e.g. the rdbuf() function in streams) should have created a different name instead.
This is acceptable code, B<T>::func is just hiding A<T>::func.
A<int> a;
B<int> b;
a.func(); // inside A
b.func(); // inside B
A<int> *const pA = new B<int>();
pA->func(); // inside A
When calling func through a polymorphic type, it will call the function on the type of the pointer.

boost::bind with protected members & context

In the below code, there are two "equivalent" calls to std::for_each using boost:bind expressions. The indicated line compiles, the indicated failing line fails. The best explanation I can find in the standard amounts to "because we said so". I'm looking for "why the standard indicates this behavior". My suppositions are below.
My question is simply: Why does the indicated line compile and the equivalent following line fail to compile (and I don't want because "the standard says so", I already know that - I will not accept any answers that give this as an explanation; I'd like an explanation as to why the standard says so).
Notes: Although I use boost, boost is irrelevant to this question, and the error in various formats has been reproduced using g++ 4.1.* and VC7.1.
#include <boost/bind.hpp>
#include <iostream>
#include <map>
#include <algorithm>
class Base
{
protected:
void foo(int i)
{ std::cout << "Base: " << i << std::endl; }
};
struct Derived : public Base
{
Derived()
{
data[0] = 5;
data[1] = 6;
data[2] = 7;
}
void test()
{
// Compiles
std::for_each(data.begin(), data.end(),
boost::bind(&Derived::foo, this,
boost::bind(&std::map<int, int>::value_type::second, _1)));
// Fails to compile - why?
std::for_each(data.begin(), data.end(),
boost::bind(&Base::foo, this,
boost::bind(&std::map<int, int>::value_type::second, _1)));
}
std::map<int, int> data;
};
int main(int, const char**)
{
Derived().test();
return 0;
}
The indicated line fails with this error:
main.C: In member function 'void Derived::test()':
main.C:9: error: 'void Base::foo(int)' is protected
main.C:31: error: within this context
As noted, the supposedly equivalent statement above compiles cleanly (and if the offending statement is commented out, runs with the expected result of printing “5”, “6”, “7” on separate lines).
While searching for an explanation, I came across 11.5.1 in the standard (specifically, I’m looking at the 2006-11-06 draft):
An additional access check beyond
those described earlier in clause 11
is applied when a non-static data
member or nonstatic member function is
a protected member of its naming class
(11.2)105) 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 name 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.
After reading this, it became evidently why the second statement failed while the first succeeded, but then the question came up: What is the rationale for this?
My initial thought was that the compiler was expanding the boost::bind templates, discovering that Base::foo was protected and kicking it out because boost::bind<…> was not a friend. But, the more I thought about this explanation, the less it made sense, because if I recall correctly, as soon as you take the pointer to a member (assuming you initially are within access control of the member), all access control information is lost (i.e. I could define a function that returns an arbitrary pointer to a member that alternately returns a public, protected or private member depending on some input and the returner would be none the wiser).
More I thought about it, and the only plausible explanation I could come up with why it should make a difference was in the case of multiple inheritance. Specifically, that depending on the class layout, the member pointer when calculated from Base would be different than that calculated from Derived.
It's all about "context". In the first call the context of the call is Derived which has access to the protected members of Base and hence is allowed to take addresses of them. In the second the context is "outside of" Derived and hence outside of Base so the protected member access is not allowed.
Actually, this seems logical. Inheritance gives you access to Derived::foo and not to Base::foo. Let me illustrate with a code example:
struct Derived : public Base
{
void callPrivateMethod(Base &b)
{
// this should obviously fail
b.foo(5);
// pointer-to-member call should also fail
void (Base::*pBaseFoo) (int) = &Base::foo; // the same error as yours here
(b.*pBaseFoo)(5);
}
};
The reason for this restriction is enforcement of access control across different classes that share a common base.
This is reinforced by notes in Core Language Defects Report defect #385, the relevant part copied here for reference:
[...] the reason we have this rule is that C's use of inherited protected members might be different from their use in a sibling class, say D. Thus members and friends of C can only use B::p in a manner consistent with C's usage, i.e., in C or derived-from-C objects.
As an example of something this rule prevents:
class B {
protected:
void p() { };
};
class C : public B {
public:
typedef void (B::*fn_t)();
fn_t get_p() {
return &B::p; // compilation error here, B::p is protected
}
};
class D : public B { };
int main() {
C c;
C::fn_t pbp = c.get_p();
B * pb = new D();
(pb->*pbp)();
}
The protected status of D::p is something we want the compiler to enforce, but if the above compiled that would not be the case.