Переопределение ссылок в Cpp для указания на ложную реализацию

#c #linker #mocking #overriding

#c #компоновщик #издевательство #переопределение

Вопрос:

Мне нужно смоделировать некоторые классы с помощью GoogleMock и изменить реализацию базового класса так, чтобы он фактически создавал экземпляр этого издевательского. Базовый класс генерируется автоматически вместе с некоторыми другими классами, которые не нужно издеваться, и все они добавляются в одну библиотеку.

Классы, которые необходимо издеваться, создаются с помощью фабрики, через которую я намерен вернуть дочерний класс. Могу ли я «повторно связать» с этой новой библиотекой, которая имеет реализацию для уже связанного базового класса?

Чего я надеюсь достичь, так это получить экземпляр базового класса из тестируемого модуля, а затем преобразовать его в издевательский.

Пример кода:

 Original.hpp    
class Base
{
private:
    Base();

public:
    virtual ~Base();
    static std::shared_ptr<Base> createInstance();
}



Original.cpp
#include "Original.hpp"
...
std::shared_ptr<Base> Base::createInstance()
{
    return std::shared_ptr<Base>(new Base());
}
...


Modified.hpp
class Derived : public Base
.....


Modified.cpp    
#include "Original.hpp"
#include "Modified.hpp"
...
std::shared_ptr<Base> Base::createInstance()
{
    return std::shared_ptr<Base>((Base*) new Derived());
}
  

Поэтому я хочу, чтобы всякий раз, когда базовый класс создается через CreateInstance в любом месте проекта, CreateInstance, определенный в Modified.cpp вместо этого будет использоваться для возврата производного класса.

Комментарии:

1. Вопрос мне неясен. Покажите код вашей системы, фабрики и интерфейса для класса, который вы хотите издеваться.

2. @Ptaq666 я добавил несколько примеров кода. К вашему сведению, это для издевательства над бережливыми клиентами, но я не смог добавить исходный код, но пример должен быть понятнее

Ответ №1:

Хорошо, я думаю, я более или менее понимаю. Если библиотека уже скомпилирована, вы не можете изменить реализацию этого статического фабричного метода. Если вы предоставите свою собственную реализацию и попытаетесь связать ее с существующей библиотекой, у вас будет несколько определений (не допускается). Что вы можете сделать, так это добавить в ваше приложение один слой, который будет отвечать за Base создание этих объектов:

 // existing implementation
class Base {
public:
    virtual ~Base();
    static std::shared_ptr<Base> createInstance() {
        return std::shared_ptr<Base>(new Base());
    }

private:
    Base() {};
};

// new layer, part of your production code
class IYourFactory {
public:
    virtual ~IYourFactory() = default;
    virtual std::shared_ptr<Base> createInstance() = 0;
};

// new layer, part of your production code
class ProductionFactory: public IYourFactory {
public:
    ~ProductionFactory() override = default;
    std::shared_ptr<Base> createInstance() override {
        return Base::createInstance();
    }
};

// testing code, you can use GMock to create this class
class MockBase: public Base {
public:
    // it's a hack for Base private default constructor
    MockBase(): Base(*Base::createInstance()) {}
    ~MockBase() override = default;
};

// testing code, you can use GMock to create this class
class MockFactory: public IYourFactory {
    ~MockFactory() override = default;
    std::shared_ptr<Base> createInstance() override {
        return std::make_shared<MockBase>();
    }
};

class YourSystem {
public:
    YourSystem(std::shared_ptr<IYourFactory> factory): factory_(factory) {}
    bool doSomeThings() {
        auto basePtr = factory_->createInstance();
        return true;
    }
private:
    std::shared_ptr<IYourFactory> factory_;
};
  

Конечно, это будет работать только в том случае, если Base у класса есть некоторые виртуальные функции, которые вы можете override использовать в своем MockBase . Если нет, то это не тот путь (вам нужно будет создать свой собственный интерфейс для методов, предлагаемых Base ).

Точное решение зависит от того, как вы используете его в своей системе и к какому интерфейсу Base .