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

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

Восстановить пароль Регистрация
 
scriptus
1 / 1 / 0
Регистрация: 08.02.2012
Сообщений: 16
29.11.2012, 17:40     "Двойной" доступ к переменным класса #1
Господа, прошу совета в изложенной ниже ситуации. Часто мне встречается в различных вариациях, поэтому есть потребность в изящном решении. Итак, есть, допустим, такой класс:

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-ах конвертировать данные к(из) соответствующему типу, но это как-то не айс.

Заранее спасибо.
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Kastaneda
Модератор
Эксперт С++
 Аватар для Kastaneda
4237 / 2770 / 218
Регистрация: 12.12.2009
Сообщений: 7,104
Записей в блоге: 1
Завершенные тесты: 1
29.11.2012, 18:27     "Двойной" доступ к переменным класса #2
Может массив указателей? Размер указателя - величина постоянная и от типа не зависит. Ну а в operator[] сделать просто
C++
1
return *(ptrArray[i]);
scriptus
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*) тоже не вариант, т.к. внутри реализации он все равно должен помнить тип переменной для корректной обратной конвертации.
I.M.
 Аватар для I.M.
564 / 547 / 5
Регистрация: 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 можно вообще шаблонным классом сделать
dederkay
 Аватар для dederkay
34 / 34 / 0
Регистрация: 08.12.2010
Сообщений: 161
30.11.2012, 13:31     "Двойной" доступ к переменным класса #5
как то читал о "двойной передаче" где компилятор определял какой тип при помощи операторов, и я думаю
Джеф Элдер прекрасно описал данный способ в С++ Библиотека Программиста. Где все возлагается на операторы. Но придется делать абстрактный базовый, и при большом количестве типов будет много операторов, оочень много операторов.
scriptus
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'ами обойтись, но уж больно не хочется
dederkay
 Аватар для dederkay
34 / 34 / 0
Регистрация: 08.12.2010
Сообщений: 161
02.12.2012, 18:42     "Двойной" доступ к переменным класса #7
доброго, меня вот что интересует нельзя ли использовать
C++
1
auto
который с срр11 для данного случая? Если выйдет можете отписаться?!
I.M.
 Аватар для I.M.
564 / 547 / 5
Регистрация: 16.12.2011
Сообщений: 1,389
02.12.2012, 19:36     "Двойной" доступ к переменным класса #8
dederkay, "для данного случая" - для какого? auto позволяет программисту не писать длинные типы данных, но auto заменяется на них во время компиляции. Иначе говоря типы должны быть известны во время компиляции.
dederkay
 Аватар для dederkay
34 / 34 / 0
Регистрация: 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. Тупанул(
I.M.
 Аватар для I.M.
564 / 547 / 5
Регистрация: 16.12.2011
Сообщений: 1,389
02.12.2012, 22:09     "Двойной" доступ к переменным класса #10
scriptus, а как вообще вся эта система должна работать?
представим, что у вас есть клевый get метод в виде оператора [], возвращающий нужное поле с данными в виде класса UniformType.
Что дальше?
как вы хотите дальше работать с этим классом? как вы узнаете, что за тип данных внутри?
scriptus
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 обратно.
Deviaphan
Делаю внезапно и красиво
Эксперт C++
 Аватар для Deviaphan
1283 / 1217 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
03.12.2012, 13:09     "Двойной" доступ к переменным класса #12
boost.variant или полиморфизм.
I.M.
 Аватар для I.M.
564 / 547 / 5
Регистрация: 16.12.2011
Сообщений: 1,389
03.12.2012, 13:12     "Двойной" доступ к переменным класса #13
scriptus, т.е. насколько я понимаю, менять класс UniformType нельзя? но гарантируется, что в нем есть все нужные конструкторы для ваших типов?
scriptus
1 / 1 / 0
Регистрация: 08.02.2012
Сообщений: 16
03.12.2012, 17:04  [ТС]     "Двойной" доступ к переменным класса #14
Deviaphan, думал. Не вижу существенных преимуществ, ибо уже есть UniformType, обладающий в этом конкретном случае схожим функционалом. Имхо, только геморрой приобретается, т.к. компилятор в этом случае не выполняет проверку типа при обратном преобразовании. Это я про boost::variant.
Может, я что-то не понимаю и Вы объясните свою позицию чуть подробнее?

I.M., верно. И первое, и второе.
Deviaphan
Делаю внезапно и красиво
Эксперт C++
 Аватар для Deviaphan
1283 / 1217 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
03.12.2012, 17:43     "Двойной" доступ к переменным класса #15
Аргументирую: ты хочешь реализовать переключение типов, а в ООП переключение типов - зло. буст.вариант лучше тем, что его сотни тысяч раз использовали и отлаживали.
Вопрос в другом: зачем тебе индексированный доступ к объектам РАЗНОГО типа. Ты не сможешь работать с ними в цикле, значит, тебе не нужен индексированный доступ. Если же ты хочешь однообразно работать с ними в цикле, то у них должен быть общий предок и решение твоей проблемы - полиморфизм.
scriptus
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 изначально и данного вопроса бы не стояло.
Deviaphan
Делаю внезапно и красиво
Эксперт C++
 Аватар для Deviaphan
1283 / 1217 / 50
Регистрация: 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;
}
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
03.12.2012, 19:33     "Двойной" доступ к переменным класса
Еще ссылки по теме:

C++ Работа со структурами, "Двойной список"
C++ Два класса: "Студент" и "Курс"
Разработать класс "студенческая группа". Предусмотреть возможность работы с переменным числом студентов C++

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

Или воспользуйтесь поиском по форуму:
scriptus
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 минуту
Невинная фантазия на данную тему. Только тебе не подойдёт, скорее всего, потому что состав объектов другой получился
Да, фантазия интересная. И да, не пойдет
Yandex
Объявления
03.12.2012, 19:33     "Двойной" доступ к переменным класса
Ответ Создать тему
Опции темы

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