Currently, vs. Net occupies the vast majority of application development in windows. Therefore, many people engaged in VC ++ development have switched to more powerful vs. net. In this case, many developers are faced with the issue of using C ++ developed classes in C. The following describes in detail how to encapsulate a C ++ class with managed C ++ to provide it to C.
For example, there is a project named nativecppdll compiled by C ++, which outputs a cperson class. The specific code is as follows:
- // Nativecppdll. h
- # Pragma once
- # Ifndef lx_dll_class_exports
- # Define lx_dll_class _ declspec (dllexport)
- # Else
- # Define lx_dll_class _ declspec (dllimport)
- # Endif
- Class lx_dll_class cperson
- {
- Public:
- Cperson ();
- Cperson (const wchar_t * pname, const wchar_t csex, int iage );
- Void setname (const wchar_t * pname );
- Wchar_t * getname ();
- Void setsex (const wchar_t csex );
- Wchar_t getsex ();
- Void setage (INT iage );
- Int getage ();
- Wchar_t * getlasterror ();
- PRIVATE:
- Wchar_t m_szname [128];
- Wchar_t m_csex;
- Int m_iage;
- Wchar_t m_szlasterror [128];
- Void showerror ();
- };
- // Nativecppdll. cpp
- # Include "stdafx. H"
- # Include "nativecppdll. H"
- # Include <iostream>
- # Include <tchar. h>
- Using namespace STD;
- Cperson: cperson ()
- {
- Wcscpy_s (m_szname, _ T ("No Name "));
- M_csex = 'n ';
- M_iage = 0;
- Wcscpy_s (m_szlasterror, _ T ("no error "));
- }
- Cperson: cperson (const wchar_t * pname, const wchar_t csex, int iage)
- {
- Wcscpy_s (m_szlasterror, _ T ("no error "));
- Setname (pname );
- Setsex (csex );
- Setage (iage );
- }
- Void cperson: setname (const wchar_t * pname)
- {
- If (pname = NULL) | (wcslen (pname) = 0) | (wcslen (pname)> 127 ))
- {
- Wcscpy_s (m_szname, _ T ("No Name "));
- Wcscpy_s (m_szlasterror, _ T ("the length of the input name is out of range ."));
- Showerror ();
- Return;
- }
- Wcscpy_s (m_szname, pname );
- }
- Wchar_t * cperson: getname ()
- {
- Return m_szname;
- }
- Void cperson: setsex (const wchar_t csex)
- {
- If (csex! = 'F') & (csex! = 'M') & (csex! = 'M') & (csex! = 'F '))
- {
- M_csex = 'n ';
- Wcscpy_s (m_szlasterror, _ T ("the input sex is out of [F/M].");
- Showerror ();
- Return;
- }
- M_csex = csex;
- }
- Wchar_t cperson: getsex ()
- {
- Return m_csex;
- }
- Void cperson: setage (INT iage)
- {
- If (iage <0) | (iage> 150 ))
- {
- M_iage = 0;
- Wcscpy_s (m_szlasterror, _ T ("the input age is out of range ."));
- Showerror ();
- Return;
- }
- M_iage = iage;
- }
- Int cperson: getage ()
- {
- Return m_iage;
- }
- Wchar_t * cperson: getlasterror ()
- {
- Return m_szlasterror;
- }
- Void cperson: showerror ()
- {
- Cerr <m_szlasterror <Endl;
- }
This is a typical DLL developed by C ++ and outputs a complete C ++ class. What should I do if I want to develop a C # project and use the C ++ class cperson output from this DLL? For this example, cperson class is very small. You can use C # to re-write a class that is the same as the C ++ class. However, if the required C ++ class is large, or in many cases, the rewrite project will be very large. In this way, existing code is not reused, which wastes existing resources and is time-consuming and labor-intensive for development.
Of course, there are still ways to solve this problem. It is to encapsulate the C ++ class with managed C ++, and then provide it to C # for use. The following code is used to describe how to use hosted C ++ to encapsulate the above C ++ class.
First, create a DLL project managecppdll that hosts C ++, and add the following code to it:
- // Managecppdll. h
- # Pragma once
- # Define lx_dll_class_exports
- # Include "../nativecppdll. H"
- Using namespace system;
- Namespace managecppdll
- {
- Public ref class person
- {
- // Wrap all public member functions of cperson class
- Public:
- Person ();
- Person (string ^ strname, char csex, int iage );
- ~ Person ();
- Property string ^ name
- {
- Void set (string ^ strname );
- String ^ get ();
- }
- Property char sex
- {
- Void set (char csex );
- Char get ();
- }
- Property int age
- {
- Void set (INT iage );
- Int get ();
- }
- String ^ getlasterror ();
- PRIVATE:
- // The pointer of the class cperson, used to call the member functions of the class cperson
- Cperson * m_pimp;
- };
- };
From this header file, we can see that this is the packaging of C ++ class cperson. All public member functions of the class person are the same as those of the C ++ class cperson, except that the parameters and return values of the member functions are changed to the type that hosts C ++, this is also the first condition for class person to be used in C. Of course, you only need to encapsulate public member functions, and do not need to encapsulate them to protect Member functions and private member functions.
Class person only has one private member variable: a pointer to class cperson. The implementation of all member functions of the person class relies on the cperson pointer to call the corresponding member functions of the cperson class.
The specific implementation code is as follows:
- // Managecppdll. cpp
- # Include "stdafx. H"
- # Include "managecppdll. H"
- # Include <vcclr. h>
- Namespace managecppdll
- {
- // Create a cperson-like object in the constructor and destroy the object in the destructor
- // All member functions are implemented by using the m_pimp pointer to call the corresponding member functions of the cperson class.
- Person: Person ()
- {
- M_pimp = new cperson ();
- }
- Person: Person (string ^ strname, char csex, int iage)
- {
- // Convert string to a pointer that can be recognized by C ++
- Pin_ptr <const wchar_t> wcname = ptrtostringchars (strname );
- M_pimp = new cperson (wcname, csex, iage );
- }
- Person ::~ Person ()
- {
- // Delete the cperson object in the destructor
- Delete m_pimp;
- }
- Void person: Name: Set (string ^ strname)
- {
- Pin_ptr <const wchar_t> wcname = ptrtostringchars (strname );
- M_pimp-> setname (wcname );
- }
- String ^ person: Name: Get ()
- {
- Return gcnew string (m_pimp-> getname ());
- }
- Void person: Sex: Set (char csex)
- {
- M_pimp-> setsex (csex );
- }
- Char person: Sex: Get ()
- {
- Return m_pimp-> getsex ();
- }
- Void person: Age: Set (INT iage)
- {
- M_pimp-> setage (iage );
- }
- Int person: Age: Get ()
- {
- Return m_pimp-> getage ();
- }
- String ^ person: getlasterror ()
- {
- Return gcnew string (m_pimp-> getlasterror ());
- }
- };
If you want to use the class person in C #, first Add a reference to managecppdll. dll, and then you can use the class person like a common class C. For example, the following code:
- Using managecppdll;
- Person = new person ();
- Person. Name = "starlee ";
- Person. Sex = 'M ';
- Person. Age = 28;
If you are familiar with the design pattern, you will surely find that such a design is exactly the same as the bridge pattern. In fact, the above method is also a bridge mode, where the hosted C ++ serves as a bridge between classes used for C # development. In addition, this form can also be understood as the adapter mode. Hosting a C ++ class person is an adapter of the C ++ class cperson. Through this bridge, you can easily reuse the classes previously developed using C ++, so that these C ++ classes can continue to play their role in C #, making development more efficient.