C++ inheritance - ambiguous Function - c++

I've got an Inheritance problem:
Let's say I've got
class Time{
protected:
void foo();
};
and also
class Base: private Time{
void foo1(){ foo(); }
};
class Child: public Base, private Time{
void foo2(){ foo(); }// here my compiler says that foo is ambiguous
};
why is foo() ambiguous, if the inheritance of Time in Base is private?
PS.
Just&only for those who need to see the full code, here is the GitHub Project:
https://github.com/huntekah/Interior_decorator-OpenGL_Project/blob/master/Grafika-OpenGL/Interior_decorator/Display.cpp#L133
class Time( utilities directory ) is inherited by ControlObjects and ControlCamera, both of which are the base for Controls. Display inherits Controls , and additionally Time. commented line shows a place where SetDeltaTime() is ambiguous;

there's another error in your code: class base inherits privately from class Time and class Child inherits again privately from class time!!!
the law of inheritance:
class Time
{};
class Base : private Time
{};
class Child : public Base, private Time
{};
Base has a copy of class Time because it inherits from it.
child has a copy of class Base because it inherits from it.
*** Child has a copy of class Time because its parents (Base) has this copy.
if Child tries to inherit explicitly from class Time will issue a compile-time-error: error C2584: 'Child' : direct base 'Time' is inaccessible; already a base of 'Base'

Preliminary remarks
Your code snippet doesn't compile for another reason: Base has no access to Time's foo() as it is a private member. So the foo1() causes an error, before you have the reported ambiguity.
If you change Time to make its member protected, then you can reproduce your error exactly as you describe:
class Time{
protected:
void foo();
};
What's wrong here ?
Base privately inherits Time, so that it's members are not expected to be visible to the outside world.
But what could be true for the external world is not true for derived classes. The name lookup rules in the case of derivation say that first the name is looked up in the class hierarchy, then overloading is applied, than only is access control carried out:
10.2/1 Member name lookup determines the meaning of a name (id-expression) in a class scope. Name lookup can result in an
ambiguity, in which case the program is ill-formed. For an
id-expression, name lookup begins in the class scope of this; for a qualified-id, name lookup begins in the scope of the
nested-name-specifier. Name lookup takes place before access
control.
10.2/8 If the name of an overloaded function is unambiguously found, overloading resolution also takes place before access control.
Ambiguities can often be resolved by qualifying a name with its class
name.
As you use multiple inheritance:
Time
:
:
Base Time
\ :
\ :
Child
So you inherit twice a foo(), once via private inheritance and onve via public. This ambiguity makes the name foo in foo2() ambiguous according to the standard, and before access is verified, making your code invalid.
Note that Child sees 2 foo() but ironically can't use none of them: both come via private inherited. So even if you'd resolve the ambiguity, you'd get another error message about accessibility.

Related

Using declaration for overloaded inherited function with private accessibility

