Если частные члены класса не могут быть доступны с помощью функции, не являющейся членом, то почему main () может печатать значение phone в этой программе? - PullRequest
2 голосов
/ 05 ноября 2019
#include <iostream>

class student
{
    int phone;
    public:
    student(int a)
    {
        phone = a;
    }

};

int main()
{
    class student s1(10);
    printf("%p \n",&s1);
    printf("%d \n",*(&s1));
  //  printf("%d \n", s1.phone);
   // printf("%p",&s1.phone);


    return 0;
}

output: 0x7fffd5aa5abc
10

Может ли функция, не являющаяся членом, иметь доступ к адресам объектов класса? Если да, то почему мы не можем получить доступ к его членам?

Ответы [ 5 ]

2 голосов
/ 05 ноября 2019

Может ли функция, не являющаяся членом, иметь доступ к адресам объектов класса? Если да, то почему у нас нет доступа к его членам?

У вас распространенное недоразумение. Инкапсуляция данных (как и другие инструменты, такие как constкорректность) - это инструмент, который помогает вам писать лучшие программы, т.е. с меньшим количеством ошибок. Это не тюрьма или сторожевой пес, который попытался бы сделать это невозможным. Вы хотите разрушить свою способность управлять сложностью своей программы - продолжайте, делайте всех участников публичными, не используйте const определители и так далее. Если вы хотите использовать эти инструменты - они станут вашими друзьями. Обычно это означает, что вы пытаетесь получить доступ к этим данным, когда не должны этого делать - компилятор напомнит вам, что вы делаете что-то не так, чтобы вы могли исправить свою ошибку. Это не значит, что он будет контролировать память и магически ограничивать ваш доступ к ней.

1 голос
/ 05 ноября 2019

Может ли функция, не являющаяся членом, иметь доступ к адресам объектов класса?

Да. Адрес объекта не защищен никаким спецификатором доступа.

Если да, то почему мы не можем получить доступ к его членам?

Вы не можете получить доступ к имени phone вне класса, потому что оно закрытое.

Технически это не препятствует доступу к объекту-члену.


printf("%d \n",*(&s1));

%d спецификатор формата требует, чтобы аргумент был int. *(&s1), который ссылается на объект, названный s1, не является int, что нарушает это предварительное условие, и, как следствие, поведение программы не определено.

0 голосов
/ 05 ноября 2019
Объявление класса

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

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

0 голосов
/ 05 ноября 2019

Если частные члены класса не могут быть доступны с помощью функции, не являющейся членом, то почему main () может печатать значение телефона в этой программе?

Это все еще может 'т. Рассмотрим следующий код:

printf("%d \n", s1.phone);

Это не скомпилируется, потому что phone является «закрытым в этом контексте». Вы не можете получить доступ к закрытым переменным-членам напрямую.

Почему это "работает", потому что printf пытается обработать ваш student как int. Поскольку память, хранящаяся в этом месте, предположительно 10 (из-за структуры памяти и т. Д.), Похоже, это работает. Тем не менее, вы все еще не обращаетесь к приватному члену, вы приводите int и обманываете, так сказать, ваш компилятор.

Обратите внимание, что делает это неопределенным поведением , так что нене делай этого. Игра с неопределенным поведением действительно плохая.

0 голосов
/ 05 ноября 2019

Вы должны написать, по крайней мере, как

printf("%d \n",*reinterpret_cast<int *>(&s1));

Заполнение не может быть в начале этого класса с одним нестатическим элементом данных. Таким образом, адрес класса равен адресу его единственного члена данных.

На самом деле вы не имеете дело непосредственно с личным членом данных. Вы просто переосмысливаете память. В общем случае по первому адресу класса может быть что угодно, если, например, класс не является типом стандартного макета.

Обратите внимание на то, что в соответствии со стандартом C ++ порядок размещения нестатических данныхЧлены с разным контролем доступа не определены. Так, например, если вы добавите, например, открытый элемент данных, защищенный pr, в ваш класс, то необязательно, чтобы при использовании трюка с адресом класса вы выводили элемент закрытых данных.

...