分享

CArchive类体内的友元操作符重载函数的研究

 戴维图书馆 2017-08-01
  为什么把CArchive类体内的三个操作符重载函数声明为友元的,而不是类成员函数呢?

    对于CString CRect CSize CPoint 类它们有自己对于CArchive的<<和>>操作符重载函数并将这些操作符重载函数声明为全局友元函数,原因是如果操作符重载函数是类成员函数的话,那么对于2元操作符来说,左操作数默认为该类对象,参照这些函数的定义我们发现左操作数类型都不是该类对象,所以这些操作重载函数不能是类成员函数,必须是全局函数了,在类体内对一个函数加上友元关键字就表示此函数不是类成员函数,而是一个全局函数,所以在这里声明友元函数的意思就是告诉编译器和我们这个函数不是类成员函数,而是一个全局函数.这是第一个原因,第二个原因就是我马上要提到的CArchive类体内的三个操作符重载函数为什么也必须是友元的了。

    查看CArchive的类定义,我们发现对于普通数据类型的操作符重载函数,CArchive是声明为类成员函数的,但是还是有三个操作符重载函数是友元的,所以这三个函数是全局函数,按照我刚刚的道理来说,这里左操作数类型就是CArchive对象引用,为什么要把这三个函数声明为友元的呢,答案是为了实现函数重载,注意这里是函数重载不是操作符重载,这三个友元操作符重载函数的声明如下:

friend CArchive& AFXAPI operator<<(CArchive& ar, const CObject* pOb);
friend CArchive& AFXAPI operator>>(CArchive& ar, CObject*& pOb);
friend CArchive& AFXAPI operator>>(CArchive& ar, const CObject*& pOb);
都是全局域的函数,需要和什么函数构成重载呢?答案是和前面提到的CString、CRect、CSize、CPoint类,它们都针对CArchive 的<< 和>> 自己设计了一套函数方法如下:

friend CArchive& AFXAPI operator<<(CArchive& ar, const CString& string);
friend CArchive& AFXAPI operator>>(CArchive& ar, CString& string)
CArchive& AFXAPI operator<<(CArchive& ar, SIZE size);
CArchive& AFXAPI operator<<(CArchive& ar, POINT point);
CArchive& AFXAPI operator<<(CArchive& ar, const RECT& rect);
CArchive& AFXAPI operator>>(CArchive& ar, SIZE& size);
CArchive& AFXAPI operator>>(CArchive& ar, POINT& point);
CArchive& AFXAPI operator>>(CArchive& ar, RECT& rect);

参考书---深入浅出MFC 2e 第8章 Document-View深入讨论(整章)
      ---C++ Primer 3rd 第15章 15.1节 操作符重载 和 15.2节 友元

关于MFC中的DECLARE_SERIAL宏展开后的
AFX_API friend CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb);操作符重载函数声明
和 IMPLEMENT_SERIAL宏展开的
CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb) /
        { pOb = (class_name*) ar.ReadObject(RUNTIME_CLASS(class_name)); /
            return ar; } /操作符重载函数的定义
我的测试结果是这个操作符重载函数至少在深入浅出MFC 2e Document-View深入讨论那章中的程序举例中根本不会被调用
被调用的是
AFX_INLINE CArchive& AFXAPI operator>>(CArchive& ar, CObject*& pOb)
    { pOb = ar.ReadObject(NULL); return ar; }
这个CArchive 内声明为友元全局操作符重载函数
可以做如下测试把这对宏改为如下方式:并放置与头文件StdAfx.h中(注意这对宏我加字母串最后我加了'A')
来和MFC定义的这对宏用于区分。测试程序没有任何问题,读取和写入文件都没有错误
同时从下面测试更改也看的出 和 _DECLARE_DYNCREATE那对宏比较
IMPLEMENT_SERIALA在这里唯一与_DECLARE_DYNCREATE那对宏不同的就是指定串型类的版本号
放入了CRuntimeClass结构体成员变量UINT m_wSchema中

#define IMPLEMENT_SERIALA(class_name, base_class_name, wSchema) /
    CObject* PASCAL class_name::CreateObject() /
        { return new class_name; } /
    _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, /
        class_name::CreateObject) /
    AFX_CLASSINIT _init_##class_name(RUNTIME_CLASS(class_name)); /
    
#define DECLARE_SERIALA(class_name) /
    _DECLARE_DYNCREATE(class_name) /

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多