Форум программистов, компьютерный форум CyberForum.ru

Наследование и защищенные члены - C++

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 11, средняя оценка - 4.73
Selendis
1 / 1 / 0
Регистрация: 15.02.2011
Сообщений: 43
12.04.2011, 15:45     Наследование и защищенные члены #1
Добрый день всем.
У меня имеется следующий набор классов Visitor <- User <- Manager <- Admin
Visitor - самый базовый, надеюсь, иерархия ясна.
В каждом классе есть пара виртуальных функций, меня интересует сейчас
virtual bool set(User* user, char *nm) в классе Admin. Она должна по переданным параметрам менять атрибут name для переданного юзера и придавать ему значение строки nm.
Проблема в том, что я не могу обратиться к user->name, хотя вообще говоря нахожусь в теле потомка.
Через User может передаваться User, Manager или Admin.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#include <iostream>
 
using namespace std;
 
enum X{VIS, USE, MAN, ADM};
 
class User;
 
class Visitor
{
protected:
    char login[8];
    char *name;
    X x;
    Visitor(char l[8], char *nm, X xx = VIS)
    {
        if(strlen(l) != 7)
            cout<<"Error - login should be 7 chars long"<<endl;
        strcpy(login,l);
        name = new char[strlen(nm)+1];
        //if(!name) error
        name = strcpy(name,nm);
        //if(!name) error
    }
public:
    virtual char* getname()
    {
        return 0;
    }
    virtual void printInfo(User& user)
    {
        cout<<"Error: Unknown user"<<endl;
    }
    virtual bool set(User* user, char *name)
    {
        cout<<"Error - access denied"<<endl;
        return false;
    }
    ~Visitor()
    {
        delete[] name;
    }
};
 
class User : public Visitor
{
 
public:
    User (char l[8], char *nm):Visitor(l,nm,USE)
    {
        x = USE;
    }
    virtual char* getname() {return name;}
    virtual bool set(User* user, char *name)
    {
        cout<<"Error - access denied"<<endl;
        cout << user->name;
        return false;
    }
    virtual void printInfo(User& user)
    {
        cout<<name<<endl;
        cout<<login<<endl;
    }
    ~User() {};
};
class Manager : public User
{
public:
    Manager (char l[8], char *nm):User(l,nm)
    {
        x = MAN;
    }
    virtual char* getname() {return name;}
    virtual bool set(User* user, char *nm)
    {
        if(!nm) return false;
        
        delete[] name;
 
        name = new char[strlen(nm)+1];
 
        if(!name) return false;
 
        name = strcpy(name,nm);
 
        if(!name) return false;
 
        return true;
    }
    virtual void printInfo(User& user)
    {
        cout<<name<<endl;
        cout<<login<<endl;
    }
    ~Manager(){}
};
class Admin : public Manager
{
public:
    Admin (char l[8], char *nm):Manager(l,nm)
    {
        x = ADM;
    }
    virtual bool set(User* user, char *nm)
    {
        if(!nm) return false;
        if(this == user)
        {
            delete[] name;
            name = new char[strlen(nm)+1];
            if(!name) return false;
            name = strcpy(name,nm);
            if(!name) return false;
            return true;
        }
        cout<<"---> " << user->name;
        user->set(user,nm);     
        return true;
    }
    virtual void printInfo(User& user)
    {
        if( this != &user)
            user.printInfo(user);
        else
        {
            cout<<name<<endl;
            cout<<login<<endl;
        }
    }
    ~Admin() {}
};
int main()
{
    User u("abcdefg","S1");
    Manager m("abcdefg","S1");
    Admin a("aaaaaaa", "S2");
    Admin a1("aaaaaa1", "S3");
    /*a.printInfo(a);
    m.printInfo(m);
    u.printInfo(u);
    */
    //m.set(&m,"S123");
    //m.printInfo(m);
 
    a.set(&a1,"S321");
    return 0;
}
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Deviaphan
Делаю внезапно и красиво
Эксперт C++
 Аватар для Deviaphan
