DBedrenko
DBedrenko

Reputation: 5029

How to extend class from library when there's an interface involved?

I have a library that provides class Foo. I extend Foo with some of my own member functions in class FooExtended. In order to use FooExtended in my unit tests I must make it mockable, therefore I create an interface IFoo and this is the type I use all throughout my codebase. Then I created two implementations of the interface:

Problem: The problem is with the FooWrapper. I don't know how to utilise the factory Lib::create_foo() to create Foo as the library wants, but also have the my_added_function() which I added in FooExtended. The dynamic_cast fails.

#include <iostream>
#include <memory>
#include <cassert>
using namespace std;

// What's in this namespace is in a 3rd party lib that I cannot change.
namespace Lib {

class Foo {
  public:
    virtual ~Foo() {};

    int lib_func() {
      return 42;
    }
};

// Factory
Foo* create_foo() {
  return new Foo();
}
} // namespace Lib


/** I want to extend the 3rd party class, and only use
this extended class in my project */
class FooExtended : public Lib::Foo {
  public:
    float my_added_func() {
      return 1.0;
    }
};

/** Interface for class Foo, created so that a mock
implementation of `FooExtended` can be created for unit tests. */
class IFoo {
  public:
    virtual int lib_func() = 0;
    virtual float my_added_func() = 0;
};

/** Mock implemenation of IFoo for unit-tests. */
class FooMock : public IFoo() {
 // Blah blah
}

/** Non-mock implementation of IFoo. Just a wrapper for the class with the
actual implementation, i.e. FooExtended. */ 
class FooWrapper : public IFoo {
  public:
    int lib_func() override {
      assert(mFooExt);  // This fails because dynamic_cast failed.
      return mFooExt->lib_func();
    };

    float my_added_func() override {
      assert(mFooExt);  // This fails because dynamic_cast fails.
      return mFooExt->my_added_func();
    }

  private:
    unique_ptr<FooExtended> mFooExt {
      unique_ptr<FooExtended>(
        // This dynamic_cast fails.
        dynamic_cast<FooExtended*>(Lib::create_foo()))
    };
};

int main() {
  unique_ptr<IFoo> foo {  unique_ptr<IFoo>(new FooWrapper()) };
  assert(foo != nullptr);
  cout << "Starting...";
  // Exits the program because of the assert inside.
  cout << foo->lib_func() << "\n";
  cout << foo->my_added_func();
}

Upvotes: 0

Views: 118

Answers (1)

Yola
Yola

Reputation: 19043

If you are not afraid to pay the price for calling virtual functions, you can create a wrapper for Foo and use it in your program:

class IFoo {
  public:
    virtual ~Foo() {};
    virtual int lib_func() = 0;
};

class MyFoo : public IFoo {
  int lib_func() override { _foo.lib_func(); }
private:
  std::unique_ptr<Foo> _foo = create_foo(); // pseudocode
};

Now you can create mock and use it for IFoo.

Upvotes: 1

Related Questions