I have a class that looks something like this:
class A
{
public:
void foo(int arg) { foo(arg, false); }
private:
void foo(int arg, bool flag) {}
};
It is built this way because I want foo's flag argument to only be false when called from outside A. I want to inherit it privately, but allow calling foo:
class B : private A
{
public:
using A::foo;
};
However, this fails because the using declaraion attempts to bring all the overloads of foo into scope, including the private one, which the the compiler rightly rejects.
This isn't hard to fix, I can either:
Change the accessibility of A::foo(int, bool) to protected or public
Inherit A publicly; only public overloads of foo will be inherited
Change the name of A::foo(int, bool) so that the using declaration does not attempt to bring it into scope
This is a small, private project, and besides, that overload is only called inside A. So fixing the problem is a non-issue here. (I'm just going to rename the private overload.)
But it doesn't feel like it should be necessary. Why does the using declaration attempt to bring the non-accessible methods into scope? Is this particular case just not covered by the standard? Is there a way to fix this besides the methods I listed?
You can also redefine the overload you want and have it forward its argument to the function in A:
class B : private A
{
public:
void foo(int arg) { A::foo(arg); }
};
The using declaration is just too blunt a tool in this case. It brings function names into the derived class scope. And when the name refers to something private, it chokes. It can't distinguish overloads. The standard requires the names introduced by a using declaration to be accessible:
[namespace.udecl]/17
In a using-declarator that does not name a constructor, all members of
the set of introduced declarations shall be accessible. In a
using-declarator that names a constructor, no access check is
performed. In particular, if a derived class uses a using-declarator
to access a member of a base class, the member name shall be
accessible. If the name is that of an overloaded member function, then
all functions named shall be accessible. The base class members
mentioned by a using-declarator shall be visible in the scope of at
least one of the direct base classes of the class where the
using-declarator is specified.
The forwarding function can also be templated. So one won't need to redefine each function they want to expose individually.
class B : private A
{
public:
template<typename ...Args>
void foo(Args ...args) { A::foo(args...); }
};
It's "catch-all" like the using declaration, except the access specifier is checked only on template instantiation, i.e. when the function is called. So the template will be ill-formed based on its scope and whether or not the member in A is accessible there.
I found the following extract from Scott Meyer's Effective C++ which is related to your predicament (with emphasis added):
Item 33: Avoid hiding inherited names.
...
This means that if you inherit from a base class with overloaded functions
and you want to redefine or override only some of them, you need
to include a using declaration for each name you’d otherwise be hiding.
If you don’t, some of the names you’d like to inherit will be hidden.
...
It’s conceivable that you sometimes won’t want to inherit all the functions
from your base classes. Under public inheritance, this should
never be the case, because, again, it violates public inheritance’s is-a
relationship between base and derived classes. (That’s why the using
declarations above are in the public part of the derived class: names
that are public in a base class should also be public in a publicly
derived class.)
Under private inheritance, however, it can
make sense. For example, suppose Derived privately inherits from
Base, and the only version of the function that Derived wants to inherit is the
one taking no parameters. A using declaration won’t do the trick here,
because a using declaration makes all inherited functions with a given
name visible in the derived class.
No, this is a case for a different technique, namely, a simple forwarding function:
class Base {
public:
virtual void mf1() = 0;
virtual void mf1(int);
... // as before
};
class Derived: private Base {
public:
virtual void mf1() // forwarding function; implicitly
{
Base::mf1(); } // inline
};
}

C++ Ambiguity issue

Let the following classes :
class BaseClass
{
class OnSomeEventListener
{
public:
enum SomeEnum { BLABLA }
virtual void OnSomeEvent( SomeEnum eventData ) = 0;
}
};
class ChildClass :
public BaseClass,
public BaseClass::OnSomeEventListener
{
virtual void OnSomeEvent( BaseClass::OnSomeEventListener::SomeEnum eventData );
}
My question is : why do I need to specify BaseClass:: in front of OnSomeEventListener::SomeEnum eventData in the method virtual void OnSomeEvent( BaseClass::OnSomeEventListener::SomeEnum eventData ); ?
If I don't do it, it says that OnSomeEventListener is ambiguous between BaseClass::OnSomeEventListener and BaseClass::OnSomeEventListener::OnSomeEventListener
Why would it think i'm referencing the constructor instead of the OnSomeEventListener type ? Why would i need to prefix the argument type with BaseClass:: since I'm already inside BaseClass ?
Thank you.
Why would i need to prefix the argument type with BaseClass:: since I'm already inside BaseClass ?
You are inside BaseClass, but you are also inside OnSomeEventListener because you inherit from both.
When the compiler parses a name, it doesn't think "I need a type here, can this be an enum?", instead it thinks "I have a name here, what can it be?". And in your case it can be two different things, depending on which base class is searched for the name.
You don't need the BaseClass::OnSomeEventListener scope at all since you bring that in with your inheritance of BaseClass::OnSomeEventListener:
class ChildClass:
public BaseClass,
public BaseClass::OnSomeEventListener
{
virtual void OnSomeEvent(SomeEnum eventData);
};
That being said OnSomeEventListener in the ChildClass is ambiguous since it can be either the constructor or the class from that scope since you inherit both.
When trying to use the name OnSomeEventListener::SomeEnum, it wasn't preceded with :: so the compiler uses the unqualified lookup rules to create a lookup set. And from the compiler error you can see it first only considers OnSomeEventListener which directly becomes ambiguous in that scope since both the class itself and the constructor matches.

Resolution of inherited member functions, based on parameters' types [duplicate]

