#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. спасибо, хотя это не было задано в вопросах, это был точный источник путаницы для меня. Спасибо, что поняли это из моего комментария. Я обновлю вопрос позже, чтобы добавить этот бит.