Question

I'm using the call B::foo() in the definition of the member function D::foo() in the derived class D. It works, but since I've never used this before, I'd like to know a quote from the Standard supporting this construction.

#include <iostream>
class B {
public:
    virtual void foo() = 0;
};

inline void B::foo() { std::cout << "B::foo()" << '\n'; } 

class D : public B {
public:
    void foo() { std::cout << "D::"; B::foo(); }
};

int main() {
  D d;
  d.foo();
}

Edit

This question has nothing whatsoever to do with my question!

Was it helpful?

Solution

Calling a function using the B::foo syntax is perfectly legal in general.

The exception detailed in the C++ standard is that when you have a pure virtual function that you do not call via B::foo, you do not have to define it. 10.4/2: (via @jrok)

[...] A pure virtual function need be defined only if called with, or as with (12.4), the qualified-id syntax (5.1). [...]

The B::foo() syntax is an example of calling foo with the qualified-id syntax. Note that this is distinct from the (this->*&B::foo)() syntax, which does a virtual table lookup.

A pure virtual function is not "setting the function to a null pointer" despite the =0 syntax. Rather, it is marking it as "in order to instantiate this class, I require that a descendent override this method". As it happens, compilers tend to set the virtual function table of a pure virtual function to point to an error handler that sets up an error (at least in debugging) that you made a pure virtual function call, because that is pretty cheap to set up, and it diagnoses calls to said method during construction/destruction before or after the descendent class instance lifetimes.

You can mark a method as pure virtual even if your parent defined it. This just indicates that your child implementations have to override it again. You can mark a method as pure virtual even if you define it. Again, this just tells your child implementations that they have to override it.

As a bonus answer, why would we do this? Sometimes you want to implement a partial implementation in a base class, to be invoked before or after the child implementation. Other times you want a default implementation. In each case, you want some code to be coupled to this method, and you want to force children to override it.

You could implement the before/after/default in a distinct non-virtual method called before_foo or default_foo, or you could just do this.

At other times, in a deep hierarchy the implementation of some method inherited from above may no longer be valid. So you'll =0 it to indicate that children have to override it again.

Both cases are extreme corner cases.

The final spot I've used this technique is when I wanted to do away with the (bar->*&Bar::foo)() annoyance. I override Bar::foo to do (this->*&Bar::foo)(), allowing bar->Bar::foo() to do the right thing "magically".

OTHER TIPS

I haven't read the standard with enough care to be able to identify where it says that the call you are making is legal. However, making functions using fully qualified name must work. Using a implicitly qualified name is only a shortcut.

In your main function, when you call:

d.foo();

it is equivalent to

d.D::foo();

The first is implicitly qualified to 'D::foo'. The second is explicitly qualified to D:foo. You can also call

 d.B::foo();

This will bypass the D::foo() and go directly to B::foo().

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