程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 拷貝構造和賦值操作符,C#和本機C++代碼的互用性(4)

拷貝構造和賦值操作符,C#和本機C++代碼的互用性(4)

編輯:關於C語言

如果 C++ 類太復雜,你碰到的最大的互用性問題將會是本地和托管類型之間的參數轉換問題,這個過程稱為封送(marshaling)。托管擴展所做的 一個令人贊譽的工作是使這一過程盡可能輕松(例如,自動轉換原始數據類型和字符串 String),但有時你必須了解自己正在做什麼。

例如,你不能在沒有固定(pinning)住托管對象或嵌入對象的前提下,將其地址傳遞給本地函數。那是因為托管對象存在於托管堆中 ,垃圾收集器在托管堆中可以隨意重整對象。如果垃圾收集器移動某個對象,它能更新所有針對該對象的托管引用——但它對托管 環境以外的原始指針一無所知。那就是 __pin 的作用之所在;它告訴垃圾收集器:不要移動這個對象。對於字符串來說,框架有一個專門的函 數 PtrToStringChars,返回一個被固定住的本地字符指針。(順便提一下,對於那些好奇者來說,PtrToStringChars 是到目前為止定義在 <vcclr.h>文件中的唯一一個函數)。其代碼如下:

// PtrToStringChars, from vcclr.h
// get an interior gc pointer to the first character contained in a
// System::String object
//
inline const System::Char * PtrToStringChars(const System::String *s) {
  const System::Byte *bp = reinterpret_cast<const System::Byte *> (s);
  if( bp != 0 ) {
    unsigned offset = System::Runtime::CompilerServices::
       RuntimeHelpers::OffsetToStringData;
    bp += offset;
  }
  return reinterpret_cast<const System::Char*>(bp);
}

我在 MPerson 中使用 PtrToStringChars 來設置 Name,詳細代碼參見 Figure 3。

指針固定並不是你將遇到的僅有的互用性問題。如果你要處理數組,引用,結構和回調,或者存取某個對象中的嵌入對象,還會碰到其它的 問題。這是一些將來要討論的更高級的技術,如:StructLayout,框入/框出(boxing),__value 類型等等。你還需要專門的代碼來處理異常 (本地或托管)以及回調/委托。但不要讓這些戶用性細節遮住了大方向。首先確定你的調用方式(是從托管調用本地還是從本地調用托管), 如果你是從托管調用本地,是使用 P/Invoke 還是包裝器。

Visual Studio 2005 中(有些人已經開始用beta版了),托管擴展已更名 並升級到 C++/CLI。你可以把 C++/CLI 看成是 Managed Extensions Version 2,或者是 Managed Extensions 演變成的一個什麼。這個改變 幾乎都是語法上的,雖然也有一些重要的語義變化。總體上講,C++/CLI 是設計用來突出而不是模糊托管和本地對象間的差異。使用托管對象 的指針語法是明智的想法,但最終也許做的有些過於明智,因為它淡化了托管和本地對象之間的重要差異。C++/CLI 引入了一個處理托管對象 的關鍵概念,CLI 處理托管對象時使用 ^(讀作 hat)來代替 C 語言的指針語法:// handle to managed string
String^ s = gcnew String;

正像你已經明確注意到的,還有一個 gcnew 操作符用以來表示你是在托管堆中分配對象,而不是在本地分配。這樣 做有一個額外的好處是 gcnew 不會與 C++ 的 new 發生沖突,它能被重載或者甚至被重定義成一個宏。C++/CLI 有許多其它很棒的特性,專門 用來使互用性盡可能簡單明了。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved