Russian Qt Forum
Ноябрь 23, 2024, 20:26 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: template + operator[]  (Прочитано 6821 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Сентябрь 12, 2011, 15:19 »

Добрый день

Созрел template, многовато однотипных классов. Использование (упрощенный пример)

Код
C++ (Qt)
class CUser {
...
CList * mList;
};
 
При этом фактический тип mList может быть напр std::vector <float> или std::vector <double> или другой, и это может меняться в runtime. Поэтому объявлять template в CUser мне не резон. Ладно, сделал так

Код
C++ (Qt)
struct CList {
...
};
 
template <class T>
struct CListVec : public CList, public std::vector <T> {
...
};
 
// теперь я могу написать напр
mList = new CListVec <float>;
 
Но как мне теперь заполучить операторы [], size() для класса CList ?

Спасибо

Записан
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4747



Просмотр профиля WWW
« Ответ #1 : Сентябрь 12, 2011, 15:46 »

dynamic_cast<std::vector<float> *>(mList)->size()
Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
BRE
Гость
« Ответ #2 : Сентябрь 12, 2011, 15:59 »

2 kambala: Вроде этого должно быть достаточно.
Код
C++ (Qt)
mList->size()
(*mList)[ 1 ]
 
Не?

Но как мне теперь заполучить операторы [], size() для класса CList ?
А что там в CList?
« Последнее редактирование: Сентябрь 12, 2011, 16:02 от BRE » Записан
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4747



Просмотр профиля WWW
« Ответ #3 : Сентябрь 12, 2011, 16:10 »

у нас тут не динамический язык Улыбающийся вот в Objective-C подобное бы прокатило.
« Последнее редактирование: Сентябрь 12, 2011, 16:13 от kambala » Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
Akon
Гость
« Ответ #4 : Сентябрь 12, 2011, 16:36 »

У CList есть совпадающие c std::vector функции?
Код:
mList = new CListVec <float>;
int CList_size = static_cast<CList*>(mList)->size();
size_t vector_size = static_cast<std::vector<float>*>(mList)->size();
Записан
SASA
Гость
« Ответ #5 : Сентябрь 12, 2011, 17:36 »

Код
C++ (Qt)
template <class T>
struct CListVec : public CList, public std::vector <T> {
...
};
 
А зачем наследоваться от двух контейнерных классов. Или CList имеет какую-то изощрённую логику?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Сентябрь 12, 2011, 17:45 »

Код
C++ (Qt)
mList->size()
(*mList)[ 1 ]
 
Хотелось бы, но как это сделать?  (как объявить этот оператор в CList)

У CList есть совпадающие c std::vector функции?
Код:
mList = new CListVec <float>;
int CList_size = static_cast<CList*>(mList)->size();
size_t vector_size = static_cast<std::vector<float>*>(mList)->size();
Совпадающих нет, CList делается только как обертка для CListVec. Но как избежать "декодирования", ведь фактический тип может быть разным CListVec.<T>

А зачем наследоваться от двух контейнерных классов. Или CList имеет какую-то изощрённую логику?
CList не контейнер, наследоваться от std::vector необязательно, можно сделать его членом, не суть.
Дело в том что объявлять так
Код
C++ (Qt)
template <class T>
class CUser {
...
 
std::vector <T> * mList;
};
 
мне не подходит, mList должен быть всяким-разным (для одного класса CUser)
Записан
Akon
Гость
« Ответ #7 : Сентябрь 12, 2011, 18:19 »

Код:
class User
{
...
private:
void* mList;  // pointer to vector<int>, vector<float> ...
};

template <typename T>
class TheUser : public User
{
...
public:
const std::vector<T>* mList() const { return static_cast<const std::vector<T>*>(mList); }
};

TheUser<float> floatUser;

Вообще (если с нуля), в базовом контейнере хранятся указатели на элементы (это даст полиморфизм в рантайм), а тонкая шаблонная обертка навешивается на наследников для статического приведения типов интерфейсных функций.
Записан
BRE
Гость
« Ответ #8 : Сентябрь 12, 2011, 18:40 »

Сообразил чего хочется... и как-то пока не представляю как это сделать и вообще возможно ли это сделать...
В классе CUser хочется объявить указатель на класс CList, который будет базовым для списков разных типов и в дальнейшем работать через этот указатель со списком конкретного типа, причем типы списков могут изменяться runtime.
Значит в классе CList должен быть описан весь интерфейс, через который можно работать с элементами. И если описать виртуальный метод size труда не составит, то методы для работы с элементами описать в нем будет просто не возможно - конкретного типа мы еще не знаем.
« Последнее редактирование: Сентябрь 12, 2011, 18:45 от BRE » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #9 : Сентябрь 12, 2011, 18:58 »

Сообразил чего хочется... и как-то пока не представляю как это сделать и вообще возможно ли это сделать...
В классе CUser хочется объявить указатель на класс CList, который будет базовым для списков разных типов и в дальнейшем работать через этот указатель со списком конкретного типа, причем типы списков могут изменяться runtime.
Да, и ситуация не такая уж фантастическая. Есть 2 класса, у одного массив/контейнер float, у другого double, классы знают как эти массивы создавать/заполнять. И есть класс CUser, который умеет с контейнерами что-то делать (напр вычислять среднее). Конечно это условно, для float/double нет смысла городить, просто суть та же. Заметим что если бы mList не требовался как член CUser, то проблем никаких - просто функция-член принимающая template аргумент.

Значит в классе CList должен быть описан весь интерфейс, через который можно работать с элементами. И если описать виртуальный метод size труда не составит, то методы для работы с элементами описать в нем будет просто не возможно - конкретного типа мы еще не знаем.
Ну впарить в mList флажок mType и потом switch - дело нехитрое. Но хочется же цивильно..
Записан
BRE
Гость
« Ответ #10 : Сентябрь 12, 2011, 19:25 »

Ну впарить в mList флажок mType и потом switch - дело нехитрое. Но хочется же цивильно..
Не хитрое?
А как будем менять тип в методах в зависимости от значения флага?
Код
C++ (Qt)
void append( (( mType )? float : double)  item )
 
Записан
BRE
Гость
« Ответ #11 : Сентябрь 12, 2011, 19:47 »

Да, и ситуация не такая уж фантастическая.
Она может и не такая фантастическая, только по моему нормально на C++ не описываемая. Можно воспользоваться чем то типа boost::any, но лучше пересмотреть архитектуру этих классов. Есть стандартные контейнеры и есть стандартные алгоритмы, там все просто и прозрачно.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Сентябрь 12, 2011, 21:33 »

Так, ну один вариант есть

Код
C++ (Qt)
#include <vector>
 
struct CList {
virtual size_t size ( void ) = 0;
virtual double GetDoub ( size_t index ) = 0;
};
 
template <class T>
struct CListVec : public CList {
CListVec( const T & elem ) { mVec.push_back(elem); }
 
virtual size_t size ( void ) { return mVec.size(); }
virtual double GetDoub ( size_t index ) { return mVec[index]; }
 
std::vector <T> mVec;
};
 
int main(int argc, char *argv[])
{
(void) argc;
(void) argv;
CList * vecLst1 = new CListVec <double> (0.123);
CList * vecLst2 = new CListVec <float> (0.456f);
double d1 = vecLst1->GetDoub(0);
double d2 = vecLst2->GetDoub(0);
printf("d1 = %g, d2 = %g, size = %ld\n", d1, d2, vecLst1->size());
return 0;
}
 
Виртуальщина мне не очень нравится, ну да ладно.
По поводу оператора [] я был неправ - мне наоборот, не нужно (нельзя) его иметь, потому что он возвращает ссылку. То есть если данные хранятся как float, то ссылка на double просто ошибка (даже если мне удастся ее взять). Ну со стороны CUser вполне достаточно get/set по индексу
« Последнее редактирование: Сентябрь 12, 2011, 21:34 от Igors » Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.239 секунд. Запросов: 23.