Эта книга из серии Must Read. Вот ссылка на неё на сайте самого автора. Книга вышла в серии под названием «C++ In-Depth» под редакцией создателя языка – Бьярна Страуструпа. Книга выдержана в традиционной уже для этой серии книг манере задач для самостоятельного обдумывания с последующим подробным объяснением. Причём вопросы делятся на вопросы для новичков в C++ и вопросы для профессионалов. Не удивляйтесь, если прочитав её вы увидите, что-то знакомое – некоторые материалы на блоге используют информацию подчерпнутую и в ней, равно как и в любых других источниках. Темы задач, предложенных в книге довольно обширны – это: обобщённое программирование и стандартная библиотека, безопасность исключений, дизайн классов, наследование и полиморфизм, оптимизация и эффективность, головоломки и отдельно рассмотрены ошибки при проектировании класса std::string.
Архив за Май 2008
Must Read: Герб Саттер "Новые сложные задачи на C++"
Май 26, 2008Вокруг public, private и protected
Май 19, 2008Тема довольно избита, однако, я всё-таки решил начать с неё. Думаю, новичкам будет полезно.
Итак, public, private и protected – это модификаторы доступа, а не видимости, как ошибочно думают некоторые. Private члены видны снаружи класса, но не доступны.
Теперь кратко, кому какой доступ они предоставляют.
- Public – доступ открыт всем, кто видит определение данного класса.
- Private – доступ открыт самому классу (т.е. функциям-членам данного класса) и друзьям (friend) данного класса, как функциям, так и классам.
- Protected – доступ открыт классам, производным от данного.
Далее приведены примеры доступа с указанием какие поля в каких местах программы доступны.
1 class some {
2 friend void f(some&);
3 public:
4 int a_;
5 protected:
6 int b_;
7 private:
8 int c_;
9 };
10
11 void f(some& obj) {
12 obj.a_ = 0; // ok
13 obj.b_ = 0; // ok
14 obj.c_ = 0; // ok
15 }
16
17 void g(some& obj) {
18 obj.a_ = 0; // ok
19 obj.b_ = 0; // CT error
20 obj.c_ = 0; // CT error
21 }
22
23 class derived : public some {
24 derived() {
25 a_ = 0; // ok
26 b_ = 0; // ok
27 c_ = 0; // CT error
28 }
29 };
В C++ существует public-наследование, private-наследование и protected-наследование. В зависимости от того, какой тип используется, изменяется доступ к членам базового класса для клиентов производного. В таблице сведена информация об этом изменении.
| Исходный модификатор доступа | |||
| public | private | protected | |
| public-наследование | public | private | protected |
| private-наследование | private | private | private |
| protected-наследование | protected | private | protected |
Следует добавить, что производный класс может изменить модификатор доступа с protected на public, разместив using объявление в соответствующей секции класса:
1 class some {
2 public:
3 int a;
4 protected:
5 int b;
6 private:
7 int c;
8 };
9
10 class derived : public some {
11 public:
12 using some::b;
13 };
14
15 void f(derived& obj) {
16 obj.b = 0; // ok
17 }
Напоследок приведу несколько приёмов, с помощью которых можно «достучаться» до закрытых функций или данных. Допустим, у нас есть класс some и нам нужно обнулить закрытую переменную c:
- Модифицировать определение класса, добавив друга (функцию или класс)
1 class some {
2 friend class some_friend;
3 public:
4 int a;
5 protected:
6 int b;
7 private:
8 int c;
9 };
10
11 class some_friend {
12 public:
13 static void hack(some& obj) {
14 obj.c = 0;
15 }
16 };
- Воспользоваться препроцессором:
1 #define private public
2
3 class some {
4 public:
5 int a;
6 protected:
7 int b;
8 private:
9 int c;
10 };
11
12 void hack(some& obj) {
13 obj.c = 0;
14 }
- Создать класс с таким же расположением в памяти и воспользоваться reinterpret_cast для преобразования указателей:
1 class some {
2 public:
3 int a;
4 protected:
5 int b;
6 private:
7 int c;
8 };
9
10 class hack_some {
11 public:
12 int a;
13 int b;
14 int c;
15 };
16
17 void h(some& obj) {
18 reinterpret_cast<hack_some*>(&obj)->c = 0;
19 }
- Если у «взламываемого» класса есть шаблонная функция, можно её специализировать своим типом:
1 class some {
2 public:
3 int a;
4 template<class T> void func(void) {
5 a = b + c;
6 }
7 protected:
8 int b;
9 private:
10 int c;
11 };
12
13 class hack_template_param{};
14
15 template<>
16 void some::func<hack_template_param>(void) {
17 c = 0;
18 }
19
20 void hack(void) {
21 some o;
22 o.func<hack_template_param>();
23 };
Очевидно, что способ с reinterpret_cast работает только для доступа к закрытым членам данных или вызова виртуальных функций. Остальные же способы позволяют как модифицировать закрытые данные, так и вызывать закрытые невиртуальные методы.
На сегодня всё.
C++ Для Всех. Полетели!
Май 6, 2008Приветствую всех читателей!
Этот блог задуман как попытка собрать в одном месте всю интересную и полезную информацию о языке программирования C++. Он может быть использован также и как справочник. Надеюсь, время проведённое на этом блоге не будет потрачено впустую.
