-
Implement_serial_new
If anyone has any idea, I'd be grateful. Basically, I'm trying to make some class serializable with CArchive, but it isn't working out too well, because I can't get the macro IMPLEMENT_SERIAL_NEW to work.
The problem lies in that the class CIndex is nested inside CRegistry (and also declared private). Typing CRegistry::CIndex and passing it to the macro causes major compile errors due to the way it's structured.
So I've tried a typedef CRegistry::CIndex CIndex; which doesn't work because it's private! Neither can I actually make a friend or anything because it's in global scope level.
The current solutions seems to be to re-define IMPLEMENT_SERIAL_NEW and all its depending macros to take an extra arg - the full class path and class name or make CIndex public or moving it outside CRegistry.
Are there any other viable solutions to a problem like this?
Oh yes, I tried doing it in the header, inside the encapsuling class, but then it would complain with all sorts of errors such as cannot overload static and non-static functions of the same name or something? And also cannot overload a function from an interface it isn't derived from or some such.
-
You could look at what IMPLEMENT_SERIAL_NEW actually does and insert the code - with appropriate changes - yourself.
I don't think the MFC developers really considered something as fancy as nested classes back when they were creating MFC.
-
Yes, I looked at it and it looks pretty messy. I can't reproduce 100% what the macros should look like...
Code:
#define IMPLEMENT_SERIAL(class_name, base_class_name, wSchema) \
CObject* PASCAL class_name::CreateObject() \
{ return new class_name; } \
extern AFX_CLASSINIT _init_##class_name; \
_IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, \
class_name::CreateObject, &_init_##class_name) \
AFX_CLASSINIT _init_##class_name(RUNTIME_CLASS(class_name)); \
CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb) \
{ pOb = (class_name*) ar.ReadObject(RUNTIME_CLASS(class_name)); \
return ar; }
Code:
#define IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew, class_init) \
CRuntimeClass* PASCAL class_name::_GetBaseClass() \
{ return RUNTIME_CLASS(base_class_name); } \
AFX_COMDAT const CRuntimeClass class_name::class##class_name = { \
#class_name, sizeof(class class_name), wSchema, pfnNew, \
&class_name::_GetBaseClass, NULL, class_init }; \
CRuntimeClass* PASCAL class_name::GetThisClass() \
{ return _RUNTIME_CLASS(class_name); } \
CRuntimeClass* class_name::GetRuntimeClass() const \
{ return _RUNTIME_CLASS(class_name); }
Code:
#define RUNTIME_CLASS(class_name) (class_name::GetThisClass())
This especially confuses:
Code:
AFX_COMDAT const CRuntimeClass class_name::class##class_name = { \
#class_name, sizeof(class class_name), wSchema, pfnNew, \
&class_name::_GetBaseClass, NULL, class_init }; \
That would be...
Code:
AFX_COMDAT const CRuntimeClass CRegistry::CIndex::class##CIndex = { \
"CIndex", sizeof(class CRegistry::CIndex), 0, pfnNew, \
&CRegistry::CIndex::_GetBaseClass, NULL, class_init }; \
WTF?
-
OK, this is very problematic. There's simply no way something like this:
extern AFX_CLASSINIT _init_##class_name;
is going to work with nested names.
Hmm ... very much looks like you're out of luck there. You'll have to make CIndex a free class.
Or you simply don't give it the MFC RTTI stuff. Why do you need to serialize the thing, anyway?
-
I serialize it to store in a file and later read it back. It's an index!
Silly, silly Microsoft. But I can't believe no one else has actually found a solution to this problem since I would believe a lot of programmers have tried to serialize nested classes.
Oh well. For now, I'll make it free. Err, or just public, because it's the same darn thing.
I'll have to see if I can actually find someone who has found a solution, maybe rewritten the macros?