MFC的容器虽然实现了基本的功能,但是有些比较常用的并没有直接提供给我们,比如查找,排序.通常,作这些操作都要我们自己去实现,可这样作,时间,效率,可靠性,都会超支.如果可以将STL的查找,排序算法应用到MFC上,那将是一件很愉快的事. 查找,排序对容器有一定的要求,即iterator,如果实现了MFC容器相对应的iterator,问题自然解开. 下面顺序制作Array和List的迭代器.
一. Array是最基本的容器,在一块连续的空间上构造对象序列. CArray提供了一个函数GetData(),使得我们可以访问这块空间. STL对于基本数组提供了支持,所以,我们可以直接使用这块空间的指针当Iterator.
CDWordArray arr;
arr.Add( 1 );
arr.Add( 2 );
arr.Add( 3 );
arr.Add( 4 );
DWORD* posBegin = arr.GetData();
DWORD* posEnd = arr.GetData() + arr.GetSize();
DWORD* posFind = std::find( posBegin, posEnd, 3 );
DWORD dwVal = *posFind;
ASSERT( dwVal == 3 );
对于CArray也可以这样作. 以下是我封装的辅助类.
//////////////////////////////////////////////////////////////////////////
// *****QQQ******* W******W******W EEEEEEEEEEEEEEE RRRRRRRRRRRRR**
// ***QQ***QQ***** WW****WWW****WW EE************* RR********RRRRR
// *QQ*******QQ*** *WW**WW*WW**WW* EE************* RR******RRRRR**
// QQ****Q****QQ** *WW**WW*WW**WW* EEEEEEEEEEEEEEE RR****RRRRR****
// *QQ****QQ*QQ*** *WW**WW*WW**WW* EEEEEEEEEEEEEEE RR**RRRR*******
// **QQ*****QQ**** *WW**WW*WW**WW* EE************* RRRR***********
// ***QQ***QQ*QQ** **W**W***W**W** EE************* RR**RRRR*******
// *****QQQ*****QQ ***WW*****WW*** EEEEEEEEEEEEEEE RR****RRRRRRRRR
// Author Terry board
// Email qwer4821@163.com
// Date 2005-7-7 16:28:40
// File MCArrayUtil.hpp
//////////////////////////////////////////////////////////////////////////
#ifndef MCArrayUtil_qwer_
#define MCArrayUtil_qwer_
//////////////////////////////////////////////////////////////////////////
#include <functional>
#include <algorithm>
//////////////////////////////////////////////////////////////////////////
//
//
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
namespace qwer
{
//////////////////////////////////////////////////////////////////////////
template < typename TYPE, typename ARG_TYPE >
class MCArrayUtil
{
public:
typedef TYPE value_type;
typedef TYPE& reference;
typedef const TYPE& const_reference;
typedef TYPE* _Tptr;
typedef const TYPE* _Ctptr;
typedef int size_type;
typedef _Tptr iterator;
typedef _Ctptr const_iterator;
typedef ptrdiff_t difference_type;
typedef std::reverse_iterator<const_iterator, value_type,
const_reference, _Ctptr, difference_type>
const_reverse_iterator;
typedef std::reverse_iterator<iterator, value_type,
reference, _Tptr, difference_type>
reverse_iterator;
//!
typedef ARG_TYPE arg_type;
typedef CArray< TYPE, ARG_TYPE > base_array;
protected:
base_array& m_arrRef;
public:
MCArrayUtil();
MCArrayUtil( base_array& arr )
:m_arrRef(arr)
{
}
MCArrayUtil( const MCArrayUtil& arrUtil )
:m_arrRef( arrUtil.m_arrRef )
{
}
operator = ( const MCArrayUtil& arrUtil );
operator = ( base_array& arr );
public:
_Tptr GetData() const
{
return const_cast< _Tptr >(m_arrRef.GetData());
}
size_type GetSize() const
{
return m_arrRef.GetSize();
}
public:
inline iterator begin( )
{
return GetData();
}
inline const_iterator begin() const
{
return GetData();
}
inline iterator end( )
{
return GetData() + GetSize();
}
inline const_iterator end() const
{
return GetData() + GetSize();
}
inline iterator indexToIterator( size_type nIndex )
{
if ( CheckIndex( nIndex ) )
{
return begin() + nIndex;
}
else
{
return end( );
}
}
inline const_iterator indexToIterator( size_type nIndex ) const
{
if ( CheckIndex( nIndex ) )
{
return begin( ) + nIndex;
}
else
{
return end( );
}
}
inline size_type iteratorToIndex( iterator it )
{
return it - begin();
}
inline size_type iteratorToIndex( const_iterator it ) const
{
return it - begin();
}
inline bool checkIndex( size_type nIndex )
{
return ( nIndex >= 0 && nIndex < GetSize() );
}
size_type find( arg_type val ) const
{
return iteratorToIndex( std::find( begin(), end(), val ) );
}
template < typename Predicate >
size_type find_if( Predicate pre ) const
{
return iteratorToIndex( std::find_if( begin(), end(), pre ) );
}
void sort( )
{
std::sort( begin(), end() );
}
template < typename Predicate >
void sort( Predicate pre )
{
std::sort( begin(), end(), pre );
}
//////////////////////////////////////////////////////////////////////////
size_type size() const
{
return m_arrRef.GetSize();
}
bool empty() const
{
return ( size() > 0 );
}
void push_back( const value_type& val )
{
m_arrRef.Add( val );
}
void push_front( const value_type& val )
{
m_arrRef.InsertAt( 0, val );
}
void pop_front()
{
m_arrRef.RemoveAt( 0 );
}
void pop_back()
{
m_arrRef.RemoveAt( size() - 1 );
}
void clear()
{
m_arrRef.RemoveAll();
}
};
//////////////////////////////////////////////////////////////////////////
template < typename Array, typename TYPE >
class MBaseArray
{
public:
typedef TYPE value_type;
typedef TYPE& reference;
typedef const TYPE& const_reference;
typedef TYPE* _Tptr;
typedef const TYPE* _Ctptr;
typedef int size_type;
typedef _Tptr iterator;
typedef _Ctptr const_iterator;
typedef ptrdiff_t difference_type;
typedef std::reverse_iterator<const_iterator, value_type,
const_reference, _Ctptr, difference_type>
const_reverse_iterator;
typedef std::reverse_iterator<iterator, value_type,
reference, _Tptr, difference_type>
reverse_iterator;
//!
typedef TYPE arg_type;
typedef Array base_array;
protected:
base_array& m_arrRef;
public:
MBaseArray();
MBaseArray( base_array& arr )
:m_arrRef(arr)
{
}
MBaseArray( const MBaseArray& arrUtil )
:m_arrRef( arrUtil.m_arrRef )
{
}
operator = ( const MBaseArray& arrUtil );
operator = ( base_array& arr );
public:
_Tptr GetData() const
{
return const_cast< _Tptr >(m_arrRef.GetData());
}
size_type GetSize() const
{
return m_arrRef.GetSize();
}
public:
inline iterator begin( )
{
return GetData();
}
inline const_iterator begin() const
{
return GetData();
}
inline iterator end( )
{
return GetData() + GetSize();
}
inline const_iterator end() const
{
return GetData() + GetSize();
}
inline iterator indexToIterator( size_type nIndex )
{
if ( CheckIndex( nIndex ) )
{
return begin( ) + nIndex;
}
else
{
return end( );
}
}
inline const_iterator indexToIterator( size_type nIndex ) const
{
if ( CheckIndex( nIndex ) )
{
return begin( ) + nIndex;
}
else
{
return end( );
}
}
inline size_type iteratorToIndex( iterator it )
{
return it - begin();
}
inline size_type iteratorToIndex( const_iterator it ) const
{
return it - begin();
}
inline bool checkIndex( size_type nIndex )
{
return ( nIndex >= 0 && nIndex < GetSize() );
}
size_type find( arg_type val ) const
{
return iteratorToIndex( std::find( begin(), end(), val ) );
}
template < typename Predicate >
size_type find_if( Predicate pre ) const
{
return iteratorToIndex( std::find_if( begin(), end(), pre ) );
}
void sort( )
{
std::sort( begin(), end() );
}
template < typename Predicate >
void sort( Predicate pre )
{
std::sort( begin(), end(), pre );
}
};
//////////////////////////////////////////////////////////////////////////
typedef MBaseArray< CByteArray, BYTE > MCByteArray;
typedef MBaseArray< CWordArray, WORD > MCWordArray;
typedef MBaseArray< CUIntArray, UINT > MCUIntArray;
typedef MBaseArray< CDWordArray, DWORD > MCDWordArray;
typedef MBaseArray< CStringArray, CString > MCStringArray;
//////////////////////////////////////////////////////////////////////////
template < typename Array >
class MBaseArrayUtil
{
};
template<>
class MBaseArrayUtil< CByteArray > : public MCByteArray
{
public:
typedef MCByteArray base_class;
public:
MBaseArrayUtil( base_array& arr )
:base_class( arr )
{
}
MBaseArrayUtil( const MBaseArrayUtil& arr )
:base_class( arr )
{
}
};
template<>
class MBaseArrayUtil< CWordArray > : public MCWordArray
{
public:
typedef MCWordArray base_class;
public:
MBaseArrayUtil( base_array& arr )
:base_class( arr )
{
}
MBaseArrayUtil( const MBaseArrayUtil& arr )
:base_class( arr )
{
}
};
template<>
class MBaseArrayUtil< CUIntArray > : public MCUIntArray
{
public:
typedef MCUIntArray base_class;
public:
MBaseArrayUtil( base_array& arr )
:base_class( arr )
{
}
MBaseArrayUtil( const MBaseArrayUtil& arr )
:base_class( arr )
{
}
};
template<>
class MBaseArrayUtil< CDWordArray > : public MCDWordArray
{
public:
typedef MCDWordArray base_class;
public:
MBaseArrayUtil( base_array& arr )
:base_class( arr )
{
}
MBaseArrayUtil( const MBaseArrayUtil& arr )
:base_class( arr )
{
}
};
template<>
class MBaseArrayUtil< CStringArray > : public MCStringArray
{
public:
typedef MCStringArray base_class;
public:
MBaseArrayUtil( base_array& arr )
:base_class( arr )
{
}
MBaseArrayUtil( const MBaseArrayUtil& arr )
:base_class( arr )
{
}
public:
struct FindorNoCase : public std::binary_function< CString, CString, bool >
{
bool operator () ( const CString& strL, const CString& strR ) const
{
return ( strL.CompareNoCase( strR ) == 0 );
}
};
public:
size_type FindNoCase( LPCTSTR str ) const
{
return find_if( std::bind2nd(FindorNoCase(), str ) );
}
};
//////////////////////////////////////////////////////////////////////////
typedef MBaseArrayUtil< CByteArray > MCByteArrayUtil;
typedef MBaseArrayUtil< CWordArray > MCWordArrayUtil;
typedef MBaseArrayUtil< CUIntArray > MCUIntArrayUtil;
typedef MBaseArrayUtil< CDWordArray > MCDWordArrayUtil;
typedef MBaseArrayUtil< CStringArray > MCStringArrayUtil;
//////////////////////////////////////////////////////////////////////////
} //end namespace qwer
//////////////////////////////////////////////////////////////////////////
#endif
但是对于 CTypedPtrArray ,由于元素是指针,查找和排序的实现,需要依赖于functor. 如果不想编写特殊的functor,而是希望借用已有的或者编译器支持的operator等,设计一个Adaptor是必需的.以下代码对操作于指针对象上的functor进行封装.
//! argument_type of unary functor is pointer
template < typename UnaryFunctor >
struct unary_ptr_function : public std::unary_function< UnaryFunctor::argument_type*, UnaryFunctor::result_type >
{
protected:
UnaryFunctor& m_funcRef;
public:
result_type operator () ( argument_type arg ) const
{
return m_funcRef(*arg);
}
unary_ptr_function( UnaryFunctor& func )
:m_funcRef(func)
{
}
};
//! first_argument_type of binary functor is pointer
template < typename BinaryFunctor>
struct binary_ptr1st_function : public std::binary_function< BinaryFunctor::first_argument_type*,
BinaryFunctor::second_argument_type,
BinaryFunctor::result_type >
{
protected:
BinaryFunctor& m_funcRef;
public:
result_type operator () ( first_argument_type arg1, second_argument_type arg2 ) const
{
return m_funcRef( *arg1, arg2 );
}
binary_ptr1st_function( BinaryFunctor& func )
:m_funcRef( func )
{
}
};
//! second_argument_type of binary functor is pointer
template < typename BinaryFunctor>
struct binary_ptr2nd_function : public std::binary_function< BinaryFunctor::first_argument_type,
BinaryFunctor::second_argument_type*,
BinaryFunctor::result_type >
{
protected:
BinaryFunctor& m_funcRef;
public:
result_type operator () ( first_argument_type arg1, second_argument_type arg2 ) const
{
return m_funcRef( arg1, *arg2 );
}
binary_ptr2nd_function( BinaryFunctor& func )
:m_funcRef( func )
{
}
};
//! first_argument_type and second_argument_type of binary functor is pointer
template < typename BinaryFunctor>
struct binary_ptr_function : public std::binary_function< BinaryFunctor::first_argument_type*,
BinaryFunctor::second_argument_type*,
BinaryFunctor::result_type >
{
protected:
BinaryFunctor& m_funcRef;
public:
result_type operator () ( first_argument_type arg1, second_argument_type arg2 ) const
{
return m_funcRef( *arg1, *arg2 );
}
binary_ptr_function( BinaryFunctor& func )
:m_funcRef( func )
{
}
};
//! unary functor bindor
template < typename UnaryFunctor >
unary_ptr_function< UnaryFunctor > BindUnaryPtrFunc( UnaryFunctor& func )
{
return unary_ptr_function<UnaryFunctor>(func);
};
template < typename BinaryFunctor >
binary_ptr1st_function< BinaryFunctor > BindBinaryPtrFunc1st( BinaryFunctor& func )
{
return binary_ptr1st_function< BinaryFunctor >( func );
}
template < typename BinaryFunctor >
binary_ptr2nd_function< BinaryFunctor > BindBinaryPtrFunc2nd( BinaryFunctor& func )
{
return binary_ptr2nd_function< BinaryFunctor >( func );
}
template < typename BinaryFunctor >
binary_ptr_function< BinaryFunctor > BindBinaryPtrFunc( BinaryFunctor& func )
{
return binary_ptr_function< BinaryFunctor >( func );
}
有了以上这些Adaptor,实现CTypedPtrArray的查找,排序就非常容易了.
//////////////////////////////////////////////////////////////////////////
// *****QQQ******* W******W******W EEEEEEEEEEEEEEE RRRRRRRRRRRRR**
// ***QQ***QQ***** WW****WWW****WW EE************* RR********RRRRR
// *QQ*******QQ*** *WW**WW*WW**WW* EE************* RR******RRRRR**
// QQ****Q****QQ** *WW**WW*WW**WW* EEEEEEEEEEEEEEE RR****RRRRR****
// *QQ****QQ*QQ*** *WW**WW*WW**WW* EEEEEEEEEEEEEEE RR**RRRR*******
// **QQ*****QQ**** *WW**WW*WW**WW* EE************* RRRR***********
// ***QQ***QQ*QQ** **W**W***W**W** EE************* RR**RRRR*******
// *****QQQ*****QQ ***WW*****WW*** EEEEEEEEEEEEEEE RR****RRRRRRRRR
// Author Terry board
// Email qwer4821@163.com
// Date 2005-7-18 15:13:30
// File MPtrArrayUtil.hpp
//////////////////////////////////////////////////////////////////////////
#ifndef MPtrArrayUtil_qwer_
#define MPtrArrayUtil_qwer_
#include <MSTLFunctor.hpp>
//////////////////////////////////////////////////////////////////////////
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) if((p) != NULL) {delete (p); (p) = NULL;}
#endif //!SAFE_DELETE
//////////////////////////////////////////////////////////////////////////
//
//
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
namespace qwer
{
//////////////////////////////////////////////////////////////////////////
//! CTypedPtrArray 辅助类, 实现iterator,find,sort
//! Array 为 CPtrArray 或者 CObjArray, ClassType 为元素的值类型(不是指针)
template < typename Array, typename ClassType >
class MPtrArrayUtil
{
public:
typedef ClassType ElementValueType;
typedef ElementValueType* TYPE;
typedef TYPE value_type;
typedef TYPE& reference;
typedef const TYPE& const_reference;
typedef TYPE* _Tptr;
typedef const TYPE* _Ctptr;
typedef int size_type;
typedef _Tptr iterator;
typedef _Ctptr const_iterator;
typedef ptrdiff_t difference_type;
typedef std::reverse_iterator<const_iterator, value_type,
const_reference, _Ctptr, difference_type>
const_reverse_iterator;
typedef std::reverse_iterator<iterator, value_type,
reference, _Tptr, difference_type>
reverse_iterator;
//!
typedef TYPE arg_type;
typedef Array base_array;
protected:
base_array& m_arrRef;
public:
MPtrArrayUtil();
MPtrArrayUtil( base_array& arr )
:m_arrRef(arr)
{
}
MPtrArrayUtil( const MPtrArrayUtil& arrUtil )
:m_arrRef( arrUtil.m_arrRef )
{
}
operator = ( const MPtrArrayUtil& arrUtil );
operator = ( base_array& arr );
public:
_Tptr GetData() const
{
return reinterpret_cast< _Tptr >(m_arrRef.GetData());
}
size_type GetSize() const
{
return m_arrRef.GetSize();
}
public:
inline iterator begin( )
{
return GetData();
}
inline const_iterator begin() const
{
return GetData();
}
inline iterator end( )
{
return GetData() + GetSize();
}
inline const_iterator end() const
{
return GetData() + GetSize();
}
inline iterator indexToIterator( size_type nIndex )
{
if ( CheckIndex( nIndex ) )
{
return begin() + nIndex;
}
else
{
return end( );
}
}
inline const_iterator indexToIterator( size_type nIndex ) const
{
if ( CheckIndex( nIndex ) )
{
return begin( ) + nIndex;
}
else
{
return end( );
}
}
inline size_type iteratorToIndex( iterator it )
{
return it - begin();
}
inline size_type iteratorToIndex( const_iterator it ) const
{
return it - begin();
}
inline bool checkIndex( size_type nIndex )
{
return ( nIndex >= 0 && nIndex < GetSize() );
}
size_type find( ElementValueType val ) const
{
return iteratorToIndex( std::find_if( begin(), end(),
qwer::BindUnaryPtrFunc( std::bind2nd( std::equal_to< ElementValueType >(), val ) ) )
);
}
template < typename Predicate >
size_type find_if( Predicate pre ) const
{
return iteratorToIndex( std::find_if( begin(), end(),
qwer::BindUnaryPtrFunc(pre) )
);
}
void sort( )
{
std::sort( begin(), end(), qwer::BindBinaryPtrFunc( std::less<ElementValueType>() ) );
}
template < typename Predicate >
void sort( Predicate pre )
{
std::sort( begin(), end(), qwer::BindBinaryPtrFunc(pre) );
}
//////////////////////////////////////////////////////////////////////////
void DeleteAll()
{
for ( int i = 0; i < m_arrRef.GetSize(); i++ )
{
SAFE_DELETE( m_arrRef[i] );
}
m_arrRef.RemoveAll();
}
void DeleteAt( int nIndex, int nCount = 1 )
{
for ( int i = nIndex; i < min(m_arrRef.GetSize(), nIndex + nCount); i++ )
{
SAFE_DELETE( m_arrRef[i] );
}
m_arrRef.RemoveAt( nIndex, nCount );
}
//////////////////////////////////////////////////////////////////////////
size_type size() const
{
return m_arrRef.GetSize();
}
bool empty() const
{
return ( size() > 0 );
}
void push_back( const value_type& val )
{
m_arrRef.Add( val );
}
void push_front( const value_type& val )
{
m_arrRef.InsertAt( 0, val );
}
void pop_front()
{
m_arrRef.RemoveAt( 0 );
}
void pop_back()
{
m_arrRef.RemoveAt( size() - 1 );
}
void clear()
{
m_arrRef.RemoveAll();
}
//////////////////////////////////////////////////////////////////////////
};
//////////////////////////////////////////////////////////////////////////
} //end namespace qwer
//////////////////////////////////////////////////////////////////////////
#endif
应用举例:
1. 字符串数组类
CStringArray arrTest;
MCStringArrayUtil util(arrTest);
util.FindNoCase( "a" );
2. Array模板类
class CMan : public CObject
{
public:
int m_nWeight; //! uint is g
...
};
typedef qwer::MCArrayUtil< CMan, CMan& > CManArrayUtil;
CManArrayUtil util( m_arrMan );
util.sort();
3. 指针的数组类
typedef CTypedPtrArray< CPtrArray, CMan* > CManPtrArray;
typedef qwer::MPtrArrayUtil< CPtrArray, CMan > CManPtrArrayUtil;
CManPtrArray arrMan;
CManPtrArrayUtil util(arrMan);
arrMan.Add( new CMan(100) );
arrMan.Add( new CMan(10) );
arrMan.Add( new CMan(12) );
qwer::BindUnaryPtrFunc( Functor_5() );
int nIndex = -1;
CMan** posBegin = util.begin();
CManPtrArrayUtil::iterator posEnd = util.end();
CManPtrArrayUtil::iterator posFind = std::find_if( util.begin(), util.end(),
BindUnaryPtrFunc(Functor_5()) );
posFind = std::find_if( util.begin(), util.end(),
BindUnaryPtrFunc( std::bind2nd(std::equal_to< CMan >(),CMan(10)) ) );
nIndex = util.find( CMan(10) );
ASSERT( 1 == nIndex );
util.sort();