В реальности если требуется обойти ограничение доступа, то это может быть сделано например так:
/*
* Класс Cls определен точно таким образом:
*
* struct Cls {
* Cls(char c, double d, int i);
* private:
* char c;
* double d;
* int i;
* };
*
*/
namespace {
// Cls_Double - точная копия Cls в смысле расположения данных.
// Важный момент - данные в Cls НЕ скрыты, но видимы с ограничением доступа (что разные вещи)
// Это позволяет делать дубликат класса всегда
struct Cls_Double {
char c;
double d;
int i;
};
}
// Эта функция должна предоставить доступ к полю c объекта cls.
// Обратите внимание, что возвращается ссылка на char, т. е.
// доступ предоставляется на чтение и запись.
char &get_c(Cls &cls) {
return reinterpret_cast<Cls_Double&>(cls).c;
}
// Эта функция должна предоставить доступ к полю d объекта cls.
// Обратите внимание, что возвращается ссылка на double, т. е.
// доступ предоставляется на чтение и запись.
double &get_d(Cls &cls) {
return reinterpret_cast<Cls_Double&>(cls).d;
}
// Эта функция должна предоставить доступ к полю i объекта cls.
// Обратите внимание, что возвращается ссылка на int, т. е.
// доступ предоставляется на чтение и запись.
int &get_i(Cls &cls) {
return reinterpret_cast<Cls_Double&>(cls).i;
}
Пара замечаний:
1) приведение через арифметику указателей и reinterpret_cast оба нарушают strict aliasing, поэтому без разницы что использовать
2) если есть внутренние терзания, то для хотя бы относительного душевного спокойствия можно использовать двойной static_cast вместо reinterpret_cast, тоже нарушит strict aliasing, так что всё равно
3) Возможно, если это академическое задание, ожидается ручное вычисление через арифметику указателей, в стиле
return *(char *)((std::uint8_t*)&cls);
return *(double *)((std::uint8_t*)&cls + sizeof(char));
return *(int *)((std::uint8_t*)&cls + sizeof(char) + sizeof(double));
Но никогда так не делайте в проде, потому как можно заиметь кучу проблем с поддежкой таких вычислений, в том числе если вдруг Cls на самом деле будет наследоваться от класса с vptr, который при этом снаружи может измениться. Тогда Cls_Double нужно идентично наследовать, а компилятор обеспечит корректные адресации.
Ещё один вариант - вопросы упаковки данных, который тоже компилятор может бесплатно решить за нас.