Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top