Dynamic 2: Create an object by Class Name

Source: Internet
Author: User

Like in the same article, this article is based on answers to questions from another friend.
(See Post http://community.csdn.net/Expert/topic/3202/3202729.xml? Temp = 5.602664e-02)

C ++ is not a dynamic language, so it is impossible to dynamically create classes based on the language mechanism, but such requirements may exist, A similar example is the create method of the cwnd class in MFC. The first parameter is the name of window class, which allows users to create corresponding windows by class name.

To achieve this, you must have a "Management Center" used to register the class name and use the name to call a method to create the corresponding class. In combination with the design philosophy of the class factory, we use the base class in the inheritance system as the "Management Center" to maintain the necessary information of all derived classes, including class names and factory functions, the two must establish a ing relationship, and map is a good choice. After a derived class is defined, it automatically registers to the base class. But how does one implement automatic registration? Let's look at the program first:

// For ease of writing, the following code is located in the. cpp File
# Ifdef _ msc_ver
# Pragma warning (Disable: 4786)
# Endif
# Include <iostream>
# Include <map>
Using namespace STD;

Class base
{
Public:
Virtual void print () // for testing
{
Cout <"this is base" <Endl;
}
Protected:
Typedef base * (* classgen) (); // declare the function pointer
Static void register (const char * class_name, classgen class_gen) // registers the Function
{
Class_set.insert (Map <const char *, classgen>: value_type (class_name, class_gen ));
}
Public:
Static base * Create (const char * class_name) // factory function
{
Map <const char *, classgen>: iterator ITER;
If (iter = class_set.find (class_name ))! = Class_set.end ())
{
Return (* ITER). Second )();
}
Return NULL;
}
Protected:
Static Map <const char *, classgen> class_set; // stores subclass information.
};

Map <const char *, base: classgen> base: class_set; // static member variable definition

Class derived: public Base
{
Public:
Struct derivedregister // helper class for registration
{
Derivedregister ()
{// Register a subclass. Although map can be unique, it can only be registered once.
Static bool bregistered = false;
If (! Bregistered)
{
Base: Register ("derived", derived: Create); // register subclass Information
Bregistered = true;
}
}
};
Static base * Create () // factory function
{
Return new derived;
}
Public:
Virtual void print () // for testing
{
Cout <"This is derived" <Endl;
}
};

Static derived: derivedregister derived_for_registering; // There is no other mechanism to ensure that the registration function is called in the global space,
// As a last resort, defining a global variable to complete this glorious task seems a bit too busy

Int main ()
{
Base * pderived = base: Create ("derived"); // The class name can be dynamically entered.
If (pderived) pderived-> Print (); // call the virtual function after creation
Else cout <"create error" <Endl;
System ("pause ");
Return 0;
}

In this way, some friends may think it is very troublesome to use. In fact, if we use macro definition to transform it, it will be very beautiful and the code will be seen later. Let's talk about the automatic registration function. First, why should we implement automatic registration? This is to hide the implementation to the maximum extent. In fact, manual registration is acceptable, but we have to call the registration functions of each class one by one in the main function. So how do we implement automatic registration? The method is to put the registration code in the constructor of a helper class, and then define a static global variable of the class, so that the constructor will be called ,:), the disadvantage is that there is an additional object, except for registration, which does not have any usage (I did not use the helper class at first, but directly registered it in the constructor of the derived class, then define the global variables of the derived class, which will obviously waste space and reduce the additional overhead to a minimum using the helper class ).

Let's take a look at the macro Transformation:

# Ifdef _ msc_ver
# Pragma warning (Disable: 4786)
# Endif
# Include <iostream>
# Include <map>
Using namespace STD;

// Declare the base class with the dynamic creation Function
# Define declare_dyncrt_base (base )/
Public :/
Typedef base * (* classgen )();/
Static void register (const char * class_name, classgen class_gen )/
{/
Class_set.insert (Map <const char *, classgen>: value_type (class_name, class_gen ));/
}/
Public :/
Static base * Create (const char * class_name )/
{/
Map <const char *, classgen>: iterator ITER ;/
If (iter = class_set.find (class_name ))! = Class_set.end ())/
{/
Return (* ITER). Second )();/
}/
Return NULL ;/
}/
Protected :/
Static Map <const char *, classgen> class_set;

// Used to implement the base class
# Define implement_dyncrt_base (base )/
Map <const char *, base: classgen> base: class_set;

// Declare a class that can be dynamically created
# Define declare_dyncrt_class (derived, base )/
Public :/
Struct derived # register/
{/
Derived # register ()/
{/
Static bool bregistered = false ;/
If (! Bregistered )/
{/
Base: Register (# derived, create );/
Bregistered = true ;/
}/
}/
};/
Static base * Create ()/
{/
Return new derived ;/
}

// Implement a class that can be dynamically created
# Define implement_dyncrt_class (derived )/
Static derived: derived # register derived # _ for_registering;

// Test
Class base
{
Declare_dyncrt_base (base) // declare a dynamic base class
Declare_dyncrt_class (base, base) // You can also dynamically create the base class.
Public:
Virtual void print ()
{
Cout <"this is base" <Endl;
}
};

Implement_dyncrt_base (base) // implement the dynamic base class
Implement_dyncrt_class (base) // implement the dynamic class

Class derived: public Base
{
Declare_dyncrt_class (derived, base) // declare a dynamic class
Public:
Virtual void print ()
{
Cout <"This is derived" <Endl;
}
};

Implement_dyncrt_class (derived) // implement the dynamic class

Int main ()
{
Base * pbase = base: Create ("base"); // The class name can be dynamically entered.
If (pbase) pbase-> Print (); // call the virtual function after the creation is successful.
Else cout <"Create base error" <Endl;

Base * pderived = base: Create ("derived"); // The class name can be dynamically entered.
If (pderived) pderived-> Print (); // call the virtual function after creation
Else cout <"create derived error" <Endl;

System ("pause ");
Return 0;
}

The macro definition above can be reused (is it a bit familiar? Yes, similar macros are used in MFC for support for serialization and dynamic creation, you only need to simply use these four macros to achieve dynamic creation. It feels good, but one note is that both implement macros should be placed. CPP file.

This method still has some shortcomings, but this article mainly provides a way of thinking, you can make corresponding changes according to the specific situation.

(Freefalcon at 2004.09.19)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.