1283 / 1217 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
12.04.2011, 16:17     Наследование и защищенные члены #2
К защищённым полям напрямую можно обращаться только из методов классов-потомков. Все остальные должны пользоваться интерфейсом класса, в котором определено защищённое поле.
Selendis
1 / 1 / 0
Регистрация: 15.02.2011
Сообщений: 43
12.04.2011, 16:25  [ТС]     Наследование и защищенные члены #3
Deviaphan: Дык ведь это и есть метод класса-потомка!
Да, уточню, 117 строка у меня не работает.
Deviaphan
Делаю внезапно и красиво
Эксперт C++
 Аватар для Deviaphan
1283 / 1217 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
12.04.2011, 20:50     Наследование и защищенные члены #4
Это не совсем метод класса потомка.) Ты вызываешь поле из объекта дочернего класса, а не из объекта класса Admin. Т.е. ты можешь обратиться к полю name из класса Admin, но обратиться к полю name через объект класса User ты не можешь.
А вообще, ты там запланировал метод GetName, так что реализуй его и используй.) Тогда и поля можно сделать закрытыми.
Selendis
1 / 1 / 0
Регистрация: 15.02.2011
Сообщений: 43
12.04.2011, 20:58  [ТС]     Наследование и защищенные члены #5
Deviaphan: А вот по поводу реализации GetName - если я это сделаю, то Getname будет свой для каждого класса.
Т.е. тогда в силу виртуальности он будет вызван для объекта этого класса и из него - т.е. надо будет, чтобы GetName объекта с недостаточным доступом - Manager или User - возвращал эту строку и ее можно было бы изменять? Не будет ли это неправильно?
Deviaphan
Делаю внезапно и красиво
Эксперт C++
 Аватар для Deviaphan
1283 / 1217 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
13.04.2011, 07:09     Наследование и защищенные члены #6
Правильно будет так, как тебе нужно. Механизм виртуальных функций для того и придуман, чтобы поведение изменять.
Другое дело, нужны ли тебе разные реализации? И, почему Visitor возвращает 0, хотя name определена именно в нём.
Selendis
1 / 1 / 0
Регистрация: 15.02.2011
Сообщений: 43
13.04.2011, 10:30  [ТС]     Наследование и защищенные члены #7
Ну теоретически Визитор - он никто и имени своего посмотреть не может.
Также как и Юзер, хотя вот у него имя уже есть.
А Менеджер может посмотреть.
Ну Админ может менять имя, в том числе и у себя, и у других Админов.

Но если я передаю в функцию set Админа указатель на юзера или менеджера, то в силу работы виртуальной функции, она вызовется та, что переопределена в этом самом классе - ну, на который указатель.
Иначе мне придется дать слишком много привилегий Юзеру - разрешить его функции менять имя, например.
Или я чего-то не понимаю?
Deviaphan
Делаю внезапно и красиво
Эксперт C++
 Аватар для Deviaphan
1283 / 1217 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
13.04.2011, 14:34     Наследование и защищенные члены #8
Цитата Сообщение от Selendis Посмотреть сообщение
Ну теоретически Визитор - он никто и имени своего посмотреть не может.
Поле name задано в классе Визитёр, соответственно и интерфейс для работы с именем можно задать в нём. Или ты собрался реализовывать метод GetName сложнее, чем просто return name?
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,271
13.04.2011, 16:38     Наследование и защищенные члены #9
Цитата Сообщение от Deviaphan Посмотреть сообщение
Ты вызываешь поле из объекта дочернего класса, а не из объекта класса Admin.
Нельзя ли поподробнее? То есть я просто хочу уточнить,
C++
1
                cout<<"---> " << user->name;
В данном случае компилятор предлагает, что объект класса Admin СОВСЕМ ДАЖЕ НЕОБЯЗАТЕЛЬНО произошёл от объекта user, а просто-напросто располагает адресом этого объекта поэтому эту строчку бракует, так?
Deviaphan
Делаю внезапно и красиво
Эксперт C++
 Аватар для Deviaphan
