Ответ 1
typedef std::queue<int> Q;
Q
является адаптированным контейнером queue
.
typedef Q::container_type C;
C
является базовым контейнером Q
, который является deque<int>
.
C & get (Q &q) {
get
принимает a queue
и возвращает a deque
. Фактически он возвращает deque
, который обертывает queue
: обычными способами это невозможно.
struct hack : private Q {
hack
- это тип, локальный для функции. Он наследует от Q
и имеет только одну статическую функцию-член. От его имени вы можете подозревать, что это взломать. Вы правы.
Нет hack
когда-либо создаётся.
static C & get (Q &q) {
hack::get
имеет ту же подпись, что и сама get
. Фактически мы делегируем всю работу get
этому методу.
return q.*&hack::c;
эта строка должна быть разбита. Я сделаю это в следующих строках:
using mem_ptr_t = C Q::*; // aka typedef C Q::*mem_ptr_t;
mem_ptr_t c_mem_ptr = &hack::c;
C& ret = q.*c_mem_ptr;
return ret;
Первая строка определяет тип указателя-члена для поля типа C
в пределах Q
. Оба способа именования этого типа С++ 11 и С++ 03 являются уродливыми.
Вторая строка получает указатель на поле C
в Q
. Он делает это через отверстие в системе типов С++. &hack::c
логически относится к типу C hack::*
- указателю на элемент типа C
в классе типа hack
. Фактически, поэтому мы можем получить к нему доступ в static
член hack
. Но вопрос C
на самом деле находится в Q
, поэтому фактический тип выражения в С++ - это C Q::*
: указатель на переменную-член Q
.
Вы не можете напрямую получить этот указатель-член внутри hack
- &Q::c
является незаконным, но &hack::c
не является.
Вы можете думать о указателях-членах как "набранные смещения" на другой тип: &hack::c
- это "смещение" C
внутри Q
, а также знание того, что он имеет тип C
. Теперь это не так - это непрозрачное значение, которое сообщает компилятору, как получить C
от Q
, но это помогает думать об этом таким образом (и это может быть реализовано таким образом в простых случаях).
Затем мы используем этот указатель-член вместе с Q&
, чтобы получить C
из Q
. Получение указателя участника ограничено защитой: использование его не является! Способ, которым мы это выполняем, - это оператор .*
, который является оператором разыменования членов, который вы можете передать либо указателями на функции-членами, либо членами справа, и экземплярами класса слева.
instance .* member_ptr
- выражение, которое находит элемент, "указываемый" на member_ptr
в пределах instance
. В исходном коде все было сделано в одной строке:
instance .* &class_name::member_name
поэтому он выглядел как оператор .*&
.
}
};
а затем мы закрываем статический метод и класс hack
и:
return hack::get(q);
}
назовите его. Этот метод дает доступ к protected
состоянию: без него, protected
члены могут быть доступны только в дочерних классах одного и того же экземпляра. Используя это, мы можем получить доступ к protected
членам любого экземпляра, не нарушая ни одного бита стандарта.