#c #class #c 11 #pointers #private
#c #класс #c 11 #указатели #Частное
Вопрос:
Как вы знаете, к закрытым членам могут быть доступны только другие члены класса
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*)amp;t;
*ptr = 10;
std::cout << t.getData(); // it will return 10
return 0;
}
Так это намеренно? Почему к закрытым членам можно получить доступ с помощью указателей? Я новичок, поэтому этот вопрос довольно глупый.
Комментарии:
1. Обычно вы можете получить доступ к любому адресу памяти во всем процессе. Идея
private
состоит в том, чтобы ограничить ваш доступ во время компиляции , чтобы защитить себя, а также других разработчиков , использующих ваш код. Предотвращение доступа на чтение / запись обычно устанавливается на уровне HW (MMU и т. Д.).
Ответ №1:
На самом деле поведение использования указателя, полученного с помощью инструкции
int* ptr = (int*)amp;t;
не определено. (Технически это строгое нарушение псевдонимов).
C изобилует неопределенными конструкциями, что делает язык дьявольски трудным для освоения. Учитывая, что вы только начинаете использовать C (кстати, хорошую книгу ничем не заменишь), избегайте всех приведений, пока не узнаете, что делаете.
Комментарии:
1. Из любопытства, как class.mem/20 не применяется в случае OPs, где макет стандартный, а первый член действительно
int
есть? Я не понимаю нарушения sa, и мне искренне любопытно.2. @WhozCraig: действительно, это класс стандартной компоновки (обратите внимание, что все члены имеют одинаковый доступ), поэтому адрес
t
совпадает с адресомdata
внутри негоt
. Но типы по-прежнему не связаны, поэтому применяется строгое наложение псевдонимов.3. Как я понимаю из class.mem#general-note-12 , указатель можно преобразовать , из expr.static.cast #13 , использование
static_cast
fromvoid*
было бы хорошо, такint* ptr = static_cast<int*>(static_cast<void*>(amp;t))
что все будет хорошо. В качестве альтернативы,std::launder
тоже должно быть хорошо.