Почему я могу получить доступ к закрытым переменным в конструкторе копирования?
Я узнал, что никогда не смогу получить доступ к закрытой переменной, только с помощью функции get в классе. Но тогда почему я могу получить к нему доступ в конструкторе копирования?
Пример:
Field::Field(const Field& f)
{
pFirst = new T[f.capacity()];
pLast = pFirst + (f.pLast - f.pFirst);
pEnd = pFirst + (f.pEnd - f.pFirst);
std::copy(f.pFirst, f.pLast, pFirst);
}
Моя декларация:
private:
T *pFirst,*pLast,*pEnd;
6 ответов
ИМХО, существующие ответы плохо справляются с объяснением "почему" этого - слишком много внимания уделяют повторению того, какое поведение допустимо. "Модификаторы доступа работают на уровне класса, а не на уровне объекта". - Да, но почему?
Общая концепция здесь заключается в том, что программист (ы), разрабатывающий, пишущий и поддерживающий класс, должен (как) должен понимать желаемую инкапсуляцию ОО и уполномочен координировать ее реализацию. Итак, если вы пишете class X
Вы кодируете не только как человек X x
Объект может использоваться кодом с доступом к нему, а также как:
- производные классы могут взаимодействовать с ним (через необязательные чисто виртуальные функции и / или защищенный доступ), и
- отчетливый
X
объекты взаимодействуют, чтобы обеспечить намеченное поведение, соблюдая постусловия и инварианты из вашего дизайна.
Это не просто конструктор копирования - многие операции могут включать два или более экземпляров вашего класса: если вы сравниваете, добавляете / умножаете / делите, копируете, клонируете, присваиваете и т. Д., То это часто бывает либо просто должен иметь доступ к частным и / или защищенным данным в другом объекте, либо хотите, чтобы он позволял более простую, быструю или в целом лучшую реализацию функции.
В частности, эти операции могут использовать привилегированный доступ для таких вещей, как:
- (конструкторы копирования) используют закрытый член объекта "rhs" (правая сторона) в списке инициализатора, так что переменная-член сама создается копией, а не конструкцией по умолчанию (если даже допустимой), а затем присваивается тоже (опять же, если законно)
- обмениваться ресурсами - дескрипторы файлов, сегменты разделяемой памяти,
shared_ptr
s для справочных данных и т. д. - взять на себя ответственность за вещи, например
auto_ptr<>
"перемещает" право собственности на строящийся объект - копировать частные элементы "кэша", калибровки или состояния, необходимые для создания нового объекта в оптимально пригодном для использования состоянии без необходимости его регенерации с нуля
- информация о копировании / доступе к диагностике / трассировке, хранящаяся в копируемом объекте, которая иначе не доступна через общедоступные API, но может использоваться некоторым более поздним объектом исключения или журналированием (например, что-то о времени / обстоятельствах, когда "оригинальный" экземпляр не создан был построен)
- выполнить более эффективное копирование некоторых данных: например, объекты могут иметь, например,
unordered_map
член, но публично разоблачитьbegin()
а такжеend()
итераторы - с прямым доступом кsize()
вы могли быreserve
емкость для более быстрого копирования; еще хуже, если они только выставляютat()
а такжеinsert()
и иначеthrow
.... - копировать ссылки обратно в родительские / координационные / управляющие объекты, которые могут быть неизвестны или доступны только для записи для клиентского кода
Модификаторы доступа работают на уровне класса, а не на уровне объекта.
Таким образом, два объекта одного класса могут обращаться друг к другу к частным данным.
Зачем:
В первую очередь за счет эффективности. Было бы немалым накладным расходом времени выполнения, чтобы проверить, this == other
каждый раз, когда вы получаете доступ other.x
что бы вы сделали, если бы модификаторы доступа работали на уровне объекта.
Это также отчасти семантически логично, если вы думаете об этом с точки зрения области видимости: "Какую большую часть кода мне нужно учитывать при изменении частной переменной?" - Вы должны помнить код всего класса, и это ортогонально тому, какие объекты существуют во время выполнения.
И это невероятно удобно при написании конструкторов копирования и операторов присваивания.
Вы можете получить доступ к закрытым членам класса из класса, даже из другого экземпляра.
Чтобы понять ответ, я хотел бы напомнить вам несколько понятий.
- Независимо от того, сколько объектов вы создаете, для этого класса в памяти есть только одна копия одной функции. Это означает, что функции создаются только один раз. Однако переменные являются отдельными для каждого экземпляра класса.
this
указатель передается каждой функции при вызове.
Теперь это из-за this
указатель, функция может найти переменные этого конкретного экземпляра. независимо от того, является ли это частным публичным. к ней можно получить доступ внутри этой функции. Теперь, если мы передадим указатель на другой объект того же класса. используя этот второй указатель, мы сможем получить доступ к закрытым членам.
Надеюсь, что это ответ на ваш вопрос.
Конструктор копирования является функцией-членом класса и, как таковой, имеет доступ к членам-данным класса, даже если они объявлены как частные.
почему человек, который сделал этот компилятор, допускает такое поведение, что мы можем видеть скрытые члены объекта (что его тип совпадает с классом, в котором вы получаете доступ к скрытым членам) в конструкторе копирования или в любом методе в классе.
Ответ: потому что вы, когда вы находитесь в классе, это означает, что вы являетесь строителем или дизайнером класса, также это означает, что вы знаете все элементы данных и методы в этом классе, поэтому он разрешает такое поведение, потому что вы строите этот класс, который вы знаете каждый что-то об этом, в отличие от пользователей класса, они не должны знать все о классе, как вы.
идея сокрытия членов данных или методов, которые помогают пользователям этого класса и не путают их с неважными вещами.
Вот и все.