Jump to content

Roland

Members
  • Posts

    2,953
  • Joined

  • Last visited

Blog Comments posted by Roland

  1. HA! Thats exactly what I did in first LEO-versions (or did I ever send them? ), those which were rejected because they did not follow the C-API exactly. Well, thats history and its a great way of storing and loading thigs. Good reading

  2. I removed the correction :)

    Seems that I don't have to kill my self after all :)

     

    -- case 1: No virtuals

    #include <iostream>
    using namespace std;
    
    class Base
    {
    public:
       Base()	{ cout<<"Constructor: Base"<<endl;}
       ~Base()	{ cout<<"Destructor : Base"<<endl;}
    };
    
    class Derived: public Base
    {
    public:
       Derived()	{ cout<<"Constructor: Derived"<<endl;}
      ~Derived()	{ cout<<"Destructor : Derived"<<endl;}
    };
    
    void main()
    {
      Base *Var = new Derived();
      delete Var;
    }
    

     

    Output

    Constructor: Base

    Constructor: Derived

    Destructor : Base

    Press any key to continue . . .

    Only Base destructor called.... ERROR!!!

     

     

    -- case 2: Base destructor virtual (this is what I said)

    #include <iostream>
    using namespace std;
    
    class Base
    {
    public:
      Base()		{ cout<<"Constructor: Base"<<endl;}
      virtual ~Base()	{ cout<<"Destructor : Base"<<endl;}
    };
    
    class Derived: public Base
    {
    public:
       Derived()		{ cout<<"Constructor: Derived"<<endl;}
       ~Derived()		{ cout<<"Destructor : Derived"<<endl;}
    };
    
    void main()
    {
      Base *Var = new Derived();
      delete Var;
    }
    

     

    Output

    Constructor: Base

    Constructor: Derived

    Destructor : Derived

    Destructor : Base

    Press any key to continue . . .

    All destructors called - OK

     

    -- case 3: Derived destructor virtual

    #include <iostream>
    using namespace std;
    
    class Base
    {
    public:
      Base()	{ cout<<"Constructor: Base"<<endl;}
      ~Base()	{ cout<<"Destructor : Base"<<endl;}
    };
    
    class Derived: public Base
    {
    public:
       Derived()	            { cout<<"Constructor: Derived"<<endl;}
       virtual ~Derived() { cout<<"Destructor : Derived"<<endl;}
    };
    
    void main()
    {
       Base *Var = new Derived();
       delete Var;
    }
    

     

    Output

    Constructor: Base

    Constructor: Derived

    Destructor : Base

    Then ----> Crash : ERROR

     

    So my statment seems valid. If you ever has a reason to believe that your class will be inherited you should have a virtual base class destructor. Maybe the school was right then :D

  3. ALWAYS MAKE DESTRUCTORS VIRTUAL if you not has a good reason no to.
    Sorry, but that's what you say to school developers in the first year C++ :). There is a huge performance impact as from you have 1 virtual function. It should actually be the other way around, If you inherit or want you class to be inherited from, make your destructor virtual...
    A(){    _pmem = new char[1024];}A():_pmem(new char[1024]){ } //No default initialization. Modern compilers should optimize this...

     

    So you mean that I was wrong !!! How embarrasing :)

    Well then there is only one thing to do - As you are completely right I have to go a kill my self :D

  4. Inititalizing ...

    Do that in the constructors. Then if you feel better to do your resorce allocations etc etc.. in a method (there can be reasons for that) you should make it a virtual method.

    class A
    {
        char* _pmem;
    
    public:
        A()
        :    _pmem(nullptr)
        {}
    
        virtual ~A()
        {
             DeInit();
        }
    
        virtual void Init()
        {
           DeInit();
            _pmem = new char[1024];
        }
    
       virtual void DeInit()
       {
            delete [] _pmem;
            _pmem = nullptr;
      }
    };
    
    class B : public A
    {
        char* _pMoreMem;
    
    public:
        B()
        :    _pMoreMem(nullptr)
        {}
    
        virtual ~B()
        {
             DeInit();
        }
    
        virtual void Init()
        {
            __super::Init(); 
           DeInit();
            _pMoreMem= new char[256];
        }
    
       virtual void DeInit()
       {
            __super::DeInit();
            delete [] _pMoreMem;
            __pMoreMem = nullptr;
      }
    };
    
    void somewhere()
    {
          A a;
          B b;
    
         a.Init();   // A's init will be called
         b.Init();   // B's init will be called (which the internally calls A's init)
    
         a.Deinit(); // a's memory will be deleted
    }
    // end of scope. 
    // a's memory is already deleted so nothing will happen 
    // b's memory will be deleted including the part allocated by A
    // If you had missed the virtual keyword for the destuctors, A's desctructor would never have been executed and you would have a memory leak
    

    In case you allocate your class resources in a Init method I would recommend having a public virutal void DeInit() also and call that from the destructor.

     

    About virtual destructors. In case you have any belief that your class will ever be inherited you MUST make the destructor virtual. And as its very hard to know what the needs are going to be in the future I would say. ALWAYS MAKE DESTRUCTORS VIRTUAL if you not has a good reason no to.

     

    Keeping things in the constructors and destructors make things a bit more easy although it might not always be in line with you want.

     

    class A
    {
        char* _pmem;
    
    public:
        A()
        {
            _pmem = new char[1024];
        }
    
        virtual ~A()
        {
                 delete [] _pmem;
        }
    };
    
    class B : public A
    {
        char* _pMoreMem;
    
    public:
        B()
        {
               _pMoreMem= new char[256];
        }
    
        virtual ~B()
        {
            delete [] _pMoreMem;
        }
    };
    
    void somewhere()
    {
          A a;   // a will be created and its memory allocated
          B b;  //  b will be created and its memory include the A-part will be allocated
    
    }
    // end of scope. 
    // a's memory is deleted in its destructor
    // b's memory is deleted in its destructor, The A-part destructor will also be called as its virtual
    

     

    EDIT: Sorry Theo ... you wrote an answer while I was typing.. so I guess I just repeted some.

  5. Interesting techniuqe and well written.

    One little statement of no direct importance for the technique described, but still not correct.

     

    But it can be re-written without a class, whilst still keeping the access specifiers. "How?" You might ask, because it's true that public, protected and private (well, and friend too) are all class access specifiers - they can't be used for structs or namespaces. Well, here's how:

     

    A class is same thing as a struct with one and only one difference. The class protection is by default private, while its by default public for the struct. The code below is fully valid as the struct and class is essential the same thing.

     

    struct MyStruct
    {
    MyStruct()
    :	_prot(0),
    	_priv(0)
    {}
    
    protected:
    int _prot;
    void prot() {}
    
    private:
    int _priv;
    void priv() {}
    };
    

     

    Anyway. What's described here is an interesting way of solving the need for statics. So according to this LEO::Draw could be rewritten to something like this (not tested) if one would like to, although this is kind of "hidden" C-programming :)

     

    namespace LEO
    {
    namespace Draw
    {
    	void SetColor( const TVec3& color );
    	void SetColor( const TVec4& color );
    	void SetColor( flt red, flt green, flt blue, flt alpha = 1 );
    	void SetBlend( int blendmode );
    	void Clear( void );
    
    	void Plot( int x, int y );
    	void Line( int x1, int y1, int x2, int y2 );
    	void Rect( int x, int y, int width, int  height );
    	void Image( const Texture& image, int x, int y, int width = -1, int height = -1 );
    	void Text( int x, int y, const_str text, ... );
    }
    }
    

     

    Question

    One question about this arrangement. What is gained by using this namespace technique instead of a static class. I can't see in what way this improve things other than the semantics. Have I missed something or is it just about semantics?

  6. Just of curiosity. Is there any special reason why you doesn't use enumerations like this

    enum CollisionType
    {
         COLLISON_NONE,
         COLLISION_SCENE,
         COLLISION_CHARACTER,
         COLLISION_PROP,
         COLLISION_DEBRIS
    };
    
    void PhysicsDriver::SetCollisionResponse(const CollisionType& collisiontype0, const CollisionType& collisiontype1, const int& response)
    {
         if ( collisiontype0 == COLLISION_SCENE ) 
         ....
         ....
         ....
    }
    

  7. Looks great to me AnniXa. The idea with a simple image based GUI is quite good. I did that in some demo some years ago. The whole GUI was not one image though. In my case each button was an own image, but essential it was done in the same style and it work very good.

     

    Having a full fledged GUI with buttons, dragbars, checkboxes and good knows what can be overkill for most games, where its just a matter of give the user some simple information and the ability to select och click on some choices.

     

    Keep up the good work :blink:

×
×
  • Create New...