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

"Двойной" доступ к переменным класса

29.11.2012, 17:40. Показов 1130. Ответов 17
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Господа, прошу совета в изложенной ниже ситуации. Часто мне встречается в различных вариациях, поэтому есть потребность в изящном решении. Итак, есть, допустим, такой класс:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class EnumerousVariables
{
public:
    EnumerousVariables();
    ~EnumerousVariables();
 
    TypeA&  getA() const;
    TypeB&  getB() const;
    // ...
    TypeZZ& getZZ() const;
 
    UniformType& operator [] (int i) const;
 
private:
    Type A a;
    TypeB b;
    // ...
    TypeZZ zz;
};
Класс содержит много переменных разных типов с соответствующими методами доступа к ним. Хочется реализовать метод доступа по индексу (нужен для внешнего модуля), причем все переменные должны конвертироваться к одному типу UniformType. Последний представляет из себя примерно следующее:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class UniformType
{
public:
    UniformType()
    UniformType(const TypeA& _a);
    UniformType(const TypeB& _b);
    // ...
    UniformType(const TypeZZ& _zz);
 
    ~UniformType();
 
    TypeA&  toTypeA(bool& isOK) const;
    TypeB&  toTypeB(bool& isOK) const;
    // ...
    TypeZZ& toTypeZZ(bool& isOK) const;
};
Будем считать, что порядок следования переменных по индексу определен. В данном примере, допустим, алфавитный. Т.е. хочется иметь следующее:

C++
1
2
3
4
5
EnumerousVariables foo = EnumerousVariables();
// где:
// foo[0] == UniformType(foo.getA())
// foo[1] == UniformType(foo.getB())
// и т.д.
Вопрос заключается в следующем. Как реализовать оператор [], не держа копий переменных и не используя switch-case?
В голову приходит только один вариант - изначально держать данные в виде контейнера переменных типа UniformType, а в соответсвующих get-ах set-ах конвертировать данные к(из) соответствующему типу, но это как-то не айс.

Заранее спасибо.
1
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
29.11.2012, 17:40
Ответы с готовыми решениями:

Доступ к переменным класса
Давным давно помню была такая фишка в сях, когда приходилось много раз писать конструкцию типа...

Доступ к переменным базового класса при наследовании
Есть следующий код class Base { protected: int x; Base* enemy; public: Base() {}

Как получить доступ к переменным одного класса из методов другого
Есть класс MainWindow с переменными в pablic, и кьютешный QGraphicsView. Нужно вот тут void...

Доступ к переменным класса
Хочу, чтобы функция otrisovka() имела доступ к моему окну и могла там рисовать изображения....

17
5231 / 3204 / 362
Регистрация: 12.12.2009
Сообщений: 8,113
Записей в блоге: 2
29.11.2012, 18:27 2
Может массив указателей? Размер указателя - величина постоянная и от типа не зависит. Ну а в operator[] сделать просто
C++
1
return *(ptrArray[i]);
0
1 / 1 / 0
Регистрация: 08.02.2012
Сообщений: 16
30.11.2012, 12:59  [ТС] 3
Тоже думал уже.
Получается тогда так:
C++
1
return UniformType(*(ptrArray[i]))
Но для корректного разыменовывания указателя нужно знать тип переменной (чтобы UniformType понимал, чего ему кормят).
А тип переменной-указателя мы как раз и потеряем при записи его в ptrArray. Т.е. перед разыменовыванием указателя нужно будет сделать cast к соответствующем типу, а тип-то мы и не знаем...

UPD: Добавить в UniformType конструктор UniformType(void*) тоже не вариант, т.к. внутри реализации он все равно должен помнить тип переменной для корректной обратной конвертации.
0
576 / 559 / 47
Регистрация: 16.12.2011
Сообщений: 1,389
30.11.2012, 13:18 4
А почему бы метод
C++
1
TypeA&  getA() const;
не переписать как
C++
1
2
3
4
UniformType&  getA() const
{
   return UniformType(_a);
}
конструктор же определен для типа TypeA
UniformType можно вообще шаблонным классом сделать
0
46 / 46 / 4
Регистрация: 08.12.2010
Сообщений: 161
30.11.2012, 13:31 5
как то читал о "двойной передаче" где компилятор определял какой тип при помощи операторов, и я думаю
Джеф Элдер прекрасно описал данный способ в С++ Библиотека Программиста. Где все возлагается на операторы. Но придется делать абстрактный базовый, и при большом количестве типов будет много операторов, оочень много операторов.
0
1 / 1 / 0
Регистрация: 08.02.2012
Сообщений: 16
30.11.2012, 13:36  [ТС] 6
I.M., согласен, решение проблемы, тоже рассматривалось.
Только методов
C++
1
2
TypeA& getA() const;
// и т.д.
это не отменяет, они нужны.
Тогда возникает компромисс - или вдвое увеличивается количество методов, или потом где мне нужен "родной" тип делать
C++
1
TypeA aa = foo.getA().toTypeA()
чего о-о-очень не хотелось бы делать.


dederkay, спасибо, почитаю на досуге. Правда, здесь это едва будет уместно - не такая уж и глобальная проблема в конце концов Можно и switch'ами обойтись, но уж больно не хочется
0
46 / 46 / 4
Регистрация: 08.12.2010
Сообщений: 161
02.12.2012, 18:42 7
доброго, меня вот что интересует нельзя ли использовать
C++
1
auto
который с срр11 для данного случая? Если выйдет можете отписаться?!
0
576 / 559 / 47
Регистрация: 16.12.2011
Сообщений: 1,389
02.12.2012, 19:36 8
dederkay, "для данного случая" - для какого? auto позволяет программисту не писать длинные типы данных, но auto заменяется на них во время компиляции. Иначе говоря типы должны быть известны во время компиляции.
0
46 / 46 / 4
Регистрация: 08.12.2010
Сообщений: 161
02.12.2012, 21:39 9
да вы правы, тут ведь внешний модуль, как то не досмотрел, извините. Да прочитал This type is easily determined procedurally by the compiler as part of its semantic analysis duties. Тупанул(
0
576 / 559 / 47
Регистрация: 16.12.2011
Сообщений: 1,389
02.12.2012, 22:09 10
scriptus, а как вообще вся эта система должна работать?
представим, что у вас есть клевый get метод в виде оператора [], возвращающий нужное поле с данными в виде класса UniformType.
Что дальше?
как вы хотите дальше работать с этим классом? как вы узнаете, что за тип данных внутри?
0
1 / 1 / 0
Регистрация: 08.02.2012
Сообщений: 16
03.12.2012, 11:39  [ТС] 11
I.M., конкретно сейчас все эти танцы нужны для third-party модуля, который понимает входные данные только в формате UniformType. Модуль закрытый и все что мне доступно - конструкторы UniformType для классов, с которыми работает система в целом (а их много). "Родные" же типы данных нужны для корректной работы моей части системы.
Вообще изначально это проблема плохой проработки интерфейса стороннего модуля (имхо).

Другой пример (навскидку) из Qt - класс QAbstractItemModel (и наследуемые от него) - модель данных для qt'шной парадигмы Model-View (разновидность классической MVC). Там есть такая штука:
C++ (Qt)
1
virtual QVariant data (const QModelIndex & index, int role = Qt::DisplayRole ) const = 0;
которая по индексу возвращает данные типа QVariant (аналог UniformType в приведенном выше примере). Этот метод нужно реализовать в наследуемом классе, что в принципе приводит к аналогичному вопросу.
В Qt же такой интерфейс используется для взаимодействия с виджетами (QListView, QTableView и т.п.) для отображения данных модели.

Добавлено через 33 минуты
Сорри, не ответил на вопрос. Дальше с преобразованным типом работает сторонний модуль, как и что там - хз. Судя по доступному заголовочнику могу предположить, что UniformType нужен для корректного хранения данных в некоторой специфичной железке. Как конвертируется назад - тоже загадка. Все, что я могу сделать - а) построить UnifromType из поддерживаемого им типа данных, б) конвертнуть назад в любой другой поддерживаемый тип и посмотреть на bool& ok. Есть подозрение, что в конструкторе просто проставляется определенный флаг, который запоминает исходный тип данных и в дальнейшем определяет, во что можно конвертировать UniformType обратно.
0
Делаю внезапно и красиво
Эксперт С++
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
03.12.2012, 13:09 12
boost.variant или полиморфизм.
0
576 / 559 / 47
Регистрация: 16.12.2011
Сообщений: 1,389
03.12.2012, 13:12 13
scriptus, т.е. насколько я понимаю, менять класс UniformType нельзя? но гарантируется, что в нем есть все нужные конструкторы для ваших типов?
0
1 / 1 / 0
Регистрация: 08.02.2012
Сообщений: 16
03.12.2012, 17:04  [ТС] 14
Deviaphan, думал. Не вижу существенных преимуществ, ибо уже есть UniformType, обладающий в этом конкретном случае схожим функционалом. Имхо, только геморрой приобретается, т.к. компилятор в этом случае не выполняет проверку типа при обратном преобразовании. Это я про boost::variant.
Может, я что-то не понимаю и Вы объясните свою позицию чуть подробнее?

I.M., верно. И первое, и второе.
0
Делаю внезапно и красиво
Эксперт С++
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
03.12.2012, 17:43 15
Аргументирую: ты хочешь реализовать переключение типов, а в ООП переключение типов - зло. буст.вариант лучше тем, что его сотни тысяч раз использовали и отлаживали.
Вопрос в другом: зачем тебе индексированный доступ к объектам РАЗНОГО типа. Ты не сможешь работать с ними в цикле, значит, тебе не нужен индексированный доступ. Если же ты хочешь однообразно работать с ними в цикле, то у них должен быть общий предок и решение твоей проблемы - полиморфизм.
0
1 / 1 / 0
Регистрация: 08.02.2012
Сообщений: 16
03.12.2012, 18:11  [ТС] 16
Deviaphan, аргумент принят. Хотя это не умаляет того, что в compile-time я не поймаю ошибку неверной конверсии variant'а к нужному мне типу. Как в принципе и в случае использования контейнера из UniformType. Но это неизбежно.

Ответ на вопрос: см. первый пост. Индексированный доступ нужен не по родному типу, а по преобразованному (UniformType). Если бы его не было изначально, то вопрос с boost::variant или boost::any не стоял бы. А использовать два контейнера со схожим функционалом одновременно как-то не хочется. Тем более, что без UniformType все равно не обойтись.

По поводу полиморфизма. Увы, в данном случае все классы существуют и определенны, иначе бы я все типы данных наследовал от UniformType изначально и данного вопроса бы не стояло.
0
Делаю внезапно и красиво
Эксперт С++
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
03.12.2012, 19:16 17
Т.е. ты хочешь (например) получить элемент типа UniformType, расположенного по индексу 1 и вызвать для него метод toTypeB и, чтобы при попытке вызова других методов происходила ошибка, желательно времени компиляции? Теперь я правильно тебя понял?

Если сделать индексацию через параметр шаблона, то можно и в compile-time реализовать. В 11 версии, возможно, и без шаблонов можно будет, если обозначить функцию как константу времени компиляции, но в этом вопросе я не компетентен, так что сомневаюсь. В runtime можно реализовать с использованием RTTI.

Добавлено через 1 минуту
Если не секрет, что за внешний модуль? Хочется знать, чтобы держаться от этого разработчика подальше.)

Добавлено через 5 минут
И ещё смущают вот эти методы:
C++
1
TypeA&  toTypeA(bool& isOK) const;
либо ты сократил и не указал константность возвращаемой ссылки, либо возвращается ссылка на временный объект.

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

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
#include <iostream>
 
typedef int TypeA;
typedef double TypeB;
 
 
class UniformType
{
public:
    UniformType()
        : _type(-1)
        , _ptr(0)
    {   }
 
    ~UniformType()
    {
        delete _ptr;
    }
 
    UniformType( UniformType & rhs)
        : _type(-1)
        , _ptr(0)
    {
        DeepCopy(rhs);
    }
 
    explicit UniformType(const TypeA& _a)
        : _type(0)
    {
        _ptr = new TypeA(_a);
    }
 
    explicit UniformType(const TypeB& _b)
        : _type(1)
    {
        _ptr = new TypeB(_b);
    }
 
    UniformType& operator =( UniformType rhs )
    {
        DeepCopy( rhs );
        return *this;
    }
 
    void DeepCopy( UniformType & rhs)
    {
        delete _ptr;
 
        _type = rhs._type;
 
        switch( _type )
        {
        case 0:
            _ptr = new TypeA(rhs.toTypeA()); break;
        case 1:
            _ptr = new TypeB(rhs.toTypeB()); break;
        }
    }
 
    TypeA & toTypeA()
    {
        if( _type != 0 ) throw int(0);
        return *reinterpret_cast<TypeA*>(_ptr);
    }
 
    TypeB & toTypeB()
    {
        if( _type != 1 ) throw double(1);
        return *reinterpret_cast<TypeB*>(_ptr);
    }
 
private:
    int _type;
 
    void * _ptr;
};
 
 
class EnumerousVariables
{
public:
    EnumerousVariables()
    {
        _u[0] = UniformType(10);
        _u[1] = UniformType(3.14);
    }
 
    TypeA&  getA()
    {
        return _u[0].toTypeA();
    }
    TypeB&  getB()
    {
        return _u[1].toTypeB();
    }
 
    UniformType& operator [] (int i)
    {
        return _u[i];
    }
 
private:
    UniformType _u[2];
};
 
 
int _tmain(int argc, _TCHAR* argv[])
{
    EnumerousVariables ev;
 
    std::cout << ev[0].toTypeA() << "\n";
    std::cout << ev[1].toTypeB() << "\n";
//  std::cout << ev[1].toTypeA();
 
    return 0;
}
1
1 / 1 / 0
Регистрация: 08.02.2012
Сообщений: 16
03.12.2012, 19:33  [ТС] 18
В целом - да, верно. Только вот методы toTypeX() мне вообще хотелось бы не использовать (не доверяю я им что-то).
Поэтому (см. первый пост) хотелось бы юзать родные типы. Но вот чтобы сторонний модуль мог со мной работать, ему нужен поиндексный доступ к переменным класса и причем непременно в виде UniformType.

Если не секрет, что за внешний модуль? Хочется знать, чтобы держаться от этого разработчика подальше.)
Нонейм кЕтай какой-то, некий девайс для контроля параметров энергосети - Impulse x700. Хз ваще, что это, но кому-то сверху сильно приспичило с ними интегрироваться.

И ещё смущают вот эти методы:
Да, тупанул я с чего-то. Без ссылок:
C++
1
TypeA  toTypeA(bool& isOK) const;
Добавлено через 1 минуту
Невинная фантазия на данную тему. Только тебе не подойдёт, скорее всего, потому что состав объектов другой получился
Да, фантазия интересная. И да, не пойдет
0
03.12.2012, 19:33
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
03.12.2012, 19:33
Помогаю со студенческими работами здесь

Доступ к переменным внутри класса
чем отличается доступ к объявленной переменной внутри класса указателем $thes-&gt;, от доступа к не...

Доступ к переменным другого класса
class Form1: Form { public Class1 cl; public PictureBox pictureBox1; public ImageList...

Доступ к классам и переменным класса
Я читаю самоучитель и там на каждом шагу пишут что в классах желательно закрывать доступ ко всем...

Ограниченный доступ к переменным класса
У меня есть 3 класса A, B, C. В классе A есть переменная var. Мне нужно, чтобы класс B мог...

Доступ к переменным и функциям класса из потока
Здравствуйте товарищи. У меня такая проблема, создаю поток, в потоке идет цикл прослушивания...

Доступ к переменным класса из обработчика события KeyPress
Добрый день. Есть форма, в ней контрол RichTextBox. Есть обработчик события KeyPress. Могу ли я в...


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

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