Thread: Virtual Constructor Help Needed.

  1. #1
    Registered User
    Join Date
    Feb 2003
    Posts
    265

    Virtual Constructor Help Needed.

    Okeydokey, im up to no good again. What im trying to do is this:

    I have the core class called Core.
    I have a base class called Module.
    Somebody else will create derived classes, whatever they may be.
    Core contains a std::map<string,Module*> Modules.
    Core has a member function called AddModule(std::string modname)

    What i need to do is have Core.AddModule("DerivedClass1"); and it will do something along the lines of
    Code:
    if(!Modules[modname]) { Modules[modname] = new modname; }
    Im told what i want is called a Virtual Constructor, however after googling im not sure that does what i need. Very hard to find source code that does anything like this, so any help or examples would be greatly appreciated.

    As always, thanks for your time.

  2. #2
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    Base class constructors are always called.
    You can force derived classes to always use a particular constructor like so...
    Code:
    #include <iostream>
    #include <string>
    using namespace std;
    
    class Base
    {
        Base(); // no impl. - disallow default construction
    
    public:
        explicit Base(const string &s)
        {
            cout << "Base(" << s << ")" << endl;
        }//constructor
    
        virtual void foo() = 0; // some interfaces...
    };//Base
    
    class Derived : public Base
    {
    public:
        // must use Base's only constructor
        Derived() : Base("Derived") {}
    
        virtual void foo() {}
    };//Derived
    
    int main()
    {
        Derived d;
    
        return 0;
    }//main
    gg

  3. #3
    Registered User
    Join Date
    Feb 2003
    Posts
    265
    Quote Originally Posted by Codeplug
    int main()
    {
    Derived d;

    return 0;
    }//main
    Yes but your using the Derived class directly, how do i make this work without knowing the name Derived? See the AddModule? im trying to do that.

  4. #4
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    Derived can either tell Base what his name is (my prior post), or Base can ask Derived what his name is...
    Code:
    #include <iostream>
    #include <string>
    #include <memory>
    using namespace std;
    
    class Base
    {
    public:
        virtual string get_name() = 0;
    };//Base
    
    class Derived : public Base
    {
    public:
        virtual string get_name() {return "Derived";}
    };//Derived
    
    Base* GetObject()
    {
        return new Derived;
    }//GetObject
    
    int main()
    {
        Base *pBase = GetObject();
    
        cout << pBase->get_name() << endl;
    
        delete pBase;
    
        return 0;
    }//main

  5. #5
    Registered User
    Join Date
    Feb 2003
    Posts
    265
    Quote Originally Posted by Codeplug
    Base* GetObject()
    {
    return new Derived;
    }//GetObject
    Thats the problem, I need a way to call new with DYNAMIC input because we DONT KNOW the name of the module at compile time.

  6. #6
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    The only way is to use an object factory, like the GetObject() function.
    Code:
    Base* GetObject(const string &name)
    {
        if (name == "Derived")
            return new Derived;
    
        return NULL;
    }//GetObject
    gg

  7. #7
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Core contains a std::map<string,Module*> Modules.
    Core has a member function called AddModule(std::string modname)
    What i need to do is have Core.AddModule("DerivedClass1"); and it will do something along the lines of
    Code:
    if(!Modules[modname]) { Modules[modname] = new modname; }
    what's wrong with what you've got? just give Module a constructor that takes a const string (or char*), then continue on with what you had. Something like -

    Code:
    if(!Modules[modname]) { 
     Modules[modname] = new Module(modname); 
     } else { 
     Propagate(error::duplicate_record, "Record Already Exists for '%s'", modname.c_str());
     }
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  8. #8
    Registered User
    Join Date
    Feb 2003
    Posts
    265
    Quote Originally Posted by Codeplug
    The only way is to use an object factory, like the GetObject() function.
    Code:
    Base* GetObject(const string &name)
    {
        if (name == "Derived")
            return new Derived;
    
        return NULL;
    }//GetObject
    gg
    Your STILL USING THE STATIC NAME OF THE OBJECT TYPE IN THE CODE! Core does NOT know the name of ANY derived classes! It FIRST sees the name AT RUNTIME when bob types in "LOADMODULE bobs_derived_module". I need a way to convert INPUT to a TYPENAME so i can create an instance of it.

  9. #9
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    Quote Originally Posted by Codeplug
    The only way is to use an object factory, like the GetObject() function.
    There's your awnser.

    Here are all the different ways you can create an instance of Derived:
    Code:
    new Derived;
    Where that line of code is and how it gets executed is up to you.

    gg

  10. #10
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >
    > Core does NOT know the name of ANY derived classes!
    >

    I think he was just putting the idea across of using an object factory to create an instance of Module(), whether all that is necessary or not it's hard to say without a more concrete example of the classes in action.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  11. #11
    Registered User
    Join Date
    Feb 2003
    Posts
    265
    The line i gave as an example, Modules[modname] = new modname; is NOT real code, and will NEVER compile/run because modname is a std::string and as we all know new doesnt take strings as valid typenames. Its merely an example of the behavior im looking for. I do not know what the mechanism i need is called, or how to describe it as sofar nobody i have tried to explain it to has understood. Ill try again:

    Bob has my program, core and driver, compiled.
    Bob uses the newmodule.txt file (outlines required interface) to write an object compliant with the interface necessary to make it function with the rest of them.
    Bobs module called bobs_sexy_module is compiled.
    Bob links and executes the program, and once its running he types in LOADMODULE bobs_sexy_module
    At this point i need to create an instance of type bobs_sexy_module and im not sure how to do that. You cant simply typecast from a string to a typename that will make new happy.
    I can now access it via the baseclass pointer.

    Its the second to last step, auctually creating the object without knowing its type at compiletime that i need help with. Does this make sense?

    Im sorry for not being as polite as i should be, i do appreciate the help. Its been 3 days now, and most people are simply confused by what im trying to do or why. My examples are poorly writen i guess.

    Thanks for your time.

  12. #12
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    OK, here's one solution (it was raining outside so what the hell ):

    It uses templates hevily, so you'll need a relatively updated compiler (I used MSVC++)

    Here's the base code:
    Code:
    
    #include <vector>
    #include <iostream>
    #include <string>
    #include <map>
    #include <typeinfo>
    //
    // The base class for all modules
    //
    class Module
    {
    public:
    	virtual void someModuleThings()
    	{
    	}
    };
    //
    // DeepBlackMagic's Core class
    //
    typedef Module* (*ModuleCreator)();
    class Core
    {
    public:
    	static addModule(std::string name, ModuleCreator creator)
    	{
    		std::cout << "addModule(" << name << "," << creator << ")\n";
    		if (!moduleMap)
    			moduleMap = new std::map<std::string, ModuleCreator>();
    		(*moduleMap)[name] = creator;
    	}
    	static Module* newObject(std::string name)
    	{
    		if (!moduleMap)
    			moduleMap = new std::map<std::string, ModuleCreator>();
    		if ((*moduleMap)[name])
    			return (*moduleMap)[name]();
    		else
    			return 0;
    	}
    protected:
    	static std::map<std::string, ModuleCreator>* moduleMap;
    };
    //Create the static member
    std::map<std::string, ModuleCreator>* Core::moduleMap = 0; 
    
    //
    // This class adds class M to the list of modules on
    // creation
    //
    template <class M>
    class ModuleCreatorClass 
    {
    public:
    	ModuleCreatorClass()
    	{
    		//Add this module to the list of modules in Core
    		Core::addModule(typeid(M).name(), createThisModule);
    	}
     
    	//This function create a new M module
    	static Module* createThisModule()
    	{
    		return new M;
    	}
    };
    //
    // This function creates an object of class C
    // on instantiation
    //
    //
    // This is the class that new modules should
    // inherit from
    //
    template <class C>
    class NewModule:
    	public Module
    {
    public:
    	NewModule()
    	{
    		//Must reference the static object here
    		//so it's instantiated.
    		&obj;
    	}
    	static ModuleCreatorClass<C> obj;
    };
    template <class C>
    ModuleCreatorClass<C> NewModule<C>::obj;
    
    


    To be continued...
    Last edited by Sang-drax; 06-20-2004 at 07:36 AM.
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

  13. #13
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    >> sofar nobody ... has understood
    I understand perfectly what you're asking - you just don't understand how to apply the awnsers.

    >> At this point i need to create an instance of type bobs_sexy_module and im not sure how to do that.
    Here is how you do it. There are no alternatives. There are no workarounds. This is the way.
    Code:
    new bobs_sexy_module;
    As I said earlier, how that line of code gets executed is up to you.

    >> ... auctually creating the object without knowing its type at compiletime that i need help with.
    This is what an object factory is used for.

    >> Bob ... writes an object compliant with the interface...Bob links and executes the program...
    Bob will also have to update the object factory to return an instance of bobs_sexy_module.
    Code:
    Base* GetObject(const string &name)
    {
        if (name == "Derived")
            return new Derived;
        else if (name == "bobs_sexy_module")
            return new bobs_sexy_module; // added by bob
    
        return NULL;
    }//GetObject
    The only way to make this better is to use the concept of DLL's so bob doesn't have to recompile the main executable.

    gg

  14. #14
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    I REALLY HATE the new edit box

    When I pasted from VC++ it first looked nice with colors retained and everything, but when I posted everything was screwed up.

    I have to post the rest of the code here:

    Here's how you create a module with the above code:
    Code:
    //
    // Create a nice new module
    //
    class MyModule:
    	public NewModule<MyModule>
    {
    public:
    	MyModule()
    	{
    		std::cout << "MyModule is created.\n";
    	}
    	//Override module functiom
    	virtual void someModuleThings()
    	{
    		std::cout << "MyModule is in action!\n";
    	}
    };
    Here's a program that uses MyModule:
    Code:
    int main()
    {
    	Module* m = Core::newObject("class MyModule");
    	m->someModuleThings();
    	cin.get();
    }

    This works for me at least, alhtough I've tested it for about 30 seconds. The dangerous thing is the creation order of the static objects.
    What happens if ModuleCreatorClass<MyModule> is created before moduleMap is set to 0? Well...
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

  15. #15
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    Quote Originally Posted by DeepBlackMagic
    as sofar nobody i have tried to explain it to has understood.
    I have understood and my solution is working under MSVC++ 7.1.
    My trick is to inherit from a template class and to use static objects to initialize the map.
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 3
    Last Post: 10-28-2009, 09:25 AM
  2. Virtual Box
    By ssharish2005 in forum Tech Board
    Replies: 3
    Last Post: 02-12-2009, 05:08 AM
  3. Replies: 48
    Last Post: 09-26-2008, 03:45 AM
  4. C++ XML Class
    By edwardtisdale in forum C++ Programming
    Replies: 0
    Last Post: 12-10-2001, 11:14 PM
  5. Exporting Object Hierarchies from a DLL
    By andy668 in forum C++ Programming
    Replies: 0
    Last Post: 10-20-2001, 01:26 PM