问题:不用AFX_API friend CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb), m_pClassInit = NULL;也可以串行化!
问题等同http://topic.csdn.net/u/20090204/19/d1eadce6-553c-4d49-9a88-1de898a7a219.html,解决后俩个加在一起给予200分
为什么还要要它们,起到什么效果?下面是我简化的可串行化的类:
#pragma once
// CSimple command targetclass CSimple : public CObject
{
public:
 //DECLARE_SERIAL( CSimple )
_DECLARE_DYNCREATE(CSimple)
CSimple();
 virtual ~CSimple();
 CString m_name;
 WORD   m_number; void Serialize( CArchive& archive );
};// Simple.cpp : implementation file
#include "stdafx.h"
#include "TestSDI.h"
#include "Simple.h"CSimple::CSimple()
{
}CSimple::~CSimple()
{
}
//IMPLEMENT_SERIAL( CSimple, CObject, 1 )
CObject* PASCAL CSimple::CreateObject() \
{ return new CSimple; } \
extern AFX_CLASSINIT _init_CSimple; \
 _IMPLEMENT_RUNTIMECLASS(CSimple, CObject, 1, \
 CSimple::CreateObject, NULL) \
 AFX_CLASSINIT _init_CSimple(RUNTIME_CLASS(CSimple)); \// CSimple member functions
void CSimple::Serialize( CArchive& archive )
{
 // call base class function first
 // base class is CObject in this case
 CObject::Serialize( archive ); // now do the stuff for our specific class
 if( archive.IsStoring() )
  {
   m_name = "fasdfads";   archive << m_name << m_number;
  }
 else
  archive >> m_name >> m_number; TRACE2("%s %d\n",m_name ,m_number );
}

