3

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!

Community
  • 1
  • 1
WaldB
  • 1,261
  • 7
  • 14
  • I think the real question is, "Why am I allowed to define a pure-virtual function?" – Mysticial May 09 '14 at 18:55
  • I seem to miss something. You make a fully qualified function call (which is nothing special) from a no-special member function. What makes you even think that this could possibly not work or that this should need a justification to work? The `D` object is fully constructed at the time of the call, but even if this was inside the constructor, it would still very clearly be a `B` object, so either way it's certainly legal to call a member of `B`. – Damon May 09 '14 at 18:57
  • @Damon `You make a fully qualified function call` That may seem trivial for you. But I've never seen this before, specially in a virtual function. – WaldB May 09 '14 at 18:59
  • 1
    10.4/2 "[... ] A pure virtual function need be defined only if called with, or as if with (12.4), the *qualified-id* syntax (5.1). [...]". Now follow the links from there... – jrok May 09 '14 at 19:01
  • 1
    @user1162978: Don't be afraid, this is a perfectly normal thing. Virtual or not does not matter. If you only call `foo()` then you are calling whatever `*this` refers to (in a member that belongs to `D`, that's of course `D::foo`, so the function would call itself). Calling `D::foo` would be the exact same thing, only more to type. Now _this is not what you want_, you want the function in `B`, and by writing `B::` you tell the compiler that. It does not matter whether the function is virtual or not (this is a statically dispatched call, not a virtual one!). – Damon May 09 '14 at 19:05
  • @user1162978: your edit is useless. If some people thought it was a dup, it means your question isn't clear enough. So explain it a bit better rather than just saying "it's not that!". (I do agree that the dup isn't good.) – Mat May 09 '14 at 19:17
  • @mysticial actually, the real question is "why can I usually not define a pure-virtual function?" – Yakk - Adam Nevraumont May 09 '14 at 19:57
  • It is actually fairly common to go `B::foo();` within `D::foo()`. Since D is supposed to build on B, often you want the action of `D::foo()` to do `B::foo()`'s actions and then do some extra things. – M.M May 09 '14 at 23:22

2 Answers2

3

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".

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
0

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().

R Sahu
  • 204,454
  • 14
  • 159
  • 270