(Конструктор копирования) Как объект, переданный в качестве параметра для инициализации другого объекта, имеет доступ к закрытым элементам?

#c #class #object

#c #класс #объект

Вопрос:

Пример кода:

 class my
{
    int x;
    public:
    my(int a)
    {
        x = a;
    }
    my(my amp;obj)
    {
        x = obj.x;
    }
.
.
}

int main(void)
{
    my object1(5);
    my object2(object1);
    return 0;
}
  

Как инициализируется object2 путем передачи ему object1? Насколько я вижу, object1 не может получить прямой доступ к элементу x , тогда как это помогает в инициализации object2?

Комментарии:

1. Класс неявно является его собственным другом.

2. @NeilKirk Это отличное описание. Классы C нарциссичны = P

Ответ №1:

Private применяется к классам, а не к объектам. Любой объект класса X имеет доступ к закрытым элементам всех других объектов класса X.

Комментарии:

1. @jack-aidley Разве не так, что к закрытым элементам можно получить доступ только внутри класса, а не его объектами?

2. @aste123: Что вы подразумеваете под «… внутри класса, а не его объектами » ?

3. Любой член класса находится «внутри класса». Не имеет значения, к какому объекту (или к любому объекту) они были вызваны.

4. @aste123 Это не Java. В C классы не являются объектами первого класса; они декларативны. Любой my объект в вашем примере может через свои члены или статические методы класса получить доступ к внутренностям другого my .

5. @aste123: Подумайте об этом так: модификатор говорит, что этот элемент является закрытым, что означает, что к нему можно получить доступ только с помощью кода, который является частью класса. Этот код принадлежит классу , а не отдельным объектам. Код имеет доступ к закрытой информации о любом экземпляре (объекте) класса, а не только к тому, который он знает как this .

Ответ №2:

Управление доступом (общедоступное / частное / защищенное) определяет, может ли фрагмент кода юридически ссылаться на имя члена класса.Отдельные объекты здесь не играют роли; вся проблема заключается только в коде и именах.

Давайте сравним конструктор из вашего вопроса, дружественную функцию и свободную функцию:

 class my
{
  int x;

  friend void fr(myamp;);
public:
  my(my amp;obj)
  {
    x = obj.x;
  }
};

void fr(my amp;obj)
{
  obj.x  = 1;
}

void nonfr(my amp;obj)
{
  obj.x  = 2;
}
  

Возьмите инструкцию x = obj.x; . Оператор — это фрагмент кода. Где этот фрагмент кода? Внутри конструктора класса my . Итак, это часть класса, и поэтому он может получить доступ к имени obj.x .

Далее, оператор obj.x = 1; . Где этот фрагмент кода? Внутри функции fr , которая является другом класса my . Это друг, поэтому он может получить доступ к имени obj.x .

Наконец, оператор obj.x = 2; . Где этот фрагмент кода? Внутри функции nonfr . nonfr это обычная функция, не связанная с классом my , поэтому она не имеет права доступа к именам закрытых (или защищенных) членов класса my , поэтому она не сможет скомпилироваться.


Примечания:

Обычно конструктор копирования должен принимать свой параметр по ссылке на const , например:

 my(const my amp;obj)
  

Конструкторы копирования, которые принимают по неконстантной ссылке, могут изменять исходный объект, и жизнеспособные варианты использования для них крайне редки. Не говоря уже о том, что они предотвращают копирование из временных файлов, поскольку они не могут привязываться к неконстантным ссылкам.

Кроме того, обычно предпочтительнее использовать mem-initializer-lists вместо присваивания внутри конструктора, потому что последний сначала инициализирует элемент, а затем присваивает ему. Итак, в целом конструктор должен выглядеть следующим образом:

 my(const my amp;obj) : x(obj.x)
{}
  

Не говоря уже о том факте, что, если вам не нужна специальная обработка в конструкторе копирования (чего вы здесь не делаете), вы вообще не должны объявлять его и позволять компилятору генерировать его для вас. См. Правило нуля и Правило трех для получения дополнительной информации.

Комментарии:

1. спасибо, хотя это не было задано в вопросах, это был точный источник путаницы для меня. Спасибо, что поняли это из моего комментария. Я обновлю вопрос позже, чтобы добавить этот бит.