在C#中使用C++編寫的類——用託管C++進行封裝[轉]

來源:互聯網
上載者:User

標籤:

現在在Windows下的應用程式開發,VS.Net佔據了絕大多數的份額。因此很多以前搞VC++開發的人都轉向用更強大的VS.Net。在這種情況 下,有很多開發人員就面臨了如何在C#中使用C++開發好的類的問題。下面就用一個完整的執行個體來詳細說明怎樣用託管C++封裝一個C++類以提供給C#使 用。
 

  比如,現在有一個工程名為NativeCppDll的由C++編寫的DLL,裡面輸出了一個CPerson類。下面是具體的代碼:
  1. // NativeCppDll.h
  2. #pragma once
  3. #ifndef LX_DLL_CLASS_EXPORTS
  4.     #define LX_DLL_CLASS __declspec(dllexport)
  5. #else
  6.     #define LX_DLL_CLASS __declspec(dllimport)
  7. #endif
  8. class LX_DLL_CLASS CPerson
  9. {
  10. public:
  11.     CPerson();
  12.     CPerson(const wchar_t *pName, const wchar_t cSex, int iAge);
  13.     void SetName(const wchar_t *pName);
  14.     wchar_t * GetName();
  15.     void SetSex(const wchar_t cSex);
  16.     wchar_t GetSex();
  17.     void SetAge(int iAge);
  18.     int GetAge();
  19.     wchar_t * GetLastError();
  20. private:
  21.     wchar_t m_szName[128];
  22.     wchar_t m_cSex;
  23.     int m_iAge;
  24.     wchar_t m_szLastError[128];
  25.     void ShowError();
  26. };
  27. // NativeCppDll.cpp
  28. #include "stdafx.h"
  29. #include "NativeCppDll.h"
  30. #include 
  31. #include 
  32. using namespace std;
  33. CPerson::CPerson()
  34. {
  35.     wcscpy_s(m_szName, _T("No Name"));
  36.     m_cSex = ‘N‘;
  37.     m_iAge = 0;
  38.     wcscpy_s(m_szLastError, _T("No Error"));
  39. }
  40. CPerson::CPerson(const wchar_t *pName, const wchar_t cSex, int iAge)
  41. {
  42.     wcscpy_s(m_szLastError, _T("No Error"));
  43.     SetName(pName);
  44.     SetSex(cSex);
  45.     SetAge(iAge);
  46. }
  47. void CPerson::SetName(const wchar_t *pName)
  48. {
  49.     if ((pName == NULL) || (wcslen(pName) == 0) || (wcslen(pName) > 127))
  50.     {
  51.         wcscpy_s(m_szName, _T("No Name"));
  52.         wcscpy_s(m_szLastError, _T("The length of the input name is out of range."));
  53.         ShowError();
  54.         return;
  55.     }
  56.     wcscpy_s(m_szName, pName);
  57. }
  58. wchar_t * CPerson::GetName()
  59. {
  60.     return m_szName;
  61. }
  62. void CPerson::SetSex(const wchar_t cSex)
  63. {
  64.     if ((cSex != ‘F‘) && (cSex != ‘M‘) && (cSex != ‘m‘) && (cSex != ‘f‘))
  65.     {
  66.         m_cSex = ‘N‘;
  67.         wcscpy_s(m_szLastError, _T("The input sex is out of [F/M]."));
  68.         ShowError();
  69.         
  70.         return;
  71.     }
  72.     m_cSex = cSex;
  73. }
  74. wchar_t CPerson::GetSex()
  75. {
  76.     return m_cSex;
  77. }
  78. void CPerson::SetAge(int iAge)
  79. {
  80.     if ((iAge < 0) || (iAge > 150))
  81.     {
  82.         m_iAge = 0;
  83.         wcscpy_s(m_szLastError, _T("The input age is out of range."));
  84.         ShowError();
  85.         return;
  86.     }
  87.     m_iAge = iAge;
  88. }
  89. int CPerson::GetAge()
  90. {
  91.     return m_iAge;
  92. }
  93. wchar_t * CPerson::GetLastError()
  94. {
  95.     return m_szLastError;
  96. }
  97. void CPerson::ShowError()
  98. {
  99.     cerr << m_szLastError << endl;
  100. }

   這是一個很典型的由C++開發的DLL,輸出一個完整的C++類。如果現在要求開發一個C#工程,需要用到這個DLL中輸出的C++類CPerson,該怎麼辦呢?針對這個例子來說,類CPerson非常小,可以用C#重新寫一個跟這個C++類一樣的類。可是,如果需要的C++類很大,或者很多的時候,重寫工程將非常龐大。而且這樣沒有對現有的代碼進行重用,浪費了現有資源,開發起來費時費力。
   當然,還是有方法解決這個問題的。那就是用託管C++將C++類給封裝一下,然後再提供給C#來使用。下面就用代碼來詳細說明怎樣用託管C++來封裝上面的那個C++類。
   首先,要建立一個託管C++的DLL工程ManageCppDll,然後在裡面添加下面的代碼:   

  1. // ManageCppDll.h
  2. #pragma once
  3. #define LX_DLL_CLASS_EXPORTS
  4. #include "../NativeCppDll/NativeCppDll.h"
  5. using namespace System;
  6. namespace ManageCppDll 
  7. {
  8.     public ref class Person
  9.     {
  10.     // 封裝所有類CPerson的公有成員函數
  11.     public:
  12.         Person();
  13.         Person(String ^ strName, Char cSex, int iAge);
  14.         ~Person();
  15.         property String ^ Name
  16.         {
  17.             void set(String ^ strName);
  18.             String ^ get();
  19.         }
  20.         property Char Sex
  21.         {
  22.             void set(Char cSex);
  23.             Char get();
  24.         }
  25.         property int Age
  26.         {
  27.             void set(int iAge);
  28.             int get();
  29.         }
  30.         String ^ GetLastError();
  31.     private:
  32.         // 類CPerson的指標,用來調用類CPerson的成員函數
  33.         CPerson *m_pImp;
  34.     };
  35. };

   從這個標頭檔就能看出來,這是對C++類CPerson的封裝。類Person的所有公有成員函數都跟C++類CPerson一樣,只不過成員函數的參數和傳回值就改成了託管C++的類型,這也是讓類Person能在C#中使用的首要條件。當然只需要對公有成員函數進行封裝,對於保護成員函數和私人成員函數則不必做任何封裝。
   類Person僅有一個私人的成員變數:一個類CPerson的指標。而類Person的所有成員函數的實現都是靠這個CPerson指標來調用類CPerson的相應成員函數來實現。
   下面是具體的實現代碼:

  1. // ManageCppDll.cpp
  2. #include "stdafx.h"
  3. #include "ManageCppDll.h"
  4. #include 
  5. namespace ManageCppDll 
  6. {
  7.     // 在建構函式中建立類CPerson的對象並在解構函式中將該對象銷毀
  8.     // 所有的成員函數實現都是通過指標m_pImp調用類CPerson的相應成員函數實現
  9.     Person::Person()
  10.     {
  11.         m_pImp = new CPerson();
  12.     }
  13.     Person::Person(String ^ strName, Char cSex, int iAge)
  14.     {
  15.         // 將string轉換成C++能識別的指標
  16.         pin_ptr<</SPAN>const wchar_t> wcName = PtrToStringChars(strName);
  17.         m_pImp = new CPerson(wcName, cSex, iAge);
  18.     }
  19.     Person::~Person()
  20.     {
  21.         // 在解構函式中刪除CPerson對象
  22.         delete m_pImp;
  23.     }
  24.     void Person::Name::set(String ^ strName)
  25.     {
  26.         pin_ptr<</SPAN>const wchar_t> wcName = PtrToStringChars(strName);
  27.         m_pImp->SetName(wcName);
  28.     }
  29.     String ^ Person::Name::get()
  30.     {
  31.         return gcnew String(m_pImp->GetName());
  32.     }
  33.     void Person::Sex::set(Char cSex)
  34.     {
  35.         m_pImp->SetSex(cSex);
  36.     }
  37.     Char Person::Sex::get()
  38.     {
  39.         return m_pImp->GetSex();
  40.     }
  41.     void Person::Age::set(int iAge)
  42.     {
  43.         m_pImp->SetAge(iAge);
  44.     }
  45.     int  Person::Age::get()
  46.     {
  47.         return m_pImp->GetAge();
  48.     }
  49.     String ^ Person::GetLastError()
  50.     {
  51.         return gcnew String(m_pImp->GetLastError());
  52.     }
  53. };

   如果要在C#中使用類Person,首先要添加對ManageCppDll.dll的引用,然後就可以像用普通的C#類一樣的使用類Person了。比如下面這樣的代碼:

  1. using ManageCppDll;
  2. Person person = new Person();
  3. person.Name = "StarLee";
  4. person.Sex = ‘M‘;
  5. person.Age = 28;

   熟悉設計模式的看了上面的代碼肯定會發現,這樣的設計跟BRIDGE模式如出一轍。其實,上面的方法也算是一種BRIDGE模式,由託管C++充當了C#中使用用C++開發的類的橋樑。另外,這種形式也可以理解為ADAPTER模式,託管C++類Person就是C++類CPerson的一個適配器。通過這個橋樑,可以很容易的重用以前用C++開發的類,讓這些C++類繼續在C#中發揮它們的效用,讓開發變得事半功倍。

 

部落格來源:http://blog.csdn.net/starlee/article/details/2864588

在C#中使用C++編寫的類——用託管C++進行封裝[轉]

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.