MFC中POSITION类详解

来源:互联网 发布:萧山网络问政供电局 编辑:程序博客网 时间:2024/06/16 07:11

本文转载自:

POSITION用法解释

VC6.0 MFC中:POSITION用法解释

MFC中POSITION究竟是一个什么类型,CStringList类解释

关于MFC的POSITION


------------------------------------------------------------------------------------------------

来源:POSITION用法解析

POSITION是MFC模板类库中经常使用的一个数据类型,我们从它的定义可以看出,其实,它就是一个指针。

// abstract iteration position
struct __POSITION { };
typedef __POSITION* POSITION;
MFC给出的注释是:一个抽象的迭代位置,既然是抽象,也就是没有给定具体的数据类型,以满足不同的模板参数的需要。
在CList中,经常会用到POSITION作为引用参数,或者作为返回值。下面,我们就举2个简单的例子,来帮助大家理解这个数据类型,不过在此之前,我要啰嗦一下,因为有很多人对__POSITION这个空结构体,表示怀疑,似乎这成为了他们理解的障碍。既然是一个空的结构体,怎么能用它来定义指针呢?
其实,C++编译器,不会将一个空的结构体完全看成是空的,编译器会为它分配1byte的内存,其实说白了__POSITION这个结构体,就相当于一个unsigned char的类型,所以__POSITION也就相当于是unsigned char,也就是Windows里面的BYTE类型,从而POSITION也就有了一个可以等价的形式,那就是BYTE*。
我们举CList中2个典型的成员函数作为讲解的重点,当然,大家应该知道CList是一个链表数据结构。下面看这两个函数:
1. POSITION GetHeadPosition() const;
显而易见,这个函数,是用来获取链表头的,它的返回值是一个POSITION,其实也就是一个指针。这个指针代表了谁?当然,就是你一直想要的链表头在链表中的指针,这个指针是new出来的,你绝对不能擅自的将这个指针delete掉。
2. TYPE& GetAt(POSITION position);
这个函数,看起来,比较怪。它的唯一的入参是一个指针,其实,有可能就是你刚刚用GetHeadPosition获得的头节点指针。这个函数的意思,也就是,需要你提供一个节点的地址,然后,CList会遍历整条链,去寻找并返回符合这个地址的节点数据。
废话了那么多,一言以蔽之,毕其功于一役,换句话说就是:
POSITION,你可以把它看成是一个学号,有了它,你就可以找到任何一个班里的学生。
POSITION在MFC里用来存放各种List或Array对象的索引,便于在遍历时标识元素的位置。其实就是一个32位值,其内容可能是一个指针,或是数组的Index。


------------------------------------------------------------------------------------------------

来源:VC6.0 MFC中:POSITION用法解释

VC的基本头文件AFX.h里对POSITION是这样定义的: 
struct __POSITION { }; 
typedef __POSITION* POSITION 
显然这里定义了一个没有任何字段的结构体,而POSITION是这个结构体的指针。 
VC在使用CList时,一些函数往往用POSITION参数,或者返回POSITION类型,其实查看CList的原代码就知道,原来CList返回的POSITION就是它的链表的一个结点指针,也就是说,在CList里有一个CNode的类定义了结点,而POSITION就是CNode* 
所以说,虽然__POSITION结构体没有任何字段,但用POSITION结构体指针,仅仅用来表达CNode*指针,并且是强制转换过来的。于是POSITION被VC用为一种常见的数据类型---32位指针。

下面是CList中它的用法 
AFX_INLINE   TYPE&   CList <TYPE,   ARG_TYPE> ::GetNext(POSITION&   rPosition)   //   
{   
  CNode*   pNode   =   (CNode*)   rPosition; 
  ASSERT(AfxIsValidAddress(pNode,   sizeof(CNode))); 
  rPosition   =   (POSITION)   pNode-> pNext; 
  return   pNode-> data; 
} 

试了试空结构,很奇怪 
struct   SS{}; 
SS   s={0};     会分配4字节内存做s变量,但并不初始化这4字节为0 
int   b=sizeof(SS);   为1 
 
在MFC4.0以前的版本中,POSITION实际上就是一个void指针。在5.0中的定义大概是: 
struct   __POSITION   {   int   unused;   }   ; 
typedef   __POSITION   *   POSITION   ; 
6.0中才变为: 
struct   __POSITION   {     }   ; 
typedef   __POSITION   *   POSITION   ; 
虽然结构内没有成员变量,但指向结构的指针仍需要4字节----32位机中天下的指针都是这个长度滴! 
这样做的目的仅是为了类型安全。对于POSITION参数,使用者很容易传错,特别是当表中元素是void   *时,此时很有可能在需要元素的地方传入POSITION,而在需要POSITION的地方传入void   *。当做上面的定义中,编译器就可以检查出这种错误。 
在MFC内部,POSITION实际上指向CNode类型。

