TL; DR
Является ли этот вызов функции / преобразования законным, соответствующим стандарту кодом C ++ 11/14?
Если нет, то был бы, если бы не было виртуальных функций (если std::is_standard_layout<Module>
стало правдой)?
( NB: работает на каждом компиляторе, который я до сих пор тестировал ... )
class Module
{
protected:
virtual float protectedVirtualFunction(float f) { return f*f*f; }
float protectedFunction(float f) { return f*f; }
};
class ModuleTester : public Module // consists of ONLY aliases
{
public:
using Module::protectedFunction;
using Module::protectedVirtualFunction;
};
int main()
{
Module module; //assume this is a pre-existing instance
// Is this legal?
ModuleTester* testerMask = static_cast<ModuleTester*>(&module);
testerMask->protectedFunction(4.4f);
testerMask->protectedVirtualFunction(4.4f);
}
Дополнительная информация
Обычно я стремлюсь протестировать классы publi c API только при написании UnitTests. В некоторых случаях - например, когда вы имеете дело с унаследованным кодом, который вы не можете изменить - просто удобнее получать доступ к закрытым членам.
Итак, если мы не можем изменить дизайн (DI, развязка ...) Я вижу следующие решения:
- Сделать приватных участников публичными c (скомпрометировать всю инкапсуляцию)
- Старый трюк:
#define private public
в тестовом контексте - Шаблон "Tester" (как в примере кода)
Стандартный способ использования этого шаблона "Tester" будет таким, и это должно быть допустимо:
ModuleTester tester;
tester.protectedFunction(4.4f);
tester.protectedVirtualFunction(4.4f);
Тем не менее, иногда у меня есть существующий экземпляр, и было бы здорово, если бы я мог просто применить эту «маску тестера» поверх него, чтобы получить доступ.
Я предполагаю, что как только я выполню виртуальные функции и остановлюсь Будучи «стандартным макетом», строго говоря, может быть «неопределенное поведение». Однако , если я определяю псевдонимы только в производном классе, я не вижу, как это может go быть неправильным, если я использую один и тот же компилятор для Module и ModuleTester.
РЕДАКТИРОВАТЬ: Я нашел похожий метод, который не использует явное приведение указателя ({ ссылка }). Это работает, возможно, менее читабельно и, вероятно, не меняет статус «легальности».
(module.*&ModuleTester::protectedVirtualFunction)(4.4f);
Другие вопросы SO, которые дают хорошие результаты: reinterpret_cast от объекта к первому члену , Как выполнить модульное тестирование защищенного метода в C ++?