This question already has answers here:
C++: rationale behind hiding rule
(5 answers)
Closed 9 years ago.
Before asking my question I tried searching the web, but I'm not sure what terms I need to use, and I didn't find an explanation to my problem. If such an answer allready exists, feel free to just point me to it :)
Here is a small sample:
class IObject;
class ClassA;
class Base {
public: void Method(IObject * object) {}
};
class Derived : public Base {
public: void Method(ClassA * objet) {}
};
class IObject {};
class ClassA : public IObject {};
int main(int argc, char ** argv) {
IObject * object = new ClassA();
Derived derived;
derived.Method(object);
delete object;
return 0;
}
This doesn't compile because the compiler tries to use the Derived::Method version of the method, even though there exists a perfectly valid Base::Method for the given object.
To make this compile (and work), I need to add the following in Derived:
class Derived : public Base {
public:
// adding this line make the Base::Method visible to the compiler ??
using Base::Method;
void Method(ClassA * object) {}
};
After adding this line, everything works as intended.
What I don't understand is : why ? If I rename Base::Method to Base::BaseMethod, I can call it from the Derived instance without any problem. Why does the compiler fails to find the correct method based on the parameter's type ??
This rule is known as Function hiding in C++.
A method in derived class with same name as of the Base class method hides the base class method in derived class. The users of the derived class can only see the derived class method irrespective of the function parameter types. The base class method is simply not present in Derived class scope. So the overload resolution doesn't work as you expect it to.
To be able to access the Base class method in derived class you explicitly need to tell the compiler to bring it in the derived class scope with the using declaration.
This is called member function hiding: As soon as you have a function in a derived class having a different signature than a function with the same name in the base class, the base class versions of the functions are invisible to the derived class and its clients. Here's the reason why this was introduced.

Class A not visible in class C but visible in main. Why?

class A {};
class B : private A {
};
class C : public B {
public:
void f() {
A a; // This line causes error, but works when it is in main() function
}
};
int main()
{
C c;
// A a; --> This line works
return 0;
}
I am guessing this has something to do with B inheriting privately from A but cannot put my finger on it.
EDIT: Error is "class A is not visible". Compiled with g++.
name lookup is separate from access checking. and when you inherit from a class, that class' name is injected into the inheriting class' scope. so in class C you pick up the name A but it's not accessible.
one solution is to write ::A a; instead of A a;.
While Alf's answer is correct, I feel that it could be made a bit clearer (or maybe more confusing, who knows). The name of a class is injected into the scope of the class itself. As he mentions access specifiers are only checked after lookup finds what the identifier means. In the code in questions:
class A {};
class B : private A {};
struct C : public B {
void f() {
A a; // This line causes error, but works when it is in main() function
}
};
When processing C::f the compiler sees the identifier A and tries to resolve it. It searches in the scope of C and it is not present, it moves up the hierarchy and does not find it in B, but it finds it inside the base type A (lookup resolves the unqualified A to be ::A::A). In this context the identifier A is resolved to the injected name A inside the base class A of my base class B and access specifiers are checked. The compiler checks whether it can access my base class B, and then whether it can access it's base class A but this one is inaccessible due to the private inheritance and complains that you cannot access the nested name A inside A.
By providing the extra qualification ::A you are directing lookup. In this case, it will find the type A in the global namespace, which is perfectly accessible and it will compile.

‘base’ is an inaccessible base of ‘deriv’

Why is base inaccessible to deriv inside deriv? The program compiles with class deriv : public base.
#include <cstdio>
class base
{
};
class deriv : base
{
public:
void f(deriv, int){printf("deriv::f(deriv, int)\n");}
void f(base){printf("deriv::f(base)\n");}
};
int main()
{
deriv d;
d.f(d);
}
17: error: ‘base’ is an inaccessible base of ‘deriv’
17: error: initializing argument 1 of ‘void deriv::f(base)’
Because two people got it wrong already, I will ask in bold: why does base need to be publicly inherited? It is accessed from within deriv only.
You seem to be incorrectly assuming that conversion from deriv to base when calling deriv::f(base) occurs "inside deriv" and thus has to be accessible. This is not the case. When you call a function, all conversions necessary for initializing function's arguments occur in the caller's context. They are not "inside derive". They happen in the "outside world". And in your case the "outside world" has no access to deriv-to-base conversion.
In your specific case it is main that is trying to convert deriv to base. And main cannot do it since it has no access to the private base of deriv. Just to experiment you can declare int main() as a friend of deriv and the code will compile.
If you define a class with the class keyword, then members and base classes are private by default.
If the base class needs to be public, then either explicitly declare it public (as you mention in the question), or use the struct keyword which makes things public by default.
why does base need to be public?
In this case, your call to f(base) requires a conversion from deriv to base, and such a conversion is only possible if the base class is accessible. Being private, it is not accessible in main, which is where the conversion is required.
Because it is privately inherited :
class deriv : base
The default inheritance for class is private, meaning other classes and functions do not have access to the base class of the derived class.
There is a small problem in your example. This :
deriv d;
d.f(d);
is not going to do what you expect it to do because of slicing.
If we fix the above problem by changing the signature of the f to this :
void f(base&){printf("deriv::f(base)\n");}
there is still a problem accessing the base class of deriv, because it inherited privately from the base.