2

I was wondering how can I correctly override the function of derived class with a derived function parameter?
e.g.

struct X;
struct Y:X
struct Z:X

class A {
    public:
      int f(int, X);    
};

class B : A{
    public:
       int f(int, Y);
};

class C : A{
    public:
       int f(int, Z);
};
4
  • if it were possible, consider passing an X to an A whose dynamic type is B, what should the call resolve to ? Commented Oct 5, 2017 at 16:12
  • You cannot as it would be wrong. Contra-variance is not supported, only co-variance on return type is supported. Commented Oct 5, 2017 at 16:53
  • @Jarod42 but only covariance on return of reference and pointer and base derived relationships, which is a subst of covariance. Commented Oct 5, 2017 at 16:57
  • wiKon, your code has no overriding as overriding only occurs with virtual methods, beyond your request for contra variance. It is really really hard to read someone's mind when they cannot express what they want in code. Always try to create a valid compiling example, then do minimal editing of your code to describe what you want to work. Commented Oct 5, 2017 at 16:59

1 Answer 1

2

The idea that you can substitude derived/base classes for return values/parameters is known as covariant return types and contravariant arguments.

In C++, reference and pointer return types of virtual pointers have covariant overloading in derived types; you can return a more restricted (pointer or reference) to the base return type in derived types.

Contravariance of arguments, where you replace a Derived* argument in base interface with a Base* argument in derived, isn't supported in C++, but you can emulate it with both overloading and overriding.

struct BaseValue {};
struct DerivedValue:BaseValue {};
struct MoreDerivedValue:DerivedValue {};

struct BaseInterface {
  virtual void contra_example( DerivedValue* ptr ) = 0;
  virtual DerivedValue* co_example() = 0;
  virtual ~BaseInterface() {}
};

struct DerivedInterface:BaseInterface {
  virtual void contra_example( DerivedValue* ptr ) override final {
    contra_example( static_cast<Value*>( ptr ) );
  }
  void contra_example( Value* ptr ) override = 0;

  virtual MoreDerivedValue* co_example() override = 0;
};

co_example is an example of covariance in return type. The compiler does this automatically for us in the case where we are just doing covariance based off of pointers and references into a type heirarchy.

contra_example is an example of contravariance of argument type. ptr, the argument to contra_example, in the case of DerivedInterface can be any Value*. The base interface requires that it be a DerivedValue*.

We can override the base contra_example, then forward to our internal "more accepting" implementation which is an overload in DerivedInterface.

The derived interface is more permissive than the base interface, and it provides guarantees at least as good, or better than the original does.


Now lets get back to your question. First, no, the compiler won't do it for you.

Second, your logic is flawed. Using the Liskov substitution principle, your B must be able to substitude for an A.

But your B has a more restricted contract on its argument to f than A does. A requires an X argument, B requires that it be not only an X but a Y as well.

struct X1{};
struct X2{};
struct Y:X1,X2{};

struct A {
  virtual void foo( Y* ) = 0;
  virtual ~A() {}
}
struct B1:A {
  virtual void foo( Y* ptr ) final override { foo( static_cast<X1*>(ptr) ); }
  virtual void foo( X1* ) = 0;
}
struct B2:A {
  virtual void foo( Y* ptr ) final override { foo( static_cast<X2*>(ptr) ); }
  virtual void foo( X2* ) = 0;
}

this corresponds to your example. The derived interfaces are more permissive of their (implicitly input) argument.

You can jump through hoops to have out-only arguments that support covariance, or simply return them.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.