Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.53/15: Рейтинг темы: голосов - 15, средняя оценка - 4.53
1 / 1 / 0
Регистрация: 15.02.2011
Сообщений: 43
1

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

12.04.2011, 15:45. Показов 2790. Ответов 23
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Добрый день всем.
У меня имеется следующий набор классов 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;
}
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
12.04.2011, 15:45
Ответы с готовыми решениями:

Невозможно явно декларировать элементы, которые определены в пространстве имен, как частные, защищенные или защищенные внутренние
Приветствую! В общем ошибка такая: Ошибка 1 Невозможно явно декларировать элементы, которые...

Наследование и члены базового класса
Господа скажите пожалуйста, если в базовом классе есть конструктор, который принимает один...

Наследование от protected класса: будут ли public члены класса Б доступны классу А
Добрый день! Если пронаследовать public класс А от protected класса Б, будут ли public члены...

Переставить члены последовательности так, чтобы сначала расположились все ее неотрицательные члены
Помогите пожалуйста решить задачу!!! Экзамен горит.... Выручайте!!! Дана очередь, элементами...

23
Делаю внезапно и красиво
Эксперт С++
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
12.04.2011, 16:17 2
К защищённым полям напрямую можно обращаться только из методов классов-потомков. Все остальные должны пользоваться интерфейсом класса, в котором определено защищённое поле.
0
1 / 1 / 0
Регистрация: 15.02.2011
Сообщений: 43
12.04.2011, 16:25  [ТС] 3
Deviaphan: Дык ведь это и есть метод класса-потомка!
Да, уточню, 117 строка у меня не работает.
0
Делаю внезапно и красиво
Эксперт С++
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
12.04.2011, 20:50 4
Это не совсем метод класса потомка.) Ты вызываешь поле из объекта дочернего класса, а не из объекта класса Admin. Т.е. ты можешь обратиться к полю name из класса Admin, но обратиться к полю name через объект класса User ты не можешь.
А вообще, ты там запланировал метод GetName, так что реализуй его и используй.) Тогда и поля можно сделать закрытыми.
0
1 / 1 / 0
Регистрация: 15.02.2011
Сообщений: 43
12.04.2011, 20:58  [ТС] 5
Deviaphan: А вот по поводу реализации GetName - если я это сделаю, то Getname будет свой для каждого класса.
Т.е. тогда в силу виртуальности он будет вызван для объекта этого класса и из него - т.е. надо будет, чтобы GetName объекта с недостаточным доступом - Manager или User - возвращал эту строку и ее можно было бы изменять? Не будет ли это неправильно?
0
Делаю внезапно и красиво
Эксперт С++
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
13.04.2011, 07:09 6
Правильно будет так, как тебе нужно. Механизм виртуальных функций для того и придуман, чтобы поведение изменять.
Другое дело, нужны ли тебе разные реализации? И, почему Visitor возвращает 0, хотя name определена именно в нём.
0
1 / 1 / 0
Регистрация: 15.02.2011
Сообщений: 43
13.04.2011, 10:30  [ТС] 7
Ну теоретически Визитор - он никто и имени своего посмотреть не может.
Также как и Юзер, хотя вот у него имя уже есть.
А Менеджер может посмотреть.
Ну Админ может менять имя, в том числе и у себя, и у других Админов.

Но если я передаю в функцию set Админа указатель на юзера или менеджера, то в силу работы виртуальной функции, она вызовется та, что переопределена в этом самом классе - ну, на который указатель.
Иначе мне придется дать слишком много привилегий Юзеру - разрешить его функции менять имя, например.
Или я чего-то не понимаю?
0
Делаю внезапно и красиво
Эксперт С++
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
13.04.2011, 14:34 8
Цитата Сообщение от Selendis Посмотреть сообщение
Ну теоретически Визитор - он никто и имени своего посмотреть не может.
Поле name задано в классе Визитёр, соответственно и интерфейс для работы с именем можно задать в нём. Или ты собрался реализовывать метод GetName сложнее, чем просто return name?
0
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
13.04.2011, 16:38 9
Цитата Сообщение от Deviaphan Посмотреть сообщение
Ты вызываешь поле из объекта дочернего класса, а не из объекта класса Admin.
Нельзя ли поподробнее? То есть я просто хочу уточнить,
C++
1
                cout<<"---> " << user->name;
