zeroexpguy
zeroexpguy

Reputation: 1

C++ Override a pure virtual method with reference to an abstract class as a parameter by method that takes non abstract sub-class as parameter

I have the following code:

struct A{ f()=0; };
struct Aa : A{ f(){} };
struct B{
   void foo(A&)=0;
};
struct Bb : B{
   void foo(Aa&);
};

Right now I can't create a Bb class instance since I didn't override foo from class B with demanded parameter. How can I make it work?

Upvotes: 0

Views: 249

Answers (3)

ChrisMM
ChrisMM

Reputation: 10021

From [class.virtual]/2 (C++17 N4713)

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 (11.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 overrides112 Base::vf. For convenience we say that any virtual function overrides itself.

Now, in this case, the note 112 is actually important.

  1. A function with the same name but a different parameter list (Clause 16) as a virtual function is not necessarily virtual and does not override.

In your case, you have the same name, but different parameter lists; thus you are not overriding, and are instead overloading.

Upvotes: 0

eerorika
eerorika

Reputation: 238311

How can I make it work?

You cannot make it work without changing the premises. void(Aa&) cannot override void(A&). The parameter types must match.


Generally in object oriented programming, an overriding function cannot never have more strict parameter type.

Some object oriented languages support contravariant parameters in derived functions, which allows overriding with a function that accepts a more general parameter. For example, member function accepting `A&` could override a member function accepting `Aa&` (i.e. other way around compared to your attempt). However, C++ does not support contravariant parameters. The parameter types must match exactly.

Perhaps dynamic polymorphism isn't what you need. Perhaps you need static polymorphism (templates):

template<
    std::derived_from<A> TA
    // or if you don't have concepts:
    // class TA
>
struct B{
   void foo(TA&) {
       // use somehow
   }
};

using Bb = B<Aa>;

Upvotes: 1

Marek R
Marek R

Reputation: 37647

lets assume it is possible/compiles and add extra class:

struct A{ void f()=0; };

struct Aa : A{ int x; void f(){} };
struct Ab : A{ double x; void f(){} };

struct B{
   void foo(A&)=0;
};
struct Bb : B{
   void foo(Aa&);
};

Now how this should work?

std::unique_ptr<B> p = std::make_unique<Bb>;
Ab a;
p->foo(a); // ???

how overridden function Bb::foo should handle this scenario? It expected something of type Aa, but got Ab which is not child of Aa. From B::foo perspective this call is perfectly fine since Ab is child of A.

This should give you a hint why compiler didn't do what you have expected.

Upvotes: 1

Related Questions