Доступ к защищенным функциям-членам из тестового кода в С++

Я пытаюсь думать о лучшем способе доступа к защищенной функции-члену из некоторого тестового кода на С++, вот моя проблема:

//in Foo.h 
Class Foo
{
protected:
    void DoSomething(Data data);
}

//in Blah.h
Class Blah
{
public:
    Foo foo;
    Data data; 
};

//in test code...
Blah blah;
blah.foo.DoSomething(blah.data); // Here my problem!

Некоторые возможные решения:

Сделайте класс тестового кода другом Foo, но это загрязняет Foo с помощью тестового кода Сделать DoSomething общедоступной функцией Я посмотрел на создание тестовой оболочки для Foo, как указано в этом сообщении, однако это не сработает, поскольку Blah содержит экземпляр Foo.

Все советы/понимание/мнения приветствуются!

Спасибо

Ответ 1

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

struct tc : protected Foo
{
    tc(Foo *foo, Data& data)
    {
        ((tc*)foo)->DoSomething(data);
    }
};

Blah blah;
tc t(&blah.foo, blah.data);

Ответ 2

Существует способ, который полностью разрешен Стандартом.

//in Foo.h 
class Foo
{
protected:
    void DoSomething(Data data);
};

//in Blah.h
class Blah
{
public:
    Foo foo;
    Data data; 
};

//in test code...
struct FooExposer : Foo {
  using Foo::DoSomething;
};

Blah blah;
(blah.foo.*&FooExposer::DoSomething)(blah.data);

Прочтите описание Скрытые функции С++ для объяснения.


Вы можете написать макрос для вашего удобства (скобки там, чтобы вы могли использовать этот макрос также для типов с запятой, например vector<pair<A, B>>):

#define ACCESS(A, M, N) struct N : get_a1<void A>::type { using get_a1<void A>::type::M; }

template<typename T> struct get_a1;
template<typename R, typename A1> struct get_a1<R(A1)> { typedef A1 type; };

Теперь вопрос становится

ACCESS((Foo), DoSomething, GetDoSomething);
Blah blah;
(blah.foo.*&GetDoSomething::DoSomething)(blah.data);

Ответ 3

С одной стороны, не делают этого.

С другой стороны, здесь азартная игра:

#define protected public
#include "foo.h"
#undef protected

8 -)

Но серьезно, почему защита DoSomething() защищена? Вероятно, потому что вызов его из внешнего кода может что-то сломать. В этом случае вы не должны вызывать его из своих тестов.

Ответ 4

Я сделал

class Foo
{
protected:
    void DoSomething(Data data);
public:
    #ifdef TEST
    void testDoSomething(Data data);
    #endif
}

Затем скомпилируйте свои модульные тесты с помощью g++ -D TEST.

Ответ 5

Вместо ifdefing private to public, рассмотрите ifdefing дружбу или еще лучше подумайте, действительно ли эта функция должна принадлежать этому классу, возможно, было бы достаточно иметь что-то в названии /unnamed namespace в cpp, а затем объявлено в тестовом проекте.

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

РЕДАКТИРОВАТЬ: Вы считали наследование своего тестового класса из своего реального класса?

Ответ 6

Вы можете использовать наследование с функциями пересылки:

class Foo
{
protected:
    void DoSomething(Data data);
}

class test_Foo : public Foo
{
public:
    void testDoSomething(Data data)
    {
        DoSomething(data);
    }
}

Ответ 7

Используйте обертку следующим образом:

// Foo.h unchanged

// Blah.h unchanged

// test code
class FooTest : public Foo { friend void test(); }; // make friends

void test()
{
    Blah blah;
    static_cast<FooTest*>(&blah.foo)->DoSomething(blah.data); // Here no problem!    
}

Ответ 8

Если это строго тестовый код, вы можете сделать...

#define protected public
#include "Foo.h"

// test code

#undef protected