Как передать объект, обертывающий API, в класс, использующий этот API? - PullRequest
2 голосов
/ 27 мая 2010

Это исправленная / лучше написанная версия вопроса, который я задал ранее сегодня - этот вопрос сейчас удален.

У меня есть проект, в котором я начинаю с Google Mock. Я создал класс, и этот класс вызывает функции в Windows API. Я также создал класс-оболочку с виртуальными функциями, обертывающими Windows API, как описано в Google Mock CheatSheet. Однако я запутался в том, как мне передать оболочку в мой класс, который использует этот объект. Очевидно, что этот объект должен быть полиморфным, поэтому я не могу передать его по значению, заставив меня передать указатель. Это само по себе не является проблемой, но я не понимаю, кто должен владеть указателем на класс, обертывающий API.

Итак ... как мне передать класс-оболочку в реальный класс для облегчения насмешек?

Вот пример того, что я имею в виду:

struct A {
    virtual void SomeMethod(int x, int y)
    {
        ::SomeMethod(x, y);
    };
};

class Client
{
    A * method_;
public:
    Client(A * method = new A) : method_(method) {};
    void DoSomething()
    {
        method_->SomeMethod(42, 34);
    }
};

struct Mock : public A
{
    MOCK_METHOD2(SomeMethod, void(int, int));
};

TEST(MyTest, MyTestWithMock)
{
    Mock * mock = new Mock();
    EXPECT_CALL(*mock, SomeMethod(42, 34)).Times(1);
    Client client(mock); //Should *client* be responsable for deleting mock?
    client.DoSomething();
};

ПРИМЕР 2:

struct A {
    virtual void SomeMethod(int x, int y)
    {
        ::SomeMethod(x, y);
    };
};

class Client
{
    A * method_;
public:
    Client(A * method) : method_(method) {};
    static Client Create()
    {
        static A;
        return Client(&A);
    }
    void DoSomething()
    {
        method_->SomeMethod(42, 34);
    }
};

struct Mock : public A
{
    MOCK_METHOD2(SomeMethod, void(int, int));
};

TEST(MyTest, MyTestWithMock)
{
    Mock  mock;
    EXPECT_CALL(mock, SomeMethod(42, 34)).Times(1);
    Client client(&mock);
    client.DoSomething();
};

Ответы [ 3 ]

2 голосов
/ 27 мая 2010

Всегда есть возможность использования shared_ptr; это определенно решило бы проблему владения.

0 голосов
/ 28 мая 2010

Виртуальные функции - не единственный способ сделать это. Вы также можете использовать шаблоны, которые эффективно обеспечивают полиморфизм времени компиляции.

struct A {
    virtual void SomeMethod(int x, int y)
    {
        ::SomeMethod(x, y);
    };
};

template <class T>
class Client
{
    T method_;
public:
    Client() : method_(method) {};
    static Client Create()
    {
        return Client();
    }
    void DoSomething()
    {
        method.SomeMethod(42, 34);
    }

    T &GetMethod()
    {
        return method_;
    }
};

struct Mock
{
    MOCK_METHOD2(SomeMethod, void(int, int));
};

TEST(MyTest, MyTestWithMock)
{
    Client<Mock> client;
    EXPECT_CALL(client.GetMethod(), SomeMethod(42, 34)).Times(1);
    client.DoSomething();
};
0 голосов
/ 27 мая 2010

Возможны многие схемы владения, но некоторые из них более ремонтопригодны, чем другие. Всякий раз, когда один объект x содержит другой y по ссылке, я спрашиваю:

Кто создает y? Эта партия также должна уничтожить y.

Преимущество этого подхода состоит в том, что он работает так же хорошо, когда один или оба объекта статически размещены, в то время как подходы, в которых передается право собственности, должны либо использовать shared_ptr<>, либо делать предположение о том, было ли y динамически распределено или не. Первый вводит накладные расходы, а второй хрупкий.

Если объект может создать более одной стороны, , как это делает ваш код (он может быть создан вызывающим или конструктором в качестве аргумента по умолчанию), безусловно, самый простой способ - это используйте shared_ptr<>. Но это хорошая идея, чтобы избежать ситуации, когда разные стороны могут создать ресурс, если вы можете - что"стреляет мышью из пистолета слона".

...