Как вы знаете, закрытые члены могут быть доступны только другим членам класса.
class DateClass // members are private by default
{
int m_month; // private, can only be accessed by other members
int m_day; // private, can only be accessed by other members
int m_year; // private, can only be accessed by other members
};
int main()
{
DateClass date;
date.m_month = 12; // error
date.m_day = 15; // error
date.m_year = 2020; // error
return 0;
}
Но меня очень удивило, что вы можете использовать указатели для доступа к закрытым элементам данных. Пример:
#include <iostream>
class Test {
private:
int data;
public:
Test()
{
data = 0;
}
int getData()
{
return data;
}
};
int main()
{
Test t;
int* ptr = (int*)&t;
*ptr = 10;
std::cout << t.getData(); // it will return 10
return 0;
}
Так это преднамеренно? Почему к закрытым членам можно получить доступ с помощью указателей? Я новичок, поэтому вопрос довольно глупый.
На самом деле поведение использования указателя, полученного оператором
int* ptr = (int*)&t;
не определено. (Технически это строгое нарушение алиасинга).
C++ изобилует неопределенными конструкциями, что делает язык чертовски трудным для освоения. Учитывая, что вы только начинаете изучать C++ (кстати, ничто не заменит хорошую книгу), избегайте всех приведений, пока не поймете, что делаете.
Из любопытства, как class.mem/20 не применяется в случае OP, где макет стандартный, а первый член действительно int
? Я не понимаю са-нарушения, и мне искренне любопытно.
@WhozCraig: Действительно, это стандартный класс макета (обратите внимание, что все члены имеют одинаковый доступ), поэтому адрес t
совпадает с адресом data
внутри этого t
. Но типы по-прежнему не связаны, поэтому применяется строгое сглаживание.
Как я понимаю из class.mem#general-note-12 , указатели взаимопреобразовываются, из expr.static.cast#13 , использование static_cast
из void*
было бы хорошо, поэтому int* ptr = static_cast<int*>(static_cast<void*>(&t))
было бы хорошо. В качестве альтернативы, std::launder тоже подойдет.
Как правило, вы можете получить доступ к любому адресу памяти во всем процессе. Идея
private
состоит в том, чтобы ограничить ваш доступ во время компиляции, чтобы защитить себя, а также других разработчиков, использующих ваш код. Предотвращение доступа для чтения/записи обычно устанавливается на аппаратном уровне (MMU и т. д.).