Не упустите упаковку проблем. В примере Вы дали все поля, при очевидных смещениях, потому что все находится на 4-байтовых границах, но это будет не всегда иметь место. Visual C++ упаковывает на 8-байтовых границах по умолчанию.
Хорошо, поскольку вы сказали, что это всего лишь тестовый код, я собираюсь предложить что-то серьезное хакерское, но оно сработает:
struct tc : protected Foo
{
tc(Foo *foo, Data& data)
{
((tc*)foo)->DoSomething(data);
}
};
Blah blah;
tc t(&blah.foo, blah.data);
Есть способ, который полностью разрешен Стандартом.
//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);
Прочтите статью Скрытые возможности C ++ для объяснения.
Вы можете написать макрос для вашего удобства (круглые скобки здесь, чтобы вы могли использовать этот макрос также для типов, которые имеют запятую, например vector
):
#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);
С одной стороны, не делайте этого .
С другой стороны, вот игра:
#define protected public
#include "foo.h"
#undef protected
8 -)
А если серьезно, почему DoSomething ()
защищен? Наверное, потому, что вызов из внешнего кода может что-то сломать. В этом случае не следует вызывать его из тестов.
Я сделал
class Foo
{
protected:
void DoSomething(Data data);
public:
#ifdef TEST
void testDoSomething(Data data);
#endif
}
Затем скомпилируйте ваши модульные тесты с помощью g ++ -D TEST.
Вместо того, чтобы определять частный
в открытый
, подумайте о при определении дружбы или еще лучше подумайте, действительно ли эта функция должен принадлежать к этому классу, возможно, было бы достаточно иметь что-то в именованном / безымянном пространстве имен в cpp, а затем объявить в тестовом проекте.
В любом случае, проверьте эту ссылку , возможно, ваша среда тестирования предоставит аналогичные функции.
РЕДАКТИРОВАТЬ: Вы рассматривали возможность наследования тестового класса от реального класса?
Используйте оболочку следующим образом:
// 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's no problem!
}
Вы можете использовать наследование с функциями пересылки:
class Foo
{
protected:
void DoSomething(Data data);
}
class test_Foo : public Foo
{
public:
void testDoSomething(Data data)
{
DoSomething(data);
}
}
Если это строго тестовый код, вы можете сделать ...
#define protected public
#include "Foo.h"
// test code
#undef protected