|
|||||||||||||||||||
Модификаторы public, private и protected в C++
Время создания: 18.07.2015 22:51
Текстовые метки: Модификатор, public, private, protected, C++, доступ, наследование, правила, контроль
Раздел: Компьютер - Программирование - Язык C++ (Си++)
Запись: xintrea/mytetra_syncro/master/base/1437249075bdhvw1kmzw/text.html на raw.github.com
|
|||||||||||||||||||
|
|||||||||||||||||||
Модификаторы доступа Public, private и protected — это модификаторы доступа, а не видимости, как ошибочно думают некоторые. Ниже кратко написано, кому какой доступ они предоставляют.
Примечание: Следует понимать, что модификаторы доступа - это модификаторы доступа к именам полей класса. Это не модификаторы доступа к данным класса. То есть, если сделать два поля типа int, причем int a будет Public, а int b будет Protected, то это не значит, что значение int b (т. е. данные) полностью защищено от изменения внешним кодом. Внешний код может получить указатель на a, прибавить к нему через арифметику указателей единицу или любое другое число, чтобы попасть на область памяти переменной b, и считать значение b, и даже его заменить. Другими словами, модификаторы доступа всего лишь дают указания компилятору контролировать обращение к полям класса. Причем контролируется именно обращение к полю класса по имени поля. И если обращение по имени будет произведено из области, где доступ к данному полю класса запрещен, компилятор выдаст ошибку времени компиляции. Всего лишь. Далее приведены примеры доступа с указанием, какие поля в каких местах программы доступны. class some { friend void f(some&); public: int a_; protected: int b_; private: int c_; };
void f(some& obj) { obj.a_ = 0; // OK obj.b_ = 0; // OK obj.c_ = 0; // OK }
void g(some& obj) { obj.a_ = 0; // OK obj.b_ = 0; // compile time error obj.c_ = 0; // compile time error }
class derived : public some { derived() { a_ = 0; // OK b_ = 0; // OK c_ = 0; // compile time error } }; Модификаторы наследования В C++ существует public-наследование, private-наследование и protected-наследование. В зависимости от того, какой тип используется, изменяется доступ к членам базового класса для клиентов производного. В таблице сведена информация об этом изменении:
Следует добавить, что производный класс может изменить модификатор доступа с protected на public, разместив using объявление в соответствующей секции класса: class some { public: int a; protected: int b; private: int c; };
class derived : public some { public: using some::b; };
void f(derived& obj) { obj.b = 0; // OK } Обычно, чтобы сохранить модификаторы доступа, используется public-наследование. Тогда у производного класса модификаторы доступа получаются точно такими же как и у базового класса. Неэтичные приемы обращения к закрытым полям класса Создание программы - это выстраивание правильной структуры классов и их отношений. Однако, язык Си++ настолько небезопасный, что существует несколько методов, которые несмотря на имеющуюся структуру, обходными путями позволяют получить доступ к полям класса. Причем этот доступ будет не вероятностный через указатели, как было написано выше в примечании, а вполне точный к любому защищенному полю. Смысла так делать практически нет никакого (программа просто станет более запустанной), но нужно понимать что такая возможность есть. Вот несколько приёмов, с помощью которых можно "достучаться" до закрытых функций или данных. Допустим, у нас есть класс some и нам нужно обнулить закрытую переменную c. Как это можно сделать?
class some { friend class some_friend; public: int a; protected: int b; private: int c; };
class some_friend { public: static void hack(some& obj) { obj.c = 0; } }; #define private public
class some { public: int a; protected: int b; private: int c; };
void hack(some& obj) { obj.c = 0; }
class some { public: int a; protected: int b; private: int c; };
class hack_some { public: int a; int b; int c; };
void h(some& obj) { reinterpret_cast<hack_some*>(&obj)->c = 0; }
class some { public: int a; template<class T> void func(void) { a = b + c; } protected: int b; private: int c; };
class hack_template_param{};
template<> void some::func<hack_template_param>(void) { c = 0; }
void hack(void) { some o; o.func<hack_template_param>(); }; Очевидно, что способ с reinterpret_cast работает только для доступа к закрытым членам данных или вызова виртуальных функций. Остальные же способы позволяют как модифицировать закрытые данные, так и вызывать закрытые невиртуальные методы. PS: Для компиляторов GCC и CLANG существует опция -fno-access-control, которая позволяет отключить контроль доступа к членам класса со стороны компилятора. |
|||||||||||||||||||
Так же в этом разделе:
|
|||||||||||||||||||
|
|||||||||||||||||||
|