When you have an array of polymorphic pointers, how do you tell what kind of class pointer you have? That is, after you set a cCritter* pcritter somewhere in your code, how can you tell if pcritter is just a cCritter* or whether it is perhaps a cCritterBullet* ? (For this discussion, assume that we have a cCritterBullet class that inherits from cCritter .) There are two ways to deal with this. A hand-made way would be to keep a CString _classname field inside our cCritter class and set it to either cCritter or to cCritterBullet , depending on whether the object was constructed by the cCritter constructor or by the cCritterBullet constructor. And then you could find out if a cCritter * pcritter is really a cCritterBullet * by checking if pcritter->_classname is the same as the string cCritterBullet . People have written programs that way. In MFC, however, we're encouraged to take advantage of the so-called CRuntimeClass structures. These objects have a CString field for the class name , just like the _classname field of the hand-made approach. They also keep track of how many bytes big one of our class objects might be. The way that you associate an informational CRuntimeClass structure with one of your class objects? You have to do three things.
MFC provides a couple of tools for working with the 'runtime class information' in a CObject -derived class. First of all, there is a macro called RUNTIME _ CLASS(classname) , which generates a pointer to a CRuntimeClass description of a class if you feed it a class's name just written there without any quotation marks. This macro can only works if the class is CObject derived. Since cCritter inherits form CObject , we can indeed write RUNTIME_CLASS(cCritter) to produce a CRuntimeClass* reference to the kind of class that cCritter is. The second main MFC tool involving CRuntimeClass information is the BOOL CObject::IsKindOf(CRuntimeClass* pruntimeclass) method. Thus, if you wanted to know if a cCritter *pcritter pointer is actually a cCritterBullet* pointer, you could evaluate pcritter->IsKindOf(RUNTIME_CLASS(cCritterBullet)) . Implementing the runtime class support is actually easier than thinking about it. Here are the three steps mentioned above.
And we do the same steps for cCritterBullet , except that if cCritterBullet inherits from cCritter , it doesn't have to inherit from CObject . The inheritance relationship is transitive. The IMPLEMENT_SERIAL macro for cCritterBullet will mention the parent cCritter , rather than cObject , as follows . IMPLEMENT_SERIAL( cCritterBullet , cCritter, 0); A word of caution here. You have to be very disciplined about putting in the correct IMPLEMENT_SERIAL macro code into the *.cpp file when you add a new class that has the DECLARE_SERIAL macro in its *.h header. If you don't do it, or if you do it wrong in any way (for instance if you were to put cObject instead of cCritter in the IMPLEMENT_SERIAL macro for cCritterBullet ), then your program will compile and build, but when you try and run it you will get a crash at startup accompanied by an inscrutable message. Try and remember this fact: if you ever do have code that seems to crash at startup 'for no reason,' then you should take a good look at all of your IMPLEMENT_SERIAL macro declarations and make sure that they're all in place and correct. |