Dynamic 2: Create an object by a class name

xiaoxiao2021-03-06  51

Foreword: Like the same above, this article is from the question of another friend (see post http://community.9cbs.net/expert/topic/3202/3202729.xml?temp=5.602664e-02)

C is not a dynamic language, so it is possible to achieve dynamic creation of classes from the language mechanism, but such demand may exist, a similar example is the Create method of the CWnd class in the MFC, its first parameter is Window Class Name, this allows users to create the corresponding window through the name of Class.

To achieve this, there must be a "management center" for the name of the registration class, and can call a method through the name to create the corresponding class. Combine the design idea of ​​the class factory, here we let the base class in the inheritance system as a "management center", which maintained the necessary information of all derived classes, including class names and factory functions, these two must establish mapping relationships, MAP is a good choice. After defining a derived class, it will automatically register with the base class, but how to automatically? Let's take a look at the program first:

/ / For the convenience of writing, the following code is in the .cpp file

#ifDef _MSC_VER

#pragma

WARNING (Disable: 4786)

#ENDIF

#include

#include

Using

Namespace

STD;

Class Base

{

PUBLIC:

Virtual

Void print ()

// Test

{

Cout <<

"This is base" << ENDL;

}

protected:

TYPEDEF BASE * (* ClassGen) ();

// Declaration function pointer

Static

Void

Register (const)

Char * class_name, Classgen Class_Gen

// Registration function

{

Class_set.insert (Map

Char *, classgen> :: value_type (class_name, class_gen);

}

PUBLIC:

Static Base * Create (Const

Char * class_name)

// Factory function

{

Map

Char *, Classgen> :: item;

IF (item_set.Find (class_name))! = class_set.end ())

{

Return ((* iter). Second) ();

}

Return NULL;

}

protected:

Static Map

CHAR *, CLASSGEN> CLASS_SET;

// Storage subclass information

}

Map

CHAR *, BASE :: Classgen> Base :: Class_Set

// Static member variable definition

Class Derived:

Public Base

{

PUBLIC:

Struct DerivedRegister

// Auxiliary class for registration

{

DerivedRegister ()

{

// Register the subclass, although Map can guarantee unique, but still register once

Static

Bool bregistered =

False;

IF (! BREGISTERED)

{

Base ::

REGISTER

"Derived", Derived :: Create);

// Register subclass information

Bregistered = true;

}

}

}

static base * create ()

// Factory function

{

Return

New deerid;

}

PUBLIC:

Virtual

Void print ()

// Test

{

Cout <<

"This is deive" << Endl;

}

}

Static Derived :: DeriveDregister Derived_for_registering;

// There is no other mechanism to ensure that the registration function is called in the global space.

/ / Must not have, define a global variable to complete this glorious task, it looks a bit

int main ()

{

Base * Pderived = Base :: CREATE

"Derived");

// Class name can be dynamically entered

IF (Pderived) Pderived-> Print ();

// Create a successful call virtual function

Else Cout <<

"Crete error" << endl;

SYSTEM

"PAUSE");

Return 0;

}

This is true, some friends may feel very troublesome, in fact, we will use the macro definition to transform it, it will be very beautiful, the code will see it. Still talk about the automatic registration function, first, why do you want to automatically register? This is to maximize the implementation, actually use manual registration, but we have to call each class's registration function one by one in the main function. So how do we realize automatic registration? The method is to place the registration code into a buffer-auxiliary class constructor, then define a static global variable of such a class, so that the constructor is called, :), the disadvantage is more than an additional object, except for the registration It doesn't use it, and I didn't use the auxiliary class, but directly registered in the constructor of the derived class, and then define the global variables of the school, which clearly wasts space, and uses the auxiliary class to reduce the minimum overhead. ).

Let us look at the way to use the macro:

#ifDef _MSC_VER

#pragma

WARNING (Disable: 4786)

#ENDIF

#include

#include

Using

Namespace

STD;

// Used to declare the base class with 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

Char *, classgen> :: value_type (class_name, class_gen); /

} /

PUBLIC: /

Static Base * Create (Const

Char * class_name) /

{/

Map

Char *, Classgen> :: item; /

IF ((iter = class_set.find (class_name))! = Class_Set.end ()) /

{/

Return ((* iter). Second (); /

} /

Return NULL; /

} /

protected: /

Static Map

Char *, classgen> class_set; // is used to implement the base class

#define import_dyncrt_base (base) /

Map

CHAR *, BASE :: Classgen> Base :: Class_Set;

// Used to declare a class that can be created dynamically

#define declare_dyncrt_class (derived, base) /

PUBLIC: /

Struct Derived ## register /

{/

Derived ## register () /

{/

Static

Bool bregistered =

False; /

IF (! BREGISTERED) /

{/

Base ::

Register (#derived, crete); /

BREGISTERED =

True; /

} /

} /

}; /

static base * create () /

{/

Return

New deerive; /

}

// Used to implement a class that can be created dynamically

#define import_dyncrt_class (derived) /

Static Derived :: Derived ## register derived ## _ for_registering;

// Test

Class Base

{

Declare_Dyncrt_base (base)

// Declare the dynamic base class

Declare_DyncRT_Class (Base, Base)

// The base class can also create itself

PUBLIC:

Virtual

Void print ()

{

Cout <<

"This is base" << ENDL;

}

}

Implement_dyncrt_base (base)

// Realize the dynamic base class

Implement_dyncrt_class (base)

// Realize dynamic class

Class Derived:

Public Base

{

Declare_Dyncrt_class (derived, base)

// Declaration Dynamic Class

PUBLIC:

Virtual

Void print ()

{

Cout <<

"This is deive" << Endl;

}

}

Implement_dyncrt_class (derived)

// Realize dynamic class

int main ()

{

Base * PBase = Base :: Create

"Base");

// Class name can be dynamically entered

IF (PBASE) PBase-> Print ();

// Create a successful call virtual function

Else Cout <<

"CREATE BASE ERROR" << ENDL;

Base * Pderived = Base :: CREATE

"Derived");

// Class name can be dynamically entered

IF (Pderived) Pderived-> Print ();

// Create a successful call virtual function

Else Cout <<

"CREATE DERIVED ERROR" << ENDL;

SYSTEM

"PAUSE");

Return 0;

}

The above macro definition can be reused (if it is a bit of recognition, it is a similar macro when it is supported by serialization and dynamic creation, etc., when using, simply use these four macros, You can realize dynamic creation, it feels good, but reminds you that two of them should be placed in .cpp files.

This method still has some shortcomings, but this paper mainly provides a thinking, which can be changed according to the specific situation. (FreefalCon at 2004.09.19)

转载请注明原文地址:https://www.9cbs.com/read-115534.html

New Post(0)