В данном случае компилятор предлагает, что объект класса Admin СОВСЕМ ДАЖЕ НЕОБЯЗАТЕЛЬНО произошёл от объекта user, а просто-напросто располагает адресом этого объекта поэтому эту строчку бракует, так?
0
Делаю внезапно и красиво
Эксперт С++
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
13.04.2011, 17:05 10
Цитата Сообщение от kravam Посмотреть сообщение
В данном случае компилятор предлагает
Я не знаю, почему так. Честно скажу, сам был удивлён. Специально пример скомпилировать попробовал.)
Думаю, дело в том, что класс Admin и класс User - разные классы, хоть Admin и является дочерним для User.
Я не знаю, что поэтому поводу сказано в стандарте.)
Тут объект одного типа пытается получить доступ к защищённому полю объекта другого типа. Думаю, правильно, что нельзя. Меньше возможностей для ошибки.
0
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
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 могут иметь разных отцов, то есть между ними вообще никаких родственных связей может не быть!
0
Делаю внезапно и красиво
Эксперт С++
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
13.04.2011, 18:46 12
Цитата Сообщение от kravam Посмотреть сообщение
это при всём при том, что A и B могут иметь разных отцов, то есть между ними вообще никаких родственных связей может не быть!
А если мать у них одна?
0
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 членов".
0
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
13.04.2011, 20:07 14
Цитата Сообщение от Selendis Посмотреть сообщение
Deviaphan: Изначально суть такая - Админ, как суперпользователь, в своем методе set может изменять значение поля name в переданном объекте User на второй параметр метода Admin::set.
Тогда у меня один вопрос. Вот, допустим, объект A класса Admin и вот он вызывает функцию set, где первый параметр- указатель p на объект типа User

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

Добавлено через 48 секунд
*Не Юзер, а Посетитель. Обчитался.
0
Эксперт С++
3225 / 1752 / 436
Регистрация: 03.05.2010
Сообщений: 3,867
13.04.2011, 21:06 16
Применение защищенных членов-данных и индикаторов типа наводит на мысль, что данный вариант проекта иерархии классов у вас не совсем удачный.
А вы можете саму задачу сформулировать?
0
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 - успешно или нет выполнена операция.
Все, текст задания кончился.

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

Далее, насчет переноса аттрибутов - раз уж Визитор будет базовым, логичнее их там оставить имхо.
0
Модератор
Эксперт по электронике
8908 / 6677 / 918
Регистрация: 14.02.2011
Сообщений: 23,521
13.04.2011, 22:00 18
попробуй сделать в админе френдом юзера
хотя если он сам от него наследуется???(хрен знает получится или нет)
0
Делаю внезапно и красиво
Эксперт С++
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
14.04.2011, 06:56 19
Цитата Сообщение от Selendis Посмотреть сообщение
Далее, насчет переноса аттрибутов - раз уж Визитор будет базовым, логичнее их там оставить имхо.
Цитата Сообщение от Selendis Посмотреть сообщение
Для любого пользователя системы, за исключением класса Visitor, определены следующие поля:
Т.е. это запрещено в самом задании.

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

Хоть это и совершенно тупая иерархия, но поля следует определить в Юзере. В дочерних классах обращаться не напрямую к полю, а через методы.
0
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;
}
0
14.04.2011, 09:47
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
14.04.2011, 09:47
Помогаю со студенческими работами здесь

Переставить члены последовательности так, чтобы сначала расположились все ее неотрицательные члены
Помогите решить задачу! :cofee2: Дана очередь, элементами которой являются действительные числа....

Данные, защищенные паролем
Недавно начала изучать лисп и столкнулась с такой проблемой: Есть процедура make-account которая...

Защищённые листы в Excel
Доброго времени суток товарищи! Подключаюсь через ADO к Excel такой строкой подключения: string...

Защищенные видео с YouTube
Не нашел подходящей ветки, поэтому решил написать свой вопрос тут. Гугл, что-то, тоже не помог. ...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru