Reference: http://www.cnblogs.com/flyingfish/archive/2007/06/05/772237.html
Object-oriented languages such as Java provide interfaces to implement interfaces, but C ++ does not. Although C ++ implements interfaces through pure virtual base classes, for example, the C ++ Implementation of COM is implemented through the pure virtual base class (of course, the com Implementation of MFC uses Nested classes), but we prefer to see something like interface. The following describes a solution.
First, we need some macros:
//
// Interfaces. h
//
# Define interface class
# Define declareinterface (name) interface name {\
Public :\
Virtual ~ Name (){}
# Define declarebasedinterface (name, base) Class Name:
Public base {\
Public :\
Virtual ~ Name (){}
# Define endinterface };
# Define implements public
With these macros, we can define our interfaces as follows ://
// Ibar. h
//
Declareinterface (IBAR)
Virtual int getbardata () const = 0;
Virtual void setbardata (INT ndata) = 0;
Endinterface
Isn't it like the macros for message ing in MFC? friends who are familiar with MFC must be familiar with it.
Now we can implement our interface as follows ://
// Foo. h
//
# Include "basicfoo. H"
# Include "Ibar. H"
Class FOO: Public basicfoo, implements Ibar
{
// Construction & Destruction
Public:
Foo (int x): basicfoo (X)
{
}
~ Foo ();
// Ibar implementation
Public:
Virtual int getbardata () const
{
// Add your code here
}
Virtual void setbardata (INT ndata)
{
// Add your code here
}
};
It's easy. We can use interfaces in C ++ without much effort. However, since this is not directly supported by the language itself, we need to follow some rules:
A) When declaring a class, if your class must inherit from another class besides the Interface Class (Structure Inheritance, that is, the is a relation ), this class is used as the first base class, just as we usually do. For example, cframewnd inherits from cwnd, cbitmapbutton inherits from cbutton, and cmydialog inherits from cdialong. This is especially important when you want to derive from the MFC class. declare them as the first base class to avoid damaging the runtimeclass mechanism of the MFC.
B) keep up with other base classes, and keep up with as much as you need. For example: Class FOO: Public basicfoo, implements
Ibar, ImplementsIother, ImplementsIWhatever,...
C) do not declare any member variables in the interface class. The interface class is only used to describe behavior rather than data. This prevents data members from being inherited from the same interface class multiple times.
D) All member functions of the interface class are defined as pure virtual functions. This ensures that your implementation class implements all these functions. Of course, you can also implement some functions in the abstract class, as long as you implement the remaining functions in your derived class.
E) do not derive your interface class from any other class except the interface class. Declarebasedinterface () can achieve this. normal classes can choose to implement the basic interface or derived interface, the latter means that both must be implemented.
F) assigning a pointer to the class implementing the interface to a pointer pointing to the interface class does not require forced type conversion, however, in turn, assigning a pointer to an interface class to a pointer to the class implementing this interface requires an explicit forced type conversion. In fact, we may use multiple inheritance, so that we cannot use old-fashioned conversions for these conversions. However, using the runtime type information (using the/GR option) and dynamic type conversion can work well and of course be safer.
G) In addition, dynamic_cast provides you with a way to query whether an object or interface has implemented a specified interface.
H) You must be very careful to avoid naming conflicts between different interface functions.
If you carefully observe the declareinterface and
Declarebasedinterfaca macro, you will find that an operation is required: each interface class has a virtual destructor. You may think this is not important, but without this, it may cause some problems. Let's look at the example below: As you can see, there is a class factory, it creates an Ibar implementation based on the bartype. After you use it, you certainly want to delete the object, as shown below:
Int main ()
{
Ibar * pbar = barfactory: createbar (FOO );
Pbar-> setname ("myfoobar ");
// Use pbar as much as you want,
//
// And then just delete it when it's no longer needed
Delete pbar; // oops!
}
What Delete pbar does depends on whether the object has a virtual destructor. If Foo does not have a virtual destructor, only Ibar's implicit empty destructor will be called, And Foo's destructor will not be called, resulting in Memory leakage. The declaration of virtual destructor in the interface class avoids this situation. It ensures that each class implementing the interface has a virtual destructor.
When you use declareinterfac, remember to use endinterface to match it. The interface macro and implements macro only replace Class and public, which seem redundant, but I think they are more explicit in expressing the intent of the Code. If I write this: Class
Foo: Public Ibar. You may think this is just a simple inheritance. But if I write: Class FOO: Implements Ibar, you will see its actual values and intentions-this is an implementation of an interface, rather than a simple inheritance.
Declareinterface (IBAR)
Virtual lpctstr getname () const = 0;
Virtual void setname (lpctstr name) = 0;
Endinterface
Class FOO: Implements Ibar
{
// Internal data
PRIVATE:
Char * m_pname;
// Construction & Destruction
Public:
Foo ()
{
M_pname = NULL;
}
~ Foo ()
{
Releasename ();
}
// Helpers
Protected:
Void releasename ()
{
If (m_pname! = NULL)
Free (m_pname );
}
// Ibar implementation
Public:
Virtual const char * getname () const
{
Return m_pname
}
Virtual void setname (const char * name)
{
Releasename ();
M_pname = _ strdup (name );
}
};
Class barfactory
{
Public:
Enum bartype {FAA, random, fii, Foo, fuu };
Static Ibar createnewbar (bartype)
{
Switch (bartype)
{
Default:
Case FAA:
Return new FAA;
Case when:
Return new response;
Case FII:
Return new FII;
Case FOO:
Return new Foo;
Case fuu:
Return new fuu;
}
}