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.
Related
I have a quite niche problem concerning private inheritance. I also have a solution for the problem, but I don't understand why it works.
TL;DR
Why does private inheritance on some intermediate level prevent me from passing the base type as a parameter to a (privately) derived class?
Consider the following code (also available here http://cpp.sh/3p5zv5): I have a composite-type class that can contain pointers to child elements of its own type. Also, that class contains the template method MyMethodTemplate(T value), allowing any type of Parameter. I need to inherit from this class multiple times, such that MyMethodTemplate(T) is not available, and instead only a typed version MyMethod() can be called with e.g. int, string, whatever.
Since the derived classes were going to contain a lot of boilerplate code (not shown here), I wrote the class template cSpecializedComposite that inherits privately from cComposite (successfully hiding MyMethodTemplate()). Its method MyMethod() internally calls MyMethodTemplate() from its parent class. So far, so good.
Now, to get rid of the template parameter in my end user code, I wanted to write trivial classes that publicly inherit from the template (cSpecializedCompositeInt, cSpecializedCompositeString, ...). My assumption was that cSpecializedCompositeInt would know cSpecializedComposite's interface, but not its internals. In cSpecializedCompositeInt's constructor, I can optionally pass a vector of unique_ptr that is passed on to its parent constructor (who does god knows what with it, nothing to see here, move along). Note that the class definition for cComposite is visible to cSpecializedCompositeInt, even if cSpecializedCompositeInt doesn't inherit from it, as far as it knows.
However, I get a compiler error C2247 in cSpecializedCompositeInt's constructor, telling me I can't use cComposite, because cSpecializedComposite inherited privately from it. This occured on both msvc10 and GCC 4.9.2 (the compiler behind http://cpp.sh).
Changing the private inheritance to protected allows cSpecializedCompositeInt to know it inherited indirectly from cComposite, and the compiler error goes away.
In how far is this related to Private Inheritance and Derived Object to Base reference ?
#include <vector>
#include <memory>
class cComposite
{
public:
cComposite(std::vector<std::unique_ptr<cComposite>>&& vecC)
: m_vecC(std::move(vecC))
{
//empty
}
template <typename T>
void MyTemplateMethod(T value)
{
//do something with any type of value
}
private:
std::vector<std::unique_ptr<cComposite>> m_vecC;
};
template <typename MySpecialType>
class cSpecializedComposite : private cComposite
{
public:
cSpecializedComposite(std::vector<std::unique_ptr<cComposite>>&& vecC)
: cComposite(std::move(vecC))
{
//empty
}
void MyMethod(MySpecialType value)
{
//allow only MySpecialType as Input, call base class template method to do something
cComposite::MyTemplateMethod(value);
}
};
class cSpecializedCompositeInt : public cSpecializedComposite<int>
{
public:
cSpecializedCompositeInt(std::vector<std::unique_ptr<cComposite>>&& vecC)
: cSpecializedComposite(std::move(vecC))
{
//empty
}
};
int main(int argc, char* argv[])
{
std::vector<std::unique_ptr<cComposite>> vecC;
cSpecializedCompositeInt spec(std::move(vecC));
spec.MyMethod(5);
return 0;
}
One of the recurring themes on this site is requesting a Minimal, Complete, and Verifiable example. You did do a good job with the "complete" and "verifiable" parts, but not so much with the "minimal". Please allow me to simplify your code to remove potentially distracting details.
// Base class, constructed from a type that involves itself.
class A {
public:
A(A *) {}
};
// Intermediate class, derives privately from the base class.
class B : private A {
public:
B(A * a) : A(a) {}
};
// Most derived class, same constructor parameter as the base class.
class C : public B {
public:
C(A * a) : B(a) {} /// error: 'class A A::A' is inaccessible
};
int main(int argc, char* argv[])
{
return 0;
}
Note the lack of templates and vectors; those are just red herrings. Also, apologies for using raw pointers; they are just a convenient way to introduce the issue with minimal overhead/baggage. (I'd use references, but that would turn one of the constructors into a copy constructor, which feels unwise.)
Look at the definition of B's constructor. In that definition, "A" is used twice: once as part of the type of the parameter, and once in the initializer list. For the latter case, the use of A definitely refers to the (private) base class of the class being constructed. Question: why should the compiler assume that the former case does not also refer to the private base class? (If the private base class was changed, would the parameter's type necessarily change as well? The compiler assumes "yes", but you could introduce another intermediate class, between A and B, which presumably would preserve the parameter's type.)
As far as I know (I have not double-checked the language specs), when you are in the context of B, any mention of its private base class is considered private information. You could think of the constructor's declaration as: B(<private> * a). Since C is not allowed to know the private information of B, it is not allowed to call this constructor. It simply cannot match the parameter list, much the same as if the parameter's type was defined within a private section of B. Fortunately, this can be circumvented by removing a mention of "A" from the parameter list.
In the following, the only change is the introduction and use of a typedef.
class A;
typedef A * special_type;
// Base class, constructed from a type that *indirectly* involves itself.
class A {
public:
A(special_type) {}
};
// Intermediate class, derives privately from the base class.
class B : private A {
public:
B(special_type a) : A(a) {}
};
// Most derived class, same constructor parameter as the base class.
class C : public B {
public:
C(special_type a) : B(a) {} /// no error!
};
int main(int argc, char* argv[])
{
return 0;
}
In your case, this would have the side benefit of introducing a shorter synonym for that rather symbol-rich std::vector<std::unique_ptr<cComposite>>.
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
};
}
My base class offers a virtual method with no arguments, like this:
class Base{
virtual void myMethod(void) = 0;
};
I would like to override it in the Derived class and offer an implementation (the Derived class is not supposed to be an abstract type), and additionally provide an optional parameter via setting the default value, as so:
class Derived : public Base{
void myMethod(Thing *optional = NULL) { ... }
};
But I seem to be getting the error of the type:
error: cannot allocate an object of abstract type 'Derived'
because the following virtual functions are pure within 'Derived':
virtual void myMethod()
Now, I know that when overloading functions, the following functions can not exist along each other:
void myFunction();
void myFunction(Thing *optional = NULL);
because the function call myFunction() would match both declared functions. Following this logic, my definition in Derived should override the Base method with no arguments, and "add another method" with one argument, but it doesn't.
I know I can solve this problem by definitions like this:
class Derived : public Base{
void myMethod(Thing *optional) { ... }
void myMethod() { myMethod(NULL); }
};
My question is: is this really the only way to achieve the desired functionality? If so, why is what I am trying not allowed and not compiled as I would expect?
Yes, what you propose as the last code block is the right way to solve this.
Your first attempt does not work because you are defining a method with one argument, and the virtual method you are trying to override has zero. Giving arguments default values does not change the number of arguments the function takes, and therefore it does not match the no-arg overload in order to override it. All it does is instruct the compiler to insert the default value at any call sites that omit it, and in this case such a call would be ambiguous between the no-arg version and the one-arg version with a default value for the parameter.
Unfortunately, I studied class design and design patterns mostly in the context of Java; thus, I sometimes have a hard time to translate a familiar pattern to C++.
Assume we want to have a base class which's functionality is extended by a sub-class. In Java, we would do something like this:
public class BaseClass<T> {
//T is used here
protected int foo = 0;
}
public class DerivedClass<T> extends BaseClass<T> {
public void incr_foo() {
++foo;
}
}
Which I directly translated to C++:
template<class T>
class BaseClass {
protected:
size_t foo = 0;
//T is used here
};
template<class T>
class DerivedClass : public BaseClass<T> {
public:
void incr_foo() {
++(this->foo);
}
};
Since the C++ semantics of 'protected' diver from the Java-semantics, we need to use something like 'this->foo' to access protected members of the base class.
Edit: If we just use '++foo', the compiler gives the error: 'use of undeclared identifier foo'.
EditEnd
If you need to access several members of the base class, this can get a bit tedious and is not so nice to read.
Is this a good design desicion? If not, what better ways are there to achieve this?
This has nothing to do with the member being protected; you'd get the exact same error with a public member.
The real reason is that templates are involed. More specifically, that your class template has a base class which depends on a template parameter. This means that when parsing the template, the compiler will not (be able to) look into that base class to find inherited members which are used unqualified. It makes sense: when the template is parsed, the template parameter values are not known yet and thus the compiler has no idea what members the base class will have (remember partial and total specialisation exist!).
In order to overcome this, you must somehow tell the compiler that the name foo depends on template parameters (that it's a dependent name). Once you do so, the compiler will not try to resolve it when parsing the template; it will postpone resolution until the template is instantiated. At that point, template arguments are known and thus the base class can be checked.
You have three ways to mark a member name as dependent:
Refer to the name through this, as you're doing: this->foo
Refer to the name through base-class qualification: BaseClass<T>::foo
Bring the name into the scope of the derived class:
template<class T>
class DerivedClass : public BaseClass<T> {
protected:
using BaseClass<T>::foo; // from this point on, `foo` is a dependent name
public:
void incr_foo() {
++foo; // works fine now
}
};
BaseClass<T> is a dependent type - it depends on the template parameter used to instantiate DerivedClass. Until DerivedClass instantiated, the compiler doesn't know what the type is: it might be an instantiation of the generic template, or it might be an explicit specialisation, with different members.
So, within the definition of DerivedClass, there is no way to know which names refer to members of the base class. You have to specify that they are, using this-> or BaseClass::.
In a class with a non-dependent base class, you can use any accessible base-class members as if they were direct members, just as in Java.
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.