Like Tree1Likes
  • 1 Post By laserlight

Most Efficient Way to Do This?

This is a discussion on Most Efficient Way to Do This? within the C++ Programming forums, part of the General Programming Boards category; I'm creating a game. I have a base Image class, with derived Decal and Primitive classes. I also have a ...

  1. #1
    Registered User
    Join Date
    May 2011
    Posts
    30

    Most Efficient Way to Do This?

    I'm creating a game. I have a base Image class, with derived Decal and Primitive classes. I also have a seperate class named Frame that holds all Decals and Primitives. What's the best way to go about doing this? I originally thought about making dynamic arrays within the Frame for each base and derived class. For example:

    Code:
    class Frame{
    //vector for Decals
    //vector for Primitives
    };
    However, I thought that this was very inefficient. I want to have a single member method in the Frame class that could take Decals, Primitives, and any new image types I may want to create. I figured a template function would be best for this. However, I'd have to do a specialization for each and every applicable type, as each one would be stored in a different array. Would I be better off doing this mess, or should I cast all of the derived ImageObjects into the base, and then store that in a dynamic array? Problem is, converting them back is never a good idea... ugh, can anyone help me out here? Is there something I'm missing?

  2. #2
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by Shokwav View Post
    I want to have a single member method in the Frame class that could take Decals, Primitives, and any new image types I may want to create.
    Why? Wouldn't it be better to have a set of overloaded methods? You could then have an internal private method that takes the base Image class as a param including whatever code is common to all the possible derived classes, and call that with a cast:

    Code:
    class Frame {
    	private:
    		void processImage (Image *img) {
    			// stuff common to all to all Image derived types
    		}
    	public:
    		void process (Decal *dec) {
    			processImage ((Image*)dec);
    			// stuff particular to Decals
    		}
    		void process (Primitive *prim) {
    			processImage ((Image*)prim);
    			// stuff particular to Primitives 
    		}
    };
    No templates required.
    Last edited by MK27; 03-02-2012 at 10:46 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  3. #3
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    21,313
    You don't even need a cast since a Decal is an Image and a Primitive is an Image.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  4. #4
    Registered User
    Join Date
    May 2011
    Posts
    30
    Thank you, that really helps me; I can just add an extra overloaded method for any new types. However, for the array bit, do you think I should cast them to the base class to be stored in array? The problem is, I need to access specific properties specific to each derivative when they are retrieved.

    Again, thank you for your help.

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    21,313
    Quote Originally Posted by Shokwav
    However, for the array bit, do you think I should cast them to the base class to be stored in array? The problem is, I need to access specific properties specific to each derivative.
    You should store a vector of (smart) pointers. If you store a vector of Image objects, there is type slicing and you lose the parts specific to each derived class.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #6
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by laserlight View Post
    You don't even need a cast since a Decal is an Image and a Primitive is an Image.
    Hmm, okay. In theory I would think that is how it should be, but I get "error: ‘Image’ is an inaccessible base of ‘Primitive’" when I try to compile the below [subsequently corrected] without the cast. I should set myself out some simple C++ specific examples -- otherwise I tend to use a quick hit and miss to deduce what rules apply in which language when what I think "in theory should be" goes wrong.

    @Shokwav WRT to accessing arrays, you can pass a reference to them internally too:

    Code:
    #include <vector>
    
    using namespace std;
    
    class Image {
    	public:
    		virtual ~Image () {}
    };
    
    class Decal : public Image {};
    
    class Primitive : public Image {};
    
    class Frame {
    	private:
    		vector<Decal*> decals;
    		vector<Primitive*> primitives;
    		void processImage (Image *img, vector<Image*> &list) {
    			list.push_back(img);
    			// other stuff common to all to all Image derived types
    		}
    	public:
    		void process (Decal *dec) {
    			processImage (dec, (vector<Image*>&)decals);
    			// stuff particular to Decals
    		}
    		void process (Primitive *prim) {
    			processImage (prim, (vector<Image*>&)primitives);
    			// stuff particular to Primitives 
    		}
    };
    
    int main(void) {
    	Decal *d = new Decal();
    	Primitive *p = new Primitive();
    	Frame *f = new Frame();
    	f->process(p);
    	f->process(d);
    	return 0;
    }
    If laserlight can straighten out the casting issue for me, I now have a C++ specific example of...something...

    Quote Originally Posted by laserlight View Post
    You should store a vector of (smart) pointers. If you store a vector of Image objects, there is type slicing and you lose the parts specific to each derived class.
    I think my idea here gets around this, since the vectors are correctly typed.
    Last edited by MK27; 03-02-2012 at 11:45 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  7. #7
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    21,313
    Quote Originally Posted by MK27
    In theory I would think that is how it should be, but I get "error: ‘Image’ is an inaccessible base of ‘Primitive’" when I try to compile the below without the cast.
    That is because you used private inheritance. It should have been:
    Code:
    class Image {
        public:
            virtual ~Image() {}
    };
     
    class Decal : public Image {};
     
    class Primitive : public Image {};
    Quote Originally Posted by MK27
    I think my idea here gets around this, since the vectors are correctly typed.
    Oh yeah, plus just passing a pointer to Image to process would otherwise invoke the version for Image (we aren't really using the visitor pattern here, methinks).
    Last edited by laserlight; 03-02-2012 at 11:16 AM.
    MK27 likes this.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  8. #8
    Registered User
    Join Date
    May 2011
    Posts
    30
    Ah, so I do have to create multiple vectors to avoid the data loss of upcasting? Okay, that's what I thought. :P Thank both of you, this has answered my question; your example is also relatively simple and not overty complex, MK27.

    EDIT: Got my code completed, no errors.

    #include <vector>
    #include "Outstream.h"
    #include "ImageObject.h"

    class Frame{

    std::vector<Decal*> DecalCntr;
    std::vector<Primitive*> PrimCntr;

    void AddObject(ImageObject* ImgObj, std::vector<ImageObject*> &Cntr){
    Cntr.push_back(ImgObj);
    }

    public:

    Frame();
    ~Frame();

    void AddObject(Decal* Dcl){
    AddObject((ImageObject*)Dcl, (std::vector<ImageObject*>&)DecalCntr);
    Print(Dcl->GetImgSrc());
    }

    void AddObject(Primitive* Prim){
    AddObject((ImageObject*)Prim, (std::vector<ImageObject*>&)PrimCntr);
    }
    };
    Last edited by Shokwav; 03-02-2012 at 11:26 AM.

  9. #9
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by laserlight View Post
    just passing a pointer to Image to process
    Whoops! I actually think it was then not such a good idea to dereference those for the vectors, so I corrected the code in post 6 to use vector<*> (and public access to the base). I guess the pointer issue all hinges on whether the Decals and Primitives have a life beyond the Frame they are submitted to; if not, then there should be no pointers and just references in that code. Squiggles & vs. quips * .

    the visitor pattern
    Will look that one up .
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  10. #10
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    21,313
    Quote Originally Posted by Shokwav
    Ah, so I do have to create multiple vectors to avoid the data loss of upcasting?
    No, you don't. The data loss comes when you cast a Decal to an Image. It does not happen when you cast a Decal* to an Image*, and in fact you don't need a cast at all for that: it is normal use of polymorphism.

    The problem is that once you only have a vector of Image pointers, you are constrained to the Image interface, i.e., if you want to do something special for objects of a derived class that is not provided for in a virtual member function of Image, then you need to use say, dynamic_cast.

    One way out is to apply the visitor method: create an ImageVisitor class that provides a virtual visitX member function corresponding to each Image derived class X. Derive Frame from ImageVisitor and implement these visit functions. Image has a virtual accept member function that takes an ImageVisitor object by reference, then each derived class X overrides accept to call the appropriate visitX member function of the ImageVisitor. The drawback is that if you add a new class derived from Image, ImageVisitor and all its derived classes should be updated to handle this new class.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  11. #11
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by laserlight View Post
    One way out is to apply the visitor method:
    I did this as exercise for my hackish C++, but I did in reverse of your suggestion (such that the image types visit the frame):

    Code:
    #include <vector>
    #include <iostream>
    #include <string>
    
    class Object {
    		std::string name;
    	public:
    		void setName (std::string name) { this->name = name; }
    		const std::string getName() { return name; }
    };
    
    class Frame;
    class Image;
    
    class Frame : public Object{
    	private:
    		std::vector<Image*> images;
    	public:
    		Frame (std::string name) {
    			setName(name);
    		}
    		void accept (Image*);
    };
    
    class Image : public Object {
    	public:
    		void visit(Frame* f) {
    			std::cout << getName() << ": " << f->getName() << std::endl;
    		}
    		~Image () {} 
    };
    
    class Decal : public Image {
    	public:
    		Decal () { setName("Decal"); }
    };
    
    class Primitive : public Image {
    	public:
    		Primitive () { setName("Primitive"); }
    };
    
    void Frame::accept (Image *img) {
    	img->visit(this);
    	images.push_back(img);
    }
    
    int main (void) {
    	Frame f = Frame("Frame 1");
    	f.accept(new Decal());
    	f.accept(new Primitive());
    	return 0;
    }
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Efficient TSP
    By Cpro in forum C++ Programming
    Replies: 2
    Last Post: 09-10-2008, 08:52 PM
  2. is mod(%) efficient?
    By franziss in forum C++ Programming
    Replies: 7
    Last Post: 05-14-2007, 09:46 AM
  3. CPU efficient
    By Queatrix in forum Game Programming
    Replies: 8
    Last Post: 12-15-2006, 01:20 AM
  4. Which of these is more efficient?
    By suzakugaiden in forum C++ Programming
    Replies: 8
    Last Post: 02-06-2006, 10:35 PM
  5. New but efficient way to...
    By jmd15 in forum C++ Programming
    Replies: 5
    Last Post: 11-01-2005, 03:19 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21