0

I have this structure:

class IA
{
    virtual void foo() = 0;
};

class IB
{
    virtual IA bar() = 0;
};

So far I made the inherited versions of these two interfaces but I have difficulties with how to make concrete overriding of the IA IB::bar() method?

I mean if I have a class A inheriting from IA then how to declare the A bar() method in a class B which inherits of IB? Or perhaps I should make a third class for this matter?

Thanks!

Edit: Now I have noticed that the bar() definition in IB is as follows:

virtual IA& bar() = 0;

Perhaps this will help?

winsett
  • 71
  • 7
  • `virtual IA bar()` cannot be implemented, because you cannot create an instance of `IA`. Did you intend to have it return a pointer or reference to `IA` that points to an object of a class derived from `IA`? – Miles Budnek Mar 26 '21 at 20:53
  • @MilesBudnek unfortunately I cannot touch this structure. I just have to inherit from it. – winsett Mar 26 '21 at 21:04
  • @winsett Like Miles said, `IA IB::bar()` cannot be implemented. `IB::bar()` **must** return either an `IA*` pointer or `IA&` reference instead. Even if `IA` weren't abstract, returning an `IA` by value without a pointer/reference would still not work, as `bar()` would [slice](https://stackoverflow.com/questions/274626/what-is-object-slicing) any derived object it tried to return. – Remy Lebeau Mar 26 '21 at 21:10
  • @RemyLebeau yes, you are right - I had a second look on it and its return type is of ```IA&```. I had missed this at my first glance and this somehow confused me. – winsett Mar 26 '21 at 21:16

2 Answers2

3

Welcome to the wonderful world of subtle differences between Java and C++. If you come from a Java background, a value of type IA is of type IA or any subclass thereof. But in C++, a value of type IA is a concrete instance of IA, nothing more and nothing less. And your IA is abstract, hence there are no concrete instances, so as written, your IB::bar is unsatisfiable. There's no well-defined function that can ever have that type.

Instead, when you want to do Java-style inheritance-based polymorphism (which is often not the answer in C++, but we'll assume it's the right tool for the job for the moment), you need a layer of indirection. That can be a raw pointer (IA*), a reference (IA&), or a smart pointer (unique_ptr<IA>).

By convention, we return a smart pointer if the data is intended to be owned by the caller (i.e. the caller is responsible for freeing it when done), a reference if it's owned by someone else, and a raw pointer if we want our fellow programmers to suffer. I'll assume you intend that the caller own the IA value, so we'll use a smart pointer.

Your interfaces can be written

#include <memory>

class IA {
  virtual void foo() = 0;
};

class IB {
    virtual std::unique_ptr<IA> bar() = 0;
};

And we can concretely implement them as follows

class A : public IA {
  virtual void foo() {}
};

class B : public IB {
  virtual std::unique_ptr<IA> bar() {
    return std::make_unique<A>();
  }
};
Silvio Mayolo
  • 62,821
  • 6
  • 74
  • 116
  • Objects in Java are passed around by pointer, not by value. Even if the Java syntax doesn't suggest pointers are being used, they are. – Remy Lebeau Mar 26 '21 at 21:13
  • @SilvioMayolo I have noticed I missed that the return type of ```boo()``` is reference of ```IA```. Your answer forced me to take a second look as at first glance I have missed this detail. Thanks again! – winsett Mar 26 '21 at 21:13
1
class IA
{
public:
    virtual void foo() = 0;
};

class IB
{
public:
    virtual IA& bar() = 0;
};
class A : public IA
{
public:
    void foo() override;
};

class B : public IB
{
private:
    A m_a;
public:
    IA& bar() override;
};
void A::foo() {
    ...
}

IA& B::bar() {
    return m_a;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770