---------------------------------------------------------------------------------------------------
来源:MFC中POSITION究竟是一个什么类型:CStringList类解释
下面是MFC的源代码,从CSDN的帖子中找到的,很好的共同学习、共同进步的门户啊。谢谢很多无私的人们!!mfc中position究竟是一什么样的类型,cstringlist类(转)
//   abstract   iteration   position  
  struct   __POSITION   {   };  
  typedef   __POSITION*   POSITION;
CStringList的声明:  
  ...  
  protected:  
  struct   CNode  
  {  
  CNode*   pNext;  
  CNode*   pPrev;  
  CString   data;  
  };  
   
  CStringList的GetAt实现:  
  _AFXCOLL_INLINE   CString&   CStringList::GetAt(POSITION   position)  
  {   CNode*   pNode   =   (CNode*)   position;  
  ASSERT(AfxIsValidAddress(pNode,   sizeof(CNode)));  
  return   pNode->data;   }  
   
  所以POSITION实际就是一个指针,必要时MFC会把它转型为指向node的指针。
   
    _AFXCOLL_INLINE   CString&   CStringList::GetNext(POSITION&   rPosition)  
  {   CNode*   pNode   =   (CNode*)   rPosition;  
  ASSERT(AfxIsValidAddress(pNode,   sizeof(CNode)));  
  rPosition   =   (POSITION)   pNode->pNext;  
  return   pNode->data;   }
 
下面这个例子几乎用到cstringlist类所有的函数
CStringList var(15);

         POSITION position;
         position =         var.InsertAfter(NULL,"item1");
         position =  var.InsertAfter(position,"item3");
         position =  var.InsertBefore(position,"item2");
         for( position = var.GetHeadPosition(); NULL != position ; )
                  AfxMessageBox(var.GetNext(position));
         for( position = var.GetTailPosition(); NULL != position ;var.GetPrev(position))
         {
                   CString str;
                   str = var.GetAt(position);
                  if("item3"==str)
                   {
                            var.RemoveAt(position);
                   }
                   else
                   {
                            str.MakeUpper();
                            var.SetAt(position,str);
                   }
         }
         var.RemoveHead();
         var.RemoveTail();
         var.RemoveAll();
         var.AddHead("he");
         var.AddTail("dan");
         position = var.Find("he");
         var.SetAt(position,"He");
         position = var.FindIndex(1);
         var.SetAt(position,"Dan");
//end 

下面是该类函数的简介

POSITION InsertBefore( POSITION position, CObject* newElement );
POSITION InsertAfter( POSITION position, CObject* newElement );
在一个位置前或后插入一个新元素.

POSITION GetHeadPosition( ) const;
POSITION GetTailPosition( ) const;
获得头位置和尾位置.

CObject*& GetNext( POSITION& rPosition );
CObject* GetNext( POSITION& rPosition ) const;
CObject*& GetPrev( POSITION& rPosition );
CObject* GetPrev( POSITION& rPosition ) const;
获得后一元素或前一元素,注意rPosition会变.

CObject*& GetAt( POSITION position );
CObject* GetAt( POSITION position ) const;
根据位置得到元素.

void SetAt( POSITION pos, CObject* newElement );
根据位置设置元素.

void RemoveAt( POSITION position );
根据位置删除元素.

CObject* RemoveHead( );删除并返回头元素
CObject* RemoveTail( ); 删除并返回尾元素

POSITION AddHead( CObject* newElement );增加头元素
void AddHead( CObList* pNewList );在前面加一个表
POSITION AddTail( CObject* newElement );增加尾元素
void AddTail( CObList* pNewList );在后面加一个表
POSITION Find( CObject* searchValue, POSITION startAfter = NULL ) const根据元素值找位置.
POSITION FindIndex( int nIndex ) const根据索引找位置.


--------------------------------------------------------------------------------------------------

来源:关于MFC的POSITION

struct __POSITION {};

typedef __POSITION* POSITION;

从这两句代码可以看出POSITION实质是一个空结构体的指针。


疑问一:为什么不用迭代器做指针?

STL相对于MFC来说是晚辈,所以不要指望MFC的工程师会继承迭代器的一切思想。


疑问二:为什么不用void* ?

这样做的目的是为了类型安全。对于POSITION参数,使用者很容易传错,特别是当表中元素是void   *时,此时很有可能在需要元素的地方传入POSITION,而在需要POSITION的地方传入void   *。当做上面的定义中,编译器就可以检查出这种错误。 

事实上在MFC4.0之前,POSITION是一个void指针。

在MFC5.0中,POSITION是

struct __POSITION { int unused; };

typedef __POSITION* POSITION;

0 0
原创粉丝点击