1

I have issues regarding C++ class inheritance. I have a class which has virtual method, for example:

class IFoo {
public:
    virtual int sayFoo() = 0;
};

And I have several implementations, for example:

class Foo1: public IFoo {
public:
    virtual int sayFoo() {
        return 1;
    }
};

class Foo2: public IFoo {
public:
    virtual int sayFoo() {
        return 2;
    }
};

I want to hold IFoo instance inside a dummy container class (like a sort of wrapper) exposing the same interface of IFoo:

class DummyWrapper : public IFoo {
public:
    DummyWrapper(IFoo& foo): foo{foo} {}
    virtual int sayFoo() {
        return foo.sayFoo(); //ALPHA
    }
private:
    IFoo& foo; //BETA
};

Normally everything should work, for example, like this:

IFoo& foo = Foo1{};
DummyWrapper wrapper{foo};

wrapper.sayFoo();

My problem is that foo is actually just a r-value that is removed after its scope goes out, like here:

DummyWrapper generateWrapper() {
    return DummyWrapper{Foo1{}};
}

This lead to read problems in "ALPHA" line. A solution would be to put the r-value on the heap and use pointers to access the foo. Since I'm new to C++ and maybe I'm falling into a XY problem, my question is:

  • is this the only solution? Isn't there a better method to use to solve the issue?
  • I don't think i can replace "BETA" line with IFoo foo since in this way the DummyWrapper will always store the bytes of a IFoo, not of a IFoo implementation. Or maybe I can use the value IFoo foo to call derived virtual methods?

Thanks for any kind reply

Koldar
  • 1,317
  • 15
  • 35
  • 2
    What compiler are you using? `IFoo& foo = Foo1{};` and `return DummyWrapper{Foo1{}};` should fail to compile in a standard compliant compiler. – NathanOliver Jul 02 '19 at 15:13
  • [The Definitive C++ Book Guide and List](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – Jesper Juhl Jul 02 '19 at 15:14
  • g++ 8.3.0. Sorry I've written a MWE but it was not really W. Let me update the code. Sorry – Koldar Jul 02 '19 at 15:17
  • 2
    Are you familiar with `std::unique_ptr`? – Eljay Jul 02 '19 at 15:19
  • Please see: https://stackoverflow.com/questions/40508033/dependency-injection-with-unique-ptr-to-mock if you want to use unique_ptr. – CuriouslyRecurringThoughts Jul 02 '19 at 15:29
  • Frankly, I don't see the point of inheriting DummyWrapper from IFoo. You need to instantiate Foos elsewhere anyway before passing them to a function that takes IFoo as an argument. – macroland Jul 02 '19 at 15:36

2 Answers2

4

is this the only solution? Isn't there a better method to use to solve the issue?

As soon as polymorphism is involved, unfortunately, yes, it is and no, there isn't. But you get an almost equivalent solution to storing IFoo foo, if you use a smart pointer:

// member:
std::unique_ptr<IFoo> foo;

// constructor:
DummyWrapper(std::unique_ptr<IFoo>&& foo): foo(std::move(foo)) { }
// need to accept r-value         ^
// reference: std::unique_ptr is only movable, not copiable!
// for the same reason, you need to preserve the r-value reference
// on assignment to member...

// creation of the wrapper:
return DummyWrapper(std::make_unique<Foo1>(/* arguments for constructor, if there are */));

I don't think i can replace "BETA" line with IFoo foo since in this way the DummyWrapper will always store the bytes of a IFoo, not of a IFoo implementation. Or maybe I can use the value IFoo foo to call derived virtual methods?

Absolutely correct: That's an effect called 'object slicing', at the point you assign a derived object to a base one, all the surplus stuff coming from the derived type gets lost. Pretty common problem (e. g. when people try to store derived objects in a std::vector<Base>).

Aconcagua
  • 24,880
  • 4
  • 34
  • 59
1

Usually we create wrapper when we wants to alter the interface of a class or want to implement additional functionalities, for example
std::queue<T> is wrapper/adapter on std::std::deque<T>(by default)
The std::queue<T> class template acts as a wrapper to the underlying container - only a specific set of functions is provided. The queue pushes the elements on the back of the underlying container and pops them from the front.
In your case i don't think you need DummyWrapper you can use IFoo in place of DummyWrapper and it will do the same job.

Let consider following function,

bool isEven( IFoo& ifoo)  // Not const& because sayFoo() is not const method.
{
  return ( 0 == ( ifoo.sayFoo() % 2)) ;
}

This function will work for all types like Foo1 , Foo2, and no wrapper is required.

Vikas Awadhiya
  • 290
  • 1
  • 8