Consider following example
#include <iostream>
struct PureVirtual {
virtual void Function() = 0;
};
struct FunctionImpl {
virtual void Function() {
std::cout << "FunctionImpl::Function()" << std::endl;
}
};
struct NonPureVirtual : public FunctionImpl, public PureVirtual {
using FunctionImpl::Function;
};
int main() {
NonPureVirtual c;
c.Function();
}
Compiler (GCC 4.9, Clang 3.5) exits with error
test.cpp:18:20: error: variable type 'NonPureVirtual' is an abstract class
NonPureVirtual c;
^
test.cpp:4:18: note: unimplemented pure virtual method 'Function' in 'NonPureVirtual'
virtual void Function() = 0;
^
But when I don't derive form PureVirtual everything is OK. This is weird because Standard 10.4.4 says
A class is abstract if it contains or inherits at least one pure
virtual function for which the final overrider is pure virtual.
They are not saying anything about what the final overrider is but I suppose it should be FunctionImpl::Function() especially when I made it available through using directive. So why is still NonPureVirtual abstract class and how can I fix this.
FunctionImpl::Function and PureVirtual::Function are different functions from different classes.
Their respective types are void (FunctionImpl::*)() and void (PureVirtual::*)().
Since PureVirtual and FunctionImpl are unrelated classes, these function types are unrelated.
They happen to have the same name and the same parameters and return type, but since they're different, the using FunctionImpl::Function line doesn't make that function an override of the one in PureVirtual.
And if you declared a variable of type void (PureVirtual::*)(), you wouldn't be able to assign FunctionImpl::Function to it.
In other words, the final override of PureVirtual::Function is the original one in PureVirtual, which is pure virtual.
For making what you want possible, Matthieu M.'s answer (using a forwarding call) is the way to go, it seems.
You cannot use a using directive and have to resort to a fowarding call instead:
struct NonPureVirtual : public FunctionImpl, public PureVirtual {
virtual void Function() override {
return FunctionImpl::Function();
}
};
And yes, it works as expected.
You're attributing a using declaration with something that it doesn't do. What it does is (From draft n3337, 7.3.3/1):
... using-declaration introduces a name into the declarative region in which the using-declaration appears.
Later from the same paragraph:
If a using-declaration names a constructor (3.4.3.1), it implicitly declares a set of constructors in the
class in which the using-declaration appears (12.9); otherwise the name specified in a using-declaration is a
synonym for the name of some entity declared elsewhere.
In your case, FunctionImpl::Function is first declared in FunctionImpl class and it is its member. A using-declaration doesn't change that fact, as paragraph 16 says further down:
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. In particular, the implicit this parameter shall be treated as if it were a pointer to the derived class rather than to the base class. This has no effect on the type of the function, and in all other respects the function remains a member of
the base class.
Now on to the definition of overriding (10.3/2):
If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name, parameter-type-list (8.3.5), cv-qualification, and ref-qualifier (or absence of same) as Base::vf is declared, then Derived::vf is also virtual (whether or not it is so declared) and it overrides Base::vf. For convenience we say that any virtual function overrides itself.
And there's also the definition of a final overrider in the same paragraph.
A virtual member function C::vf of a class object S is a final overrider unless the most derived class (1.8) of which S is a base class subobject (if any) declares or inherits another member function that overrides vf. In a derived class, if a virtual member function of a base class subobject has more than one final overrider the program is ill-formed. [...]
I think that makes it clear that you can't use a using declaration to override a virtual function. A possible fix is in Matthieu's answer.
Related
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
};
}
I have two classes representing contexts for some methods.
class BaseContext {};
class DerivedContext : public BaseContext {};
I have a base class:
class MyBase {
protected:
virtual void doSome(BaseContext* context);
};
And a derived class:
class MyDerived : public MyBase {
protected:
virtual void doSome(DerivedContext* context) override; // Overriding
virtual void doSome(DerivedContext* context); // Overloading?
};
Since DerivedContext derives from BaseContext, it might seems that I am overriding doSome. But it might also be an overloading...
Which one is correct? Am I overriding or overloading here?
Thus, if I type (MyBase* my = new MyDerived())->doSome(new DerivedContext()), what should I get?
This is neither overriding nor overloading. Since the parameter's type is different, MyDerived::doSome is just hiding MyBase::doSome.
1.1. Since DerivedContext derives from BaseContext, it might seems that I am overriding doSome.
No. Here're the preconditions of overriding listed in the standard. $10.3/2 Virtual functions
[class.virtual]:
(emphasis mine)
If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name, parameter-type-list ([dcl.fct]), cv-qualification, and ref-qualifier (or absence of same) as Base::vf is declared, then Derived::vf is also virtual (whether or not it is so declared) and it overrides110 Base::vf.
110) A function with the same name but a different parameter list (Clause [over]) as a virtual function is not necessarily virtual and does not override.
In fact with override specifier you'll get a compile error for this case. e.g.
error: 'doSome' marked 'override' but does not override any member functions
1.2. But it might also be an overloading...
You can't overload functions across scopes according to the rule of unqualified name lookup (unless using using-declaration to introduce names into the same scope).
Thus, if I type (MyBase* my = new MyDerived())->doSome(new DerivedContext()), what should I get?
MyBase::doSome() will be invoked since you call it on a MyBase*. This is not overriding, so no dynamic dispatching happens here.
LIVE
Note the argument DerivedContext* will be implicitly converted to BaseContext* and then passed to the function. BTW (MyBase* my = new MyDerived())->... is not valid syntax.
While only specifying the member function with another argument type, you are hiding the function from the base class.
With the override specifier you should get a compile error as there is no such function (with the exact same signature) in the base class.
Overriding is when redefining virtual a member function in a derived class with the exact same arguments (number and type). The override specifier is optional but encouraged as it helps identifying subtle bugs as in your case.
Overloading is when defining a function (not necessarily member of a class) with a different number or types of arguments.
Just put override after the function definition and see if it compiles. If it compiles, it is overriding the virtual method in the base class. If it does not, it would hide the base class method.
Consider the following classes in C++11:
class Base
{
public:
virtual void foo() = 0;
}
class Sub1 : public Base
{
public:
virtual void foo() override {};
}
class Sub2 : public Base
{
public:
void foo() override {};
}
What are the consequences of making the overridden function non-virtual as in Sub2?
An override of a virtual function is always virtual regardless of whether it's declared as such. Thus, having or not having the virtual keyword in the declaration of Sub2::foo() has no effect whatsoever as far as the language is concerned, since the override keyword means that the function must override a member function of a base class. From §10.3 [class.virtual]/p2 of the standard, emphasis added:
If a virtual member function vf is declared in a class Base and in
a class Derived, derived directly or indirectly from Base, a
member function vf with the same name, parameter-type-list (8.3.5),
cv-qualification, and ref-qualifier (or absence of same) as Base::vf
is declared, then Derived::vf is also virtual (whether or not it
is so declared) and it overrides Base::vf. For convenience we say
that any virtual function overrides itself.
Omitting the word virtual does not make the function non-virtual. It does reduce the verbosity, the amount of visual noise, or in short, the way that the source code text can make an impression of just being too long-winded without any specific part of it introducing anything really new that can capture the reader's attention so that it all appears more or less like a gray mass of text, which of course can lead to some important details being overlooked, which is to say, inadvertently ignored. The override keyword is preferable.
I looked over the internet for an answer to my questions but couldn't find any, so here I am.
Is it correct to specify override to my function that derived from a pure virtual:
class baseClass
{
public:
virtual void myFunction() = 0;
}
class derivedClass : public baseClass
{
public:
virtual void myFunction() override;
}
Is this correct?
And my second question is:
Do I have to specify virtual in the derivedClass for my function even though no class will inherite from my derived class (it will be final)?
Thank you a lot for your answers!
Is this correct?
Yes. Override ensures that the function is virtual and overriding a virtual function from the base class. The program is ill-formed (a compile-time error is generated) if this is not true.
Do I have to specify virtual in the derivedClass for my function even though no class will inherite from my derived class (it will be final)?
No you don't. But even if you leave away the virtual specifier it remains virtual. Because it has been declared virtual in your BaseClass.
If some member function vf is declared as virtual in a class Base, and
some class Derived, which is derived, directly or indirectly, from
Base, has a declaration for member function with the same
name
parameter type list (but not the return type)
cv-qualifiers
ref-qualifiers
Then this function in the class Derived is also virtual (whether or
not the keyword virtual is used in its declaration) and overrides
Base::vf (whether or not the word override is used in its
declaration). Base::vf does not need to be visible (can be declared
private, or inherited using private inheritance) to be overridden.
cppreference.com
Also, please remember that you should define a virtual destructor (can be empty one) in baseClass, in order to guarantee a proper resource deallocation in the derived classes.
Say if I have an interface with virtual methods, but one of the arguments are:
virtual void Delete(ParentClass *parentClass) = 0;
If I later implement this in child class
void Delete(ChildClass *childClass)
{
};
...why doesn't this work as an implementation?
As the function prototype differs (one uses ParentClass and the other ChildClass) they are not the same functions. Instead the one with the ChildClass argument is overloading and not overriding the Delete function.
C++03 Standard: 10.3/2
If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name and same parameter list as Base::vf is declared, then Derived::vf is also virtual an it overrides Base::vf.
Note the text in bold.
An derived class function overides a Base class function only and only if it has the same signature as the Base class function with the exception of Co-Variant return types. Since your function Delete() does not have the same signature in Base Class and Derived class, the derived class function is not overidding the Base class function but what you get is merely Function Hiding.
C++03 Standard: 3.3.7/1:
A name can be hidden by an explicit declaration of that same name in a nested declarative region or derived class.
Because any type that's accepted as an argument for the base-class function, must also be acceptable by an override of that function. This prevents an error such as:
struct BastardClass : ParentClass {} wrong;
Delete(&wrong);
which, if dispatched to the override that expects a ChildClass, would cause it to interpret the object as the wrong type.
(This is known as contravariance - arguments to a function overridden by a more specific type must be no more specific than those being overridden. For similar reasons, return types must be covariant - those specified by a function overridden by a more specific type must be no less specific.)