Archived

This topic is now archived and is closed to further replies.

Paradigm Shift 2000

Factory model and class hierarchy questions

Recommended Posts

Given that downcasting from a pointer of a base class to a pointer of a derived class is illegal, how exactly is a factory model supposed to work? I have a persistent example that I''m trying to program a test application around. Let''s take a base class CFile, which defines all of the necessary things that all file loaders need. A status code, a loadbit, and a pointer to a dynamically created buffer to hold the data, a pure virtual load method which loads the file and a pure virtual unload method which clears the object, three inline Get() type functions to return the status code, the loadbit and a safe buffer pointer. Then say I derive a class CBmp from this base which defines the bitmapfileheader, infoheader and colorpalette, and the methods to load, unload and get the information from the object. Now, I use a factory function, so that I can ask for any number of objects like maybe a wave instead of a bmp, sending an arbitrary type to it for the bmp so that it will create a new CBmp object, and return me the pointer as a CFile, so that I can use the new CBmp object. But, you can''t upcast the CBmp* to a CFile* for the return value, and downcast it back to a CBmp* so you can use the GetWidth() or GetSafePalettePtr() methods of the CBmp class that aren''t defined in the base class. Making the factory function return the CBmp* as a CBmp* defeats the purpose of having the factory, because then you can''t request other derived classes from it. So, I guess my question is, what is wrong with my understanding of the factory model? I''m obviously not understanding something very important here, otherwise I would be able to get this to work properly. I know I''ve been asking these questions too much, and I still feel really dense, but I would appreciate *any* good explanation about what I''m doing wrong and how this is supposed to really work. Thanks in advance Paradigm Shift 2000

Share this post


Link to post
Share on other sites
Downcasting is not illegal. If you have a base class pointer *bp, and it points to a derived-class object, and you cast to that derived class object, you''re golden. However, if you actually have a base class object and try to cast to a derived class, things will break.

As for how you''re supposed to get the factory method to work, you either:
- make everything you''re going to do with the derived classes a virtual function, only access classes through base class pointer (my preference)
- use RTTI to try to find what type it is and downcast, or implement your own kind of runtime class scheme (MFC has implemented this in CObject & CRuntimeClass). I avoid this when possible.

Share this post


Link to post
Share on other sites
*pounds head on hardwood desk repeatedly*

Can anyone tell me *please*, What is the point of creating an abstract base class, if you can''t use its pointer to determine the derived classes? All that I''m looking to do is create a function that will instantiate a class based on an arbitrary type id that I pass it, similar to QueryInterface(), in my DLL so that I don''t have to recreate the vtables for the classes manually when I dynamically load the DLL which contains the class definitions, so that I don''t have file-loader code lying around in the memory when I don''t need it. It doesn''t make sense to declare every function that any derived class could possibly need in the base because not all of those functions make sense in every case. Like, for instance, GetFontEntry() wouldn''t make sense if the file is .wav sound file. But, if I want to load a font file in, I need access to the font entries to display the font on the screen, so only having access the the Load() and Unload() methods through the base *also* doesn''t make sense. So, what''s the point of using this method if you can''t *do* anything with it?

  
IResourceFile * CreateResourceFile(unsigned int type_id)
{
IResourceFile * ptr;
switch(type_id)
{
case BMPTYPE:
ptr = new IBitmapFile;
return ptr;
default:
return NULL;
}
}

void MainCycle(void)
{
IBitmapFile * bitmap = CreateResourceFile(BMPTYPE);
// ...

}


Can anyone tell me why this doesn''t work? Even when I do reinterpret_cast to cast the result of the function, I get an illegal page fault. Is it my understanding that''s skewed? The ptr returned by CreateResourceFile() points to an IBitmapFile, which is a child of the base IResourceFile, so shouldn''t I be able to downcast this pointer back to an IBitmapFile*? If not, then how exactly am I supposed to instantiate a class in my DLL and access it in my application after I load the DLL with LoadLibrary()? Does it even matter whether I dynamically load the DLL at runtime, or statically load it when the application starts by linking the import library? If I distribute an application with a DLL, it hardly makes sense to force the user to d/l a new copy of the main executable everytime I need to recompile the DLL because the import library changes and I need to re-link the import library with the executable. I am just *completely* failing to comprehend. Am I using it wrong, perhaps? On page 18 of my Game Programming Gems reference is an example of a factory that does exactly what I''m doing above. But, my code isn''t working, and the editors obviously wouldn''t publish code that doesn''t work. So, I must be doing something wrong.

Can anyone *please* tell me what I''m doing wrong?

Paradigm Shift 2000

Share this post


Link to post
Share on other sites
C:\PROGRAMS\absclass\hooks.cpp(31) : error C2635: cannot convert a 'IResourceFile*' to a 'IBitmapFile*'; conversion from a virtual base class is implied
C:\PROGRAMS\absclass\absclass.h(17) : see declaration of 'IResourceFile'
C:\PROGRAMS\absclass\hooks.cpp(31) : error C2440: 'initializing' : cannot convert from 'class IResourceFile *' to 'class IBitmapFile *'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

Wait a minute... Should I have defined a conversion constructor IBitmapFile(IResourceFile&) or an assignment operator IBitmapFile& operator=(IResourceFile&) to handle this type of cast?

Argh. No, I suppose not. I understand why the compiler is barking at this. The way it's programmed, there's nothing to stop me from pulling some nonsense like IBitmapFile * bitmap = CreateResourceFile(WAVTYPE). But, how then is this model supposed to work? Is it only supposed to work with implementations that are specific to a single interface, as an example like DirectDraw where DirectDrawCreate() only returns an IDirectDraw type interface? Does that mean I shouldn't try to implement this type of model to return pointers to separate classes like IBitmapFile, IWaveFile, IDDBitmapFile, and ISEFontFile? Do I need to define a separate function to return each a different type of pointer like CreateBitmapFile(), CreateWaveFile(), CreateDDBitmapFile(), and CreateSEFontFile()?

Paradigm Shift 2000


Edited by - Paradigm Shift 2000 on October 17, 2001 8:34:47 PM

Edited by - Paradigm Shift 2000 on October 17, 2001 9:03:41 PM

Edited by - Paradigm Shift 2000 on October 17, 2001 9:07:04 PM

Share this post


Link to post
Share on other sites
*smacks self* I just figured it out. I was inheriting the IResourceFile class virtual I fixed it and now it works.

*bangs head on desk some more for good measure*
A lesson for those who follow.

Hey thanks for your help, Stoffel That's twice now.

Paradigm Shift 2000

Edited by - Paradigm Shift 2000 on October 17, 2001 9:20:58 PM

Share this post


Link to post
Share on other sites
I got an idea:


IBitmapFile* CreateBitmapFile()
{
return new IBitmapFile;
}

IResourceFile* CreateResourceFile(unsigned int type_id)
{
switch(type_id)
{
case BMPTYPE:
return CreateBitmapFile();
default:
return NULL;
}
}

void MainCycle(void)
{
IResourceFile* bitmap1 = CreateResourceFile(BMPTYPE);
IBitmapFile* bitmap2 = CreateBitmapFile();
}


You can get both pointers - abstract or concrete depending on what do you need, without any downcasting (I never used this so I am not sure about it)

Share this post


Link to post
Share on other sites