Thread: What's the best way to...

  1. #1
    Just because ygfperson's Avatar
    Join Date
    Jan 2002
    Posts
    2,490

    What's the best way to...

    ...control when things are initialized?

    Code:
    class Base {
      some_other_class* handle;
    
    };
    Many classes derive from Base, and some want to initialize handle (with a new object), but some want to keep it initialzed to NULL.

    Only a small minority of the derived classes want the handle == NULL. If possible I want to set the default behavior as creating a new object for this pointer. This behavior should be overridden for the special derived classes I talked about.

    There's a problem... virtual functions won't work properly until all the necessary constructors have been called. So I can't just let my base classes' constructor call a virtual function to initialize handle. At the base constructor's level, only the Base is created. I don't want to have to define the behavior for every leaf, especially since some leaves are not always leaves.

    Creating a new object, then deleting it at a lower level constructor would defeat my purpose. (I'm trying to prevent the handle's constructor from taking up valuable memory and time if the derived object is created frequently enough.)

    Any ideas?
    Last edited by ygfperson; 07-15-2003 at 09:18 PM.

  2. #2
    Registered User
    Join Date
    Apr 2002
    Posts
    1,571
    Maybe I'm not understanding exactly what you are doing but can't you do something like this..

    Code:
    class Base {
      private:   
        some_other_class *handle;
    
      public:
        Base( some_other_class *h = NULL ) : handle(h) { }
    };
    
    class Derived : public Base {
      public:
        Derived( some_other_class *h = NULL ) : Base(h) { }
    };
    I think maybe I am missing what you are trying to do.
    "...the results are undefined, and we all know what "undefined" means: it means it works during development, it works during testing, and it blows up in your most important customers' faces." --Scott Meyers

  3. #3
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    How about having another class between Base and those derived that want hte object, like this:
    Code:
    class Base
    {
    protected:
      some_other_class *handle;
    
    public:
      Base() handle(NULL) {
      }
    
      virtual  ~Base() {
        if(handle != NULL) {
          delete handle;
        }
      }
    };
    
    class BaseWithObject : public Base
    {
    public:
      BaseWithObject() {
        handle = new some_other_class();
      }
    };
    
    class DerivedNoObject : public Base
    {
    };
    
    class DerivedWithObject : public BaseWithObject
    {
    };
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  4. #4
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    MrWizard's example looks good enough for most.....

    You could also try a little template trickery;


    Code:
    #include <iostream>
    using namespace std;
    
    class some_dumb_class
    {
    public:
    	some_dumb_class()
    	{
    		cout << "created";
    	}
    };
    
    template<bool b>
    class base
    {
    	some_dumb_class* ptrSDC;
    public:
    	base();
    	virtual ~base()
    	{
    		if(ptrSDC) delete ptrSDC;
    	}
    };
    
    template<>
    base<true>::base()
    {
    	ptrSDC = new some_dumb_class;//forgive lack of error handling
    }
    
    template<>
    base<false>::base()
    {
    	ptrSDC = 0;
    }
    
    template<bool b>
    class derived : public base<b>
    {
    
    };
    
    
    int main()
    {
    	derived<true> a;
    	derived<false> b;
    }

  5. #5
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    But that would mean that you need a base class for base or you can't use base * to point to all objects. base<true> and base<false> are different types.

    And for the error handling - modern standard libraries should throw an exception if new fails.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  6. #6
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    Originally posted by CornedBee
    But that would mean that you need a base class for base or you can't use base * to point to all objects. base<true> and base<false> are different types.
    That's a good point.

    Originally posted by CornedBee
    And for the error handling - modern standard libraries should throw an exception if new fails.
    If my constructor that called new threw an exception, the destructor (that tested the ptr for NULL) wouldnt be called anyway. But my code shows I have been spending too much time with VC++6!

    [edit]
    to get aroung what CornedBee pointed out I could;

    Code:
    #include <iostream>
    using namespace std;
    
    class some_dumb_class
    {
    public:
    	some_dumb_class()
    	{
    		cout << "created" << endl;
    	}
    };
    
    
    class base
    {
    protected:
    	some_dumb_class* ptrSDC;
    public:
    	virtual ~base()
    	{
    		if(ptrSDC) delete ptrSDC;
    	}
    };
    
    template<bool b>
    class creator : public base
    {
    
    };
    
    template<>
    creator<true>::creator()
    {
    	cout << "Creating object in base...";
    	base::ptrSDC = new some_dumb_class;
    }
    
    template<>
    creator<false>::creator()
    {
    	cout << "No object created" << endl;
    	base::ptrSDC = 0;
    }
    
    template<bool b>
    class derived : public creator<b>
    {
    };
    
    
    int main()
    {
    	base *a = new derived<true>;
    	base *b = new derived<false>;
    
    	delete b;
    	delete a;
    }
    [/edit]

  7. #7
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    In that case you could as well use my approach and have less classes (2 instead of 3).
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  8. #8
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    Originally posted by CornedBee
    In that case you could as well use my approach and have less classes (2 instead of 3).

    You;
    Base
    BaseWithObject
    DerivedNoObject
    DerivedWithObject

    Me;
    base
    creator - admittedly the template specialisation does give 2 different classes
    derived

    Your DerivedNoObject has 1 base class, but DerivedWithObject has 2 just as with mine

  9. #9
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    I didn't count the derived classes, what I count is the support structure.

    And there:
    I:
    Base
    BaseWithObject

    You:
    Base
    Creator<true>
    Creator<false>
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  10. #10
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    ::scratches chin::

    Hmm..whatever

  11. #11
    Toaster Zach L.'s Avatar
    Join Date
    Aug 2001
    Posts
    2,686
    Hmm...

    Fordy
    -Base
    -Creator<true>
    -Creator<false>

    CornedBee
    -Base
    -BaseWithObject

    MrWizard
    -Base

    The word rap as it applies to music is the result of a peculiar phonological rule which has stripped the word of its initial voiceless velar stop.

  12. #12
    Just because ygfperson's Avatar
    Join Date
    Jan 2002
    Posts
    2,490
    I've decided to go the mr. wizard route...

    Here's another small related problem:
    Code:
    class Factor {
      pointer* handle;
    }
    class Numeral {} : public Factor {};
    class Numeral_Base : virtual public Numeral {};
    class Float : virtual public Numeral{};
    class Float_Base : public Float, public Numeral_Base {};
    class Infinity_Base : public Numeral_Base {};
    Here's my class layout. My Factor constructor looks like this:
    Code:
    Factor::Factor(const bool r = true) {
      if (r)
        pointer = new Blah;
      else
        pointer = NULL;
    }
    The reason for having the class Numeral_Base is to provide default behavior for its derived classes. ie:
    Code:
    Numeral_Base::Numeral_Base() : Numeral(false) { //... }
    Numeral::Numeral(const bool r = true) : Factor(r) {}
    A Numeral object would cause the pointer to be a new Blah, a Numeral_Base (or derived) object would cause it to be NULL.

    My problem is in Float_Base. How do I ask for Numeral_Base's behavior over Float's behavior?

Popular pages Recent additions subscribe to a feed