2

From a comment of mine in a previous question :

Since there can't be instances of abstract classes a pure virtual function can never be selected after overload resolution

The obvious response was :

abstract_class* a = new derived_class; a->pure_virtual_function();

and the best proof of correctness saying :

Dynamic dispatch occurs at runtime, based on whichever object is actually being used at that time. Overload resolution occurs at compile time.


Yet what bothers me is that when resolving explicitly the scope of a class member in our case compilation fails, so it looks like a pure virtual function is never actually selected through overload resolution :

struct B
{
    virtual void copy(B const& rhs) = 0;
};

struct D : B
{
    void copy(B const& rhs)
    {
        D const *pd = dynamic_cast<D const*>(&rhs);
        if (pd) {
            y = pd->y;
        }
    }
    int y;
};

int main()
{
    D d1, d2; 
    d1.y = 2;
    d2.y = 5;

    B *p1(&d1), *p2(&d2); 

    ////////////////////////////////////////////
    (*p1).B::copy(*p2);
    ////////////////////////////////////////////

    return 0;
}

Error message

undefined reference to `B::copy(B const&)'

Demo

What's the case here and if the pure virtual function is actually chosen in overload resolution why can't I "force" the compiler to do the same thing (as the resolution does).

Nikos Athanasiou
  • 29,616
  • 15
  • 87
  • 153
  • A pure virtual function *can* be selected in overload resolution. Could you clarify the last part of your question (in the bold)? – Brian Bi Jul 25 '14 at 17:12
  • @Brian I'm just asking why compilation in the Demo fails : since the `copy` in base class can and is selected why resolving it explicitly fails. – Nikos Athanasiou Jul 25 '14 at 17:14
  • 1
    Explicit qualification with the name of the class disables dynamic dispatch. However this has nothing to do with overload resolution. – Brian Bi Jul 25 '14 at 17:17
  • 1
    It fails because the pure virtual is selected, and there's no definition for it. Note in this example, there is no overload resolution, as there is no overloading. If you added a `copy` method with another signature, there would be overload resolution, but in that case, the pure virtual would still be selected if it matched better, and you'd still get a link failure. Your "comment from a previous question" is just wrong. – Chris Dodd Jul 25 '14 at 17:17
  • 1
    Are you confusing overload with override? – Oktalist Jul 25 '14 at 17:21
  • @ChrisDodd Then how is this [answer](http://stackoverflow.com/a/24958313/2567683) correct - upvoted ? A pure virtual function is never subject to overload resolution (at least not for what matters here) – Nikos Athanasiou Jul 25 '14 at 18:06
  • 1
    @NikosAthanasiou: The answer is correct, the comment is completely wrong and a non-sequitur as well. As Oktalist comments, you seem to be confusing overload resolution and dynamic dispatch, which are completely independent things, though both can happen in one function call. You probably mean "A pure virtual function can never be selected by dynamic dispatch", which is true (modulo undefined behavior with virtual calls in ctors/dtors) – Chris Dodd Jul 25 '14 at 18:14

2 Answers2

2

A pure virtual function can be selected by overload resolution. In most cases it will not be called though. Its final overrider will be called instead, just like with any other virtual function.

struct A
{
  virtual void foo() = 0;
  void foo(int);
};

A* getA();

int main ()
{
   A* a = getA();
   a->foo();
}

struct B : A
{
  void foo() {}
};
A* getA()
{
  return new B;
}

Overload resolution selects A::a() (not B::a()) at compile time, then B::a() is found and called at run-time by the virtual dispatch mechanism. Purity is irrelevant here.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
1

If I understand, you really have two questions. Both are addressed here:

Why does compilation fail?

It fails because you have explicitly attempted to invoke a pure virtual function with no implementation. However, pure virtual functions may be implemented. Here is a single line implementation that will cause your code to successfully compile and run:

void B::copy(B const& rhs) { std::cout << "I am pure and virtuous\n"; }

Is a pure virtual function actually selected in overload resolution?

In a word, no, not in this case. But there is a case in which a pure virtual function must be implemented and will be called (but strictly speaking, not due to overload resolution). That case is when there is a pure virtual destructor of a base class. See this SO question for more detail on why and how.

However, a pure virtual function may be selected in overload resolution. Add this to B

void B::copy(B const& rhs) const { std::cout 
         << "I am pure and virtuous and constant\n"; }

And a corresponding function in D:

void copy(B const& rhs) const { /* do nothing */ }

You will find that overload resolution causes only "I am pure and virtuous" to be printed.

Community
  • 1
  • 1
Edward
  • 6,964
  • 2
  • 29
  • 55