解决方案 »

  1.   

    你知道里面对象是CSimple对象,你可以直接调用CSimple::Serialze,如果你不知道它是CSimple,也许是同继承自CObject的一堆类,你怎么调用Serialize?
      

  2.   

    没有谁硬性规定一定要用MFC提供的宏才能序列化,它仅仅是一套“统一”的机制而已,在统一的前提下,类的成员变量能自动序列化。
    举个简单的例子:
    一种情况是假设你的CSimple里面有一个CArray m_array的成员变量,那么在你的序列化函数里可以直接调用 archive << m_array; 或者 m_array.Serialize(...) 来实现成员数据的保存。
    另一种情况是假设你的CSimple派生自另一个支持序列化的类,比如class CSimple : public COtherSerial {}; 那么CSimple将自动支持序列化,只不过序列化的数据是COtherSerial的,自己的数据成员无法被保存或加载。再考虑另一种情况,假设有另一个类CChildSimple是从CSimple派生,如果CSimple支持MFC标准的序列化,那么CChildSimple也能自动支持序列化,如果CSimple没有采用标准的序列化,那么CChildSimple或者任何后续的派生类都不能执行标准的序列化操作,在下面的调用方式下会失败:
    class CTest : public CObject
    {
      ...
      CSimple m_simple;
      Serialize(...)
      {
        archive << m_simple;  // or m_simple.Serialize(...); // 失败,因为非标准
        ...
      }
      ...
    };最终结论:如果你确信你的类是一个最终的类,那么可以完全无视MFC统一的序列化标准。问题在于你是否能确信你的类永远不会被其它类继承,并且也永远不会成为其它类的一个需要被序列化的成员变量?如果不能确定,最好还是使用DECLARE_SERIAL来实现标准的序列化机制。  话说回来,MFC的序列化机制已经非常简单了,你自己实现一个还有必要吗?
      

  3.   

    到现在还没明白你的问题是什么,你打算用什么形式串行化?如果用
    //CArchive archive;
    //CSimple* simple;
    archive >> simple;
    这样的形式,才会调用
    AFX_API friend CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb);
    这样的函数。
      

  4.   

    他在怀疑他永远用不到你说的这种方式因此他认为不需要operator>>
      

  5.   

    谢谢 cnzdgs 和 arong1234 的回复:
    明白了需要operator>> ,
    之前是利用对象Serialze,脑筋死了,没转过来现在就是CRuntimeClass成员m_pClassInit用在那里,我设NULL感觉一样
    MFC:
    _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, \
    class_name::CreateObject, &_init_##class_name) \
    -》我修改的:
    _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, \
    class_name::CreateObject, NULL) \
      

  6.   

    jameshooo 的回复 存在错误:象archive < < m_array等,感觉描述有点模糊
      

  7.   

    那个m_pClassInit,我也觉得是没用的,也许是早期版本中使用的,也可能是为以后版本预留的。
      

  8.   

    前面没搞清楚你在问什么。有操作符>>就有对应的操作符<<,一个用于加载,一个用于保存,重载这两个操作符仅仅是为了序列化操作方便,可以多个语句合并成一个语句,例如
    archive << "abc" << m_nData << m_array;
    如果没有重载这个操作符,就必须调用3次Serialize(),写起来有点烦。m_pClassInit非常非常重要,当模块被加载时你的运行时类需要登记在静态的模块全局运行时类链表中,否则MFC框架在动态创建类时会找不到你的运行时类。
      

  9.   

    当模块被加载时运行时类需要登记在静态的模块全局运行时类链表中是AFX_CLASSINIT _init_##class_name(RUNTIME_CLASS(class_name));但我指为什么还要给m_pClassInit
      

  10.   

    自我小结:
    IMPLEMENT_SERIAL中增加CArchive& AFXAPI operator>>(CArchive& ar, CSimple* &pOb)
    { pOb = (CSimple*) ar.ReadObject(RUNTIME_CLASS(CSimple)); \
    return ar; }的用途:
    使ar >> sm(CSimple*的指针)通过编译。跟踪ReadObject(RUNTIME_CLASS(CSimple)),参数传递RUNTIME_CLASS(CSimple)->const CRuntimeClass* pClassRefRequested
    在以下三个地方用到:
    ASSERT(pClassRefRequested == NULL ||
    AfxIsValidAddress(pClassRefRequested, sizeof(CRuntimeClass), FALSE));

    if (pClassRefRequested != NULL && pClassRefRequested->m_wSchema == 0xFFFF)
    {
    TRACE(traceAppMsg, 0, "Warning: Cannot call ReadClass/ReadObject for %hs.\n",
    pClassRefRequested->m_lpszClassName);
    AfxThrowNotSupportedException();
    } // check for correct derivation
    if (pClassRefRequested != NULL &&
    !pClassRef->IsDerivedFrom(pClassRefRequested))
    {
    AfxThrowArchiveException(CArchiveException::badClass, m_strFileName);
    }
    说明传递RUNTIME_CLASS(CSimple)主要是多增加了安全检查。所以以下俩种方式也能够读取:
    1、ar.ReadObject(RUNTIME_CLASS(CSimple))-》ar.ReadObject(NULL)
    2、不要CArchive& AFXAPI operator>>(CArchive& ar, CSimple* &pOb), 在ar >> sm 改成ar >> ((CObject*&) sm)(即强制转化通过编译);
      

  11.   

    到目前为止,你对自己要问什么问题都没搞清楚,看不出你想要什么,不如我反问你几句,也许能帮助理顺你的思路:1、为什么要去掉 operator>> ?对你有什么好处?
    2、为什么要修改MFC提供的宏?有十足的把握修改后不出现问题吗?
    3、序列化在你心目中的概念到底是什么?如果觉得现有的序列化机制不满足你的要求,那你的要求是什么?或者说你到底想实现什么用途?如果还在里面纠缠,除了你自己混乱,也会让别人混乱,更加搞不清你在问什么。建议多了解这些宏的内部机制,里面的每句代码都是千锤百炼出来的,可以借助于侯捷的《深入浅出MFC》一书加深理解。
      

  12.   

    [Quote=引用 12 楼 jameshooo 的回复:]
    正是为了了解这些宏的内部机制,所以存在一些疑问.
    去掉 operator>>,没有什么好处;但是却是是可以去掉的, 当然去掉了就没有上面说的附加的检查!
    修改MFC提供的宏只是为了证明一些疑问,为了了解这些宏的内部机制,真正写程序当然不那样。
    序列化的概念自己难定义,简单的理解为数据读写,当然MFC的序列化机制不止包装了这些!
    我没有说序列化机制不满足我的要求,也没有特别用途,想探个底。
      

  13.   

    理论上你的分析代码没有问题,尝试断点跟踪一下,确认返回的sm到底是指向CObject还是指向CSimple,检测编译器用的是哪种cast类型,但是下面的用法就一定不会有错:
    // CSimple* sm;
    CObject* obj;
    ar >> obj;
    sm = obj;
      

  14.   

    你错了,去掉一个东西不是看他有没有什么好处,而在于看他去掉以后是不是有害处。你要证明的是他确实从来没有被用过,而不是证明他确实曾经被用过。如果你随便删除一个接口,如果这个接口在某个你不知道的地方用到的话,你就死定了。
    不能仅仅因为自己看几行代码,就这么信心百倍的去改系统里的东西。而且,个人认为你要理解串行化过于关注一两个接口就偏离了方向,实际上,串行化的实现方法可以有很多种完全不同的实现,IMPLEMENT_SEIRAL只是其中一种而已,你关注于某个api怎么写,那么人家稍微换换你就瞪眼了。学习串行化需要务虚的学习,不能扣特定的函数。你这种不是所谓的“理解”,而是钻牛角尖,而这种钻出来的东西,未必真的对你有用。看你钻了一天,假如你证明了operator<<是多余或者不多余,又能怎样?能对你使用serialization有多少帮助呢?有这种功夫,一本好书至少可以看10页,小程序至少可以写100行。借用一句书上的话:改悔吧