1283 / 1217 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
13.04.2011, 17:05     Наследование и защищенные члены #10
Цитата Сообщение от kravam Посмотреть сообщение
В данном случае компилятор предлагает
Я не знаю, почему так. Честно скажу, сам был удивлён. Специально пример скомпилировать попробовал.)
Думаю, дело в том, что класс Admin и класс User - разные классы, хоть Admin и является дочерним для User.
Я не знаю, что поэтому поводу сказано в стандарте.)
Тут объект одного типа пытается получить доступ к защищённому полю объекта другого типа. Думаю, правильно, что нельзя. Меньше возможностей для ошибки.
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,271
13.04.2011, 18:12     Наследование и защищенные члены #11
Ну у меня в учебнике написано по поводу protected
"Член может быть доступен из функции, только если она член класса или подкласса"

То есть вроде как всё верно, не фиг через адреса объектов, которые не являются старшими родственниками, получать доступ к приватным членам.

А тогда тем страннее выглядит определение set в классе User
C++
1
2
3
4
5
6
        virtual bool set(User* user, char *name)
        {
                cout<<"Error - access denied"<<endl;
                cout << user->name;
                return false;
        }
Это компилится. То есть В ЭТОМ случае компилятор почему-то согласен- да, пусть будет объект
A типа User и объект B типа User. И мы спокойно передадим объекту A адрес объекта B. А тот, в свою очередь, даст объекту A значение name.

И это при всём при том, что A и B могут иметь разных отцов, то есть между ними вообще никаких родственных связей может не быть!
Deviaphan
Делаю внезапно и красиво
Эксперт C++
 Аватар для Deviaphan
1283 / 1217 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
13.04.2011, 18:46     Наследование и защищенные члены #12
Цитата Сообщение от kravam Посмотреть сообщение
это при всём при том, что A и B могут иметь разных отцов, то есть между ними вообще никаких родственных связей может не быть!
А если мать у них одна?
Selendis
1 / 1 / 0
Регистрация: 15.02.2011
Сообщений: 43
13.04.2011, 19:20  [ТС]     Наследование и защищенные члены #13
Deviaphan: Изначально суть такая - Админ, как суперпользователь, в своем методе set может изменять значение поля name в переданном объекте User на второй параметр метода Admin::set.
Единственный вариант, который я тут вижу - это чтобы Get name был char& getname(), т.е. предоставлял совершенно небезопасный доступ к члену, который, кстати, может хоть private - при таком методе по барабану совершенно. Но это плохо.

А если говорить об обычном методе getName - а на кой фиг там такой метод нужен? Если в User будет public метод, возвращающий имя и public, разрешающий изменение, то это бред - User не может его менять, как и Manager.

Если метод будет protected, то я его вот таким вот образом - в Admin::set - не смогу вызвать так же, как и достать name собственно сейчас.
Я могу его сделать виртуальным, но мне от этого ни холодно, ни жарко - вызываться-то он будет для передаваемого объекта, т.е. User или Manager.

Просто может там static_cast'ом привести к правильному типу, используя значение enum члена?

Решение, которое я вижу - это объявить в User "friend class Admin". Но это бред бредовый - "давайте объявим в родителе то, что дети к нему дружествены и могут достучаться до protected членов".
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,271
13.04.2011, 20:07     Наследование и защищенные члены #14
Цитата Сообщение от Selendis Посмотреть сообщение
Deviaphan: Изначально суть такая - Админ, как суперпользователь, в своем методе set может изменять значение поля name в переданном объекте User на второй параметр метода Admin::set.
Тогда у меня один вопрос. Вот, допустим, объект A класса Admin и вот он вызывает функцию set, где первый параметр- указатель p на объект типа User

...Обязательно ли, что бы A был потомком объекта *p? Или необязательно?
Deviaphan
Делаю внезапно и красиво
Эксперт C++
 Аватар для Deviaphan
1283 / 1217 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
13.04.2011, 20:16     Наследование и защищенные члены #15
Если Юзер не может изменять и получать имя, то зачем это поле создано в нём? Зачем объявлять в нём методы, которые не используют это поле? Если объекты Юзер не должны создаваться, класс следует сделать абстрактным. Если Юзеры могут создаваться, но имени у них нет, то и поле name в них не нужно. В общем, очень подозрительная иерархия.

Добавлено через 48 секунд
*Не Юзер, а Посетитель. Обчитался.
Mr.X
Эксперт С++
 Аватар для Mr.X
2807 / 1583 / 248
Регистрация: 03.05.2010
Сообщений: 3,688
13.04.2011, 21:06     Наследование и защищенные члены #16
Применение защищенных членов-данных и индикаторов типа наводит на мысль, что данный вариант проекта иерархии классов у вас не совсем удачный.
А вы можете саму задачу сформулировать?
Selendis
1 / 1 / 0
Регистрация: 15.02.2011
Сообщений: 43
13.04.2011, 21:49  [ТС]     Наследование и защищенные члены #17
В некотором приложении определены следующие классы, определяющие роли пользователей этого приложения:
Visitor - незарегистрированный пользователь
User - пользователь с минимальными правами
Manager - пользователь с расширенными правами
Admin - администратор системы
Для любого пользователя системы, за исключением класса Visitor, определены следующие поля:
- логин пользователя - массив char[8]
- имя пользователя - массив типа char произвольной длины
- уровень прав пользователя в системе - целое поле, я его енумом сделал

Для каждого определены следующие правила:
- Визитор не имеет доступа ни к одному полю даже на чтение
- Юзер может только читать свои поля
- Менеджер может читать поля любого Юзера, кроме того может читать и менять свои имя и логин
- Админ соответственно может менять любое любого пользователя

Все классы должны входить в одну иерархию наследования, в которой базовым является Визитор.
Все классы должны иметь виртуальные методы void printInfo(User &user) и bool set(User *user, char *name)
Инфа о printInfo:
- для Визитора - строку ошибки
- для Юзера и Менеджера - собственные имя и логин
- для Админа - имя и логин того, кто передан по ссылке - ну аргументом функции
Инфа о set:
- Юзер - Access denied, return false
- Manager - замена собственного name
- Admin - устанавливает имя того пользователя, указатель на который передается в качестве первого параметра метода, второй параметр - это новое значение. true,false - успешно или нет выполнена операция.
Все, текст задания кончился.

Фраза про одну иерархию меня натолкнула на то, что одно другое наследует столбиком, хотя наверное Визитор можно сделать базовым для каждого из остальных. Тогда и проблема с протектед членами решится.

Далее, насчет переноса аттрибутов - раз уж Визитор будет базовым, логичнее их там оставить имхо.
ValeryS
Модератор
6377 / 4843 / 442
Регистрация: 14.02.2011
Сообщений: 16,057
13.04.2011, 22:00     Наследование и защищенные члены #18
попробуй сделать в админе френдом юзера
хотя если он сам от него наследуется???(хрен знает получится или нет)
Deviaphan
Делаю внезапно и красиво
Эксперт C++
 Аватар для Deviaphan
1283 / 1217 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
14.04.2011, 06:56     Наследование и защищенные члены #19
Цитата Сообщение от Selendis Посмотреть сообщение
Далее, насчет переноса аттрибутов - раз уж Визитор будет базовым, логичнее их там оставить имхо.
Цитата Сообщение от Selendis Посмотреть сообщение
Для любого пользователя системы, за исключением класса Visitor, определены следующие поля:
Т.е. это запрещено в самом задании.

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

Хоть это и совершенно тупая иерархия, но поля следует определить в Юзере. В дочерних классах обращаться не напрямую к полю, а через методы.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
14.04.2011, 09:47     Наследование и защищенные члены
Еще ссылки по теме:

C++ Статические члены класса
Упорядочить массив так, чтобы сначала иши упорядоченные положительные члены а потом упорядоченные отрицательные члены C++
C++ Заменить наследование классов на наследование интерфейсов

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Selendis
1 / 1 / 0
Регистрация: 15.02.2011
Сообщений: 43
14.04.2011, 09:47  [ТС]     Наследование и защищенные члены #20
Офф: Ну уж обучение всегда забавно - я тут недавно кодил перегрузку ostream так, чтобы был важен порядок аргументов...

Поля определить в Юзере - т.е. оставить иерархию без изменений?

Отлично, а методы-то защищенные или открытые? Защищенные - дык то же, что и с переменными будет) Открытые - это по проектированию бред будет.
Т.е. отлично, вот у нас такой набор привилегий, но еще будет два открытых метода к каждому классу, начиная с Юзера, для чтения и изменения привилегий - так что ли сделать?

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#include <iostream>
 
using namespace std;
 
enum X{VIS, USE, MAN, ADM};
 
class User;
class Admin;
 
class Visitor
{
protected:
    Visitor()
    {
        
    }
    
public:
    virtual char* getname()
    {
        return 0;
    }
    virtual bool setname(char* nm)
    {
        //if(!nm) error
        return true;
        
    }
    virtual void printInfo(User& user)
    {
        cout<<"Error: Unknown user"<<endl;
    }
    virtual bool set(User* user, char *name)
    {
        cout<<"Error - access denied"<<endl;
        return false;
    }
    ~Visitor()
    {
    }
};
 
class User : public Visitor
{
protected:
    char login[8];
    char *name;
    X x;
public:
    User (char l[8], char *nm, X xx=USE):Visitor(), x(xx)
    {
        if(strlen(l) != 7)
            cout<<"Error - login should be 7 chars long"<<endl;
        strcpy(login,l);
        name = new char[strlen(nm)+1];
        //if(!name) error
        name = strcpy(name,nm);
        //if(!name) error
    }
    virtual char* getname() {return name;}
    virtual bool setname(char* nm)
    {
        if(!nm) return false;
        
        delete[] name;
 
        name = new char[strlen(nm)+1];
 
        if(!name) return false;
 
        name = strcpy(name,nm);
 
        if(!name) return false;
 
        return true;
    }
    virtual bool set(User* user, char *name)
    {
        cout<<"Error - access denied"<<endl;
        cout << user->name;
        return false;
    }
    virtual void printInfo(User& user)
    {
        cout<<name<<endl;
        cout<<login<<endl;
    }
    ~User() {delete[] name;}
};
class Manager : public User
{
public:
    Manager (char l[8], char *nm):User(l,nm, MAN)
    {
    }
    virtual char* getname() {return name;}
    virtual bool setname(char* nm)
    {
        return this->set(0,nm);
    }
    virtual bool set(User* user, char *nm)
    {
        if(!nm) return false;
        
        delete[] name;
 
        name = new char[strlen(nm)+1];
 
        if(!name) return false;
 
        name = strcpy(name,nm);
 
        if(!name) return false;
 
        return true;
    }
    virtual void printInfo(User& user)
    {
        cout<<name<<endl;
        cout<<login<<endl;
    }
    ~Manager(){}
};
class Admin : public Manager
{
public:
    Admin (char l[8], char *nm) : Manager(l,nm)
    {
        x = ADM;
    }
    virtual bool setname(char* nm)
    {
        if(!nm) return false;
        
        delete[] name;
 
        name = new char[strlen(nm)+1];
 
        if(!name) return false;
 
        name = strcpy(name,nm);
 
        if(!name) return false;
 
        return true;
    }
    bool set(User* user, char *nm)
    {
        if(!nm) return false;
        if(this == user)
        {
            delete[] name;
            name = new char[strlen(nm)+1];
            if(!name) return false;
            name = strcpy(name,nm);
            if(!name) return false;
            return true;
        }
        return user->setname(nm);
    }
    virtual void printInfo(User& user)
    {
        if( this != &user)
            user.printInfo(user);
        else
        {
            cout<<name<<endl;
            cout<<login<<endl;
        }
    }
    ~Admin() {}
};
int main()
{
    User u("abcdefg","S1");
    Manager m("abcdefg","S1");
    Admin a("aaaaaaa", "S2");
    Admin a1("aaaaaa1", "S3");
    /*a.printInfo(a);
    m.printInfo(m);
    u.printInfo(u);
    */
    //m.set(&m,"S123");
    //m.printInfo(m);
 
    a.set(&a1,"S321");
    a1.printInfo(a1);
    return 0;
}
Yandex
Объявления
14.04.2011, 09:47     Наследование и защищенные члены
Ответ Создать тему
Опции темы

Текущее время: 12:44. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru