Cоздание простого шаблона не помогает по причине того, что копировать STR255 нужно будет не
m_pArray[i]=pArray[i]
а
*m_pArray[i]=*pArray[i]
не говоря уже о сравнении в методе RemoveItem.
Cоздание базового темплейта с виртуальными функциями
void CopyItem(TYPE* pdst, TYPE src)
BOOL СompareItems(TYPE item1, TYPE item2)
переопределенными в темлейтах TArrayValue и TArrayPointer не очень хорошо, т.к. сгенерится
много классов (ведь так? =), что нежелательно из-за большого обема.
Мое решение:
typedef unsigned char* PBYTE;
class CArrayBase
{
protected:
CArrayBase();
virtual ~CArrayBase;
InitArray ( int NumItems, PBYTE* pArray ); // создает массив
RemoveItem( PBYTE Item ); // удалить элемент массива со значением Itemvirtual void CopyItem(PBYTE* pdst, PBYTE src) {};
virtual BOOL CompareItems(PBYTE item1, PBYTE item2) {return TRUE;};
PBYTE* m_pArray;
int m_TypeSize; // реальный размер того что передается через PBYTE
// в моей реальной задаче это в любом случае надо, для других целей..
};
template <class TYPE, int TYPE_SIZE>
class TArrayPointer: public CArrayBase // темплейт для ряботы с указателями (STR255 и RECT*)
{
public:
CArrayBase() {m_TypeSize=TYPE_SIZE;}
virtual void CopyItem(PBYTE* pdst, PBYTE src)
{ **((TYPE*)pdst)=*(*(TYPE*)&src) };
virtual BOOL CompareItems(PBYTE item1, PBYTE item2)
{ return _strnicmp((LPCSTR)item1,(LPCSTR)item2,__TYPE_SIZE); };
};
// ну и по такому же принципу темплэйт TArrayValue для работы с UINT
Пожалуйста, расскажите как такую задачу спроектировать лучше?
typedef unsigned char* PBYTE;
class CArrayBase
{
protected:
CArrayBase();
virtual ~CArrayBase;
public:
void InitArray ( int NumItems, PBYTE* pArray ); // создает массивvoid RemoveItem( PBYTE Item ); // удалить элемент массива со значением Itemprotected:
virtual void CopyItem(PBYTE* pdst, PBYTE src) {};
virtual BOOL CompareItems(PBYTE item1, PBYTE item2) {return TRUE;};
PBYTE* m_pArray;
int m_TypeSize; // реальный размер того что передается через PBYTE
// в моей реальной задаче это в любом случае надо, для других целей..
};
template <class TYPE, int TYPE_SIZE>
class TArrayPointer: public CArrayBase // темплейт для ряботы с указателями (STR255 и RECT*)
{
public:
CArrayBase() {m_TypeSize=TYPE_SIZE;}
void InitArray ( int NumItems, TYPE* pArray )
{ CArrayBase::RemoveItem((PBYTE*) pArray); }
void RemoveItem( TYPE Item );
{ CArrayBase::RemoveItem((PBYTE) Item);
protected:
virtual void CopyItem(PBYTE* pdst, PBYTE src)
{ **((TYPE*)pdst)=*(*(TYPE*)&src) };
virtual BOOL CompareItems(PBYTE item1, PBYTE item2)
{ return _strnicmp((LPCSTR)item1,(LPCSTR)item2,__TYPE_SIZE); };
};
// ну и по такому же принципу темплэйт TArrayValue для работы с UINT
inline void ::Copy(CHAR255& dest, const CHAR255& source)
{
for (int i=0; i<255; i++) // лучше пользоваться чем-то более оптимальным, но это не важно
dest[i] = source[i]; // поэлементное копирование
}
тогда при подстановке в шаблон твоего массива CHAR255 автоматически будет выбрана более специализированная версия ::Copy.
Такой подход потребует специализировать Copy для всех случаев, когда тривиального опреатора = недостаточно. Я не гуру в плюсах, так что такой вариант может не сработать:
S>тогда при подстановке в шаблон твоего массива CHAR255 автоматически будет выбрана более специализированная версия ::Copy.
S>Такой подход потребует специализировать Copy для всех случаев, когда тривиального опреатора = недостаточно.
Здравствуйте, alexanderfedin, Вы писали:
A>сделай: A>
A>template <typename _Ty, typename _Traits = DefaultTraits>
A>class CArrayClass
A>{
A> friend class _Traits;
A> ...
A> static void copy(_Ty *pDst, const _Ty &src)
A> {
A> _Traits::copy(pDst, src);
A> }
A> static bool compare(const _Ty &lhs, const _Ty &rhs)
A> {
A> return _Traits::compare(lhs, rhs);
A> }
A>};
A>
A>никакой виртуальности, работает быстро.
Спасибо! Но я ничего не понял =))
т.е. обойтись совсем без базового класса (тот, который оперирует PBYTE)? Тогда будет 15 классов (типов же 15), мне это не нравится =((
а _Traits это что? интерфейс? и два (DefaultTraits, PointerTraints) класса с ним?
В любом случае мне нужно будет передавать этот T в базовый класс, и в итоге опять получится 15 классов =(( потому что надо реализовать T& operator [](int) и т.п.
template <_class _T>
class Array
{
public:
void insertItem(_T&);
};
в этом случае (да и впервом) клиенту не надо знать о наличии класса ArrayValue, главное чтобы твои типы были оборудованы операторами сравнения, копирования и т.д.
В случае номер 1 — даже этого не обязательно все делает класс ArrayValue
Веру-ю-у! В авиацию, в научную революци-ю-у, в механизацию сельского хозяйства, в космос и невесомость! Веру-ю-у! Ибо это объективно-о! (Шукшин)
Здравствуйте, glut, Вы писали:
>>т.е. обойтись совсем без базового класса (тот, который оперирует PBYTE)? >>Тогда будет 15 классов (типов же 15), мне это не нравится =((
а у тебя настолько разные типы, с которыми нужно оперировать?
_Traits — это класс настройки на конкретные особенности типа, то есть здесь
он определяет операции по копированию и сравнению экземпляров.
В общем случае это будет
если тебе нужна независимость класса CArrayClass от обрабатываемых типов,
тогда примени метафункции — будешь по-прежнему обходиться без накладных
расходов на вызов виртуальных функций, что с поддержкой компилятором inline
подстановки даст тебе быстродействие прямого использования необходимых
алгоритмов для соотвествующих типов.
С уважением,
Александр Федин (AlexanderFedin@iname.com)
Здравствуйте, alexanderfedin, Вы писали:
>>>т.е. обойтись совсем без базового класса (тот, который оперирует PBYTE)? >>>Тогда будет 15 классов (типов же 15), мне это не нравится =((
A>а у тебя настолько разные типы, с которыми нужно оперировать?
нет, просто я подумал что _DefaultTraits<int> и _DefaultTraits<char> это будет два разных типа, и соответственно TArrayBase<int, _DefaultTraits<int> > и СArrayСlass<char, _DefaultTraits<char> > будет тоже два разных класса и в итоге получится 15 (там int, char, short и т.п) классов.. Или я не прав? если не прав, то почему?
A>_Traits — это класс настройки на конкретные особенности типа, то есть здесь A>он определяет операции по копированию и сравнению экземпляров.
A>В общем случае это будет A>
A>template <typename _Ty>
A>struct _DefaultTraits
A>{
A> static void copy(_Ty *dst, const _Ty &src) {SKIP}
A> static bool compare(const _Ty &lhs, const _Ty &rhs) {SKIP}
A>};
A>
A>Для примитивных типов операции копирования и сравнения определены языком. A>Для типа массива напиши что-то типа: A>используй так: A>[code] A>template <typename _Ty, typename _Traits = _DefaultTraits> A>class CArrayClass A>{ A> friend class _Traits;
A> static void copy(_Ty *dst, const _Ty &src) A> { A> _Traits::copy(dst, src); A> }
A> static bool compare(const _Ty &lhs, const _Ty &rhs) A> { A> return _Traits::compare(lhs, rhs); A> } A>};
А Почему _DefaultTraits без <> ? А разве CArrayClass<int> и CArrayClass<char> не сгенерят два разных класса?
A>если тебе нужна независимость класса CArrayClass от обрабатываемых типов, A>тогда примени метафункции — будешь по-прежнему обходиться без накладных A>расходов на вызов виртуальных функций, что с поддержкой компилятором inline A>подстановки даст тебе быстродействие прямого использования необходимых A>алгоритмов для соотвествующих типов.
Метафункции это кто?
Большое спасибо за все эти указания, но боюсь я все же тупой или просто чего-то другого не понимаю. Я был бы очень признателен если б мне показали, как TypeTraits и т.п. применить конкретно к моей задаче, т.е. код(определения классов) в котором есть класс c InitArray и RemoveItem и который умеет оперировать тремя описаными мной данными.
В моем решении, помимо виртуальных функций мне не нравится, что для того чтобы не делать 15 классов с RemoveItem и InitArray приходится оперировать PBYTE. Без PBYTE можно обойтись?
поправил..
G>нет, просто я подумал что _DefaultTraits<int> и _DefaultTraits<char> это будет два разных типа, и соответственно CArrayClass<int, _DefaultTraits<int> > и СArrayСlass<char, _DefaultTraits<char> > будет тоже два разных класса и в итоге получится 15 (там int, char, short и т.п) классов.. Или я не прав? если не прав, то почему?