亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

實例解析C++/CLI之值類型

2019-11-17 05:39:40
字體:
來源:轉載
供稿:網友

  值類型是一種輕量級的C++/CLI類機制,非常適合于小型的數據結構,且從語義的角度來看,與數值(Value)類似。

  與之相比,引用類型的實例--包括那些聲明在堆棧上的,是由垃圾回收器治理的,而值類型的實例卻不是。一般來說,一個值類較好的實現應只有一些數據成員,而不需要繼續性,這樣,在函數傳遞及返回值、或是賦值操作時,不會帶來巨大的數據開銷。

  值類初印像

  請看例1中的Point類,可以通過替換ref為value,來把一個引用類變為值類;與引用類(ref)相似,值類(value)也是一個包含了空格的要害字。與大家想像的一樣,值類(value)與值結構(value strUCt)之間唯一的區別就是,前者默認的可訪問性為PRivate,而后者則為public。

  例1:

using namespace System;
public value class Point
{
 int x;
 int y;
 public:
  //定義屬性X與 Y的讀寫實例
  property int X
  {
   int get() { return x; }
   void set(int val) { x = val; }
  }
  property int Y
  {
   int get() { return y; }
   void set(int val) { y = val; }
  }
  //定義實例構造函數
 
  Point(int xor, int yor)
  {
   X = xor;
   Y = yor;
  }
  void Move(int xor, int yor)
  {
   X = xor;
   Y = yor;
 }
 virtual bool Equals(Object^ obj) override
 {
  if (obj == nullptr)
  {
   return false;
  }
  if (GetType() == obj->GetType())
  {
   Point^ p = static_cast<Point^>(obj);
   return (X == p->X) && (Y == p->Y);
  }
  return false;
 }
 static bool Operator==(Point p1, Point p2)
 {
  return (p1.X == p2.X) && (p1.Y == p2.Y);
 }
 // static bool operator==(Point% p1, Point% p2)
 // {
 // return (p1.X == p2.X) && (p1.Y == p2.Y);
 // }

 // static bool operator==(Point& p1, Point& p2)
 // {
 // return (p1.X == p2.X) && (p1.Y == p2.Y);
 // }
 virtual int GetHashCode() override
 {
  return X ^ (Y << 1);
 }
 virtual String^ ToString() override
 {
  return String::Concat("(", X, ",", Y, ")");
 }
};
  值類自動繼續自System::ValueType,而System::ValueType則繼續自System::Object,但是,這卻不能顯式地聲明。值類隱式表明了為"sealed",也就是說,它不能被作為一個基類,另外,為其類成員指定一個protected是沒有任何意義,并且也是不答應的。假如想顯式聲明一個值類(或引用類),可像如下所示:

value class X sealed {/*...*/};
  請注重,此處沒有默認的構造函數。對一個值類來說,CLI本身把類實例中所有字段的位都設置為零,所以,不能提供自己的默認構造函數;然而,零、false、nullptr對其他類型來說,也許并不是合適的默認值,因此,對某些特定類型來說,就要用引用類型來取代值類型了。(遵從C++/CLI的實現會將false與nullptr表示為位全部為零。)

  值類的另一個限制是它們帶有一個默認的拷貝構造函數和一個賦值操作符,兩者都會進行逐位復制,并不可被重載。

  假如要實現Point類中的Equals函數,相比引用類中的而言要簡單一些。請記住,我們正在重載定義System::Object中的這個版本,而其接受一個Object^,因為這種類型的參數很可能有一個nullptr值,在此,先可以省去檢查是否為自身比較這一步,而對引用類的Equals實現來說,這一步是必需的,因為可有多個句柄引用同一對象。但是話說回來,在目前的這個值類中,沒有兩個值的實例可表示同一個實例,兩個相同的值實例,只代表兩個Point有相同的坐標,但修改其中一者的x坐標,不會影響到另一者的相同值。

  當一個Point的實例傳遞到Equals時,作為值類型(其最終也都繼續自System::Object)而言,裝箱就發生了--也就是說,在垃圾回收堆上分配了一個Object的實例,而其包含了傳遞進來Point的一份副本。因為是創建了一個新的對象,所以只有一個句柄,也不會有相同的其他Point。

  之前接受Point句柄的 == 操作符函數,現在已經精簡到一行,并且由接受句柄改為接受Point值,且用于選擇成員的指向操作符 -> 也被替換為點操作符。因為給定的值類型為sealed,所以與值類型參數Point唯一匹配的則為同類型的值了。同樣地,既無需檢查nullptr來確認是否為自身比較,也無需檢查傳遞進來的對象是否類型完全一致。

  而之前用于追蹤引用的 == 操作符函數基本上無需太多改動,但刪除了檢測同一類型這一部分。然而,這兩個== 操作符函數,最好只保留一個,以免在point1 == point2調用時引發歧義。(在聲明函數參數時,也可使用標準C++引用符&,而不是%,因為兩者可在本地類型與值類型之間互換。但由于這種類型的實例不存在于垃圾回收堆中,所以在垃圾回收期間不會改變它們的位置,因此也不需要對它們的位置進行追蹤。)

  例2使用了值類中的大多數成員,最主要的是它包含了靜態Point類的實例,而這在引用類中是不可能完成的。事實上,不只是不能有一個引用類的靜態實例,甚至也不能有一個此類型的靜態句柄。

  例2:


using namespace System;

Point p1;
static Point p2(3,4);

int main()
{
 static Point p3(4,7);

 Console::WriteLine("p2 is {0}", p2);
 Point% p4 = p3;

 Point p5 = p2;
 p5 = p2;

 Console::WriteLine("p1 == p2 is {0}", p1 == p2);
 Console::WriteLine("p1.Equals(p2) is {0}", p1.Equals(p2));
}
p2 is (3,4)
p1 == p2 is False
p1.Equals(p2) is False
  在第一次調用Console::WriteLine時,用傳值的方式傳遞進一個Point,但是,這個函數卻指望著接受一個對象引用,在此,Point值被自動裝箱,并把裝箱后的對象引用傳遞給函數。
  
  在定義中可看到,p5是由默認的拷貝構造函數初始化,而接下來的一行代碼,默認的賦值操作符把p2逐位復制給p5。 引用類與值類的差異

  假如我們在上述的Point引用類中加入一個ID號,用于跟蹤每個不同的Point引用對象,且再添加一個布爾類型的TraceID用于指明是否進行跟蹤;那么,把它改為值類之后,會有什么不同呢?

  再次提醒,是不能為一個值類定義默認構造函數、拷貝構造函數及賦值操作符的,但不幸的是,這些都是我們ID解決方案中所需用到的。在引用類版本的默認構造函數中,會將X與Y兩個坐標值、ID值都設置為零,并取得下一個ID賦給ID實例字段;反觀值類實現的版本,對以此方式構建的每個新Point,都是由默認為零值的ID構成,但是,我們卻想每個ID值為唯一。
 
  另一個類似問題也是由缺少顯式的拷貝構造函數造成的,在我們想要一個全新的對象時,值類的逐位復制卻造成新對象的ID與被拷貝對象的ID一樣。

  另外,在賦值時,假如我們只設置即有Point的值,那么Point的ID不應改變,也就是說,雖然任一或兩個坐標都可能改變,但它仍是同一Point對象,然而,逐位復制卻導致目標Point的ID被源對象ID覆蓋。

  雖然此處沒有列出包含ID的Point類,但例3中的程序顯示了引用類與值類的差異所在。

  例3:

using namespace System;

int main()
{
 Point::TraceID = true;

 Point p1, p2(3,7), p3(9,1), p4 = p2;
 Console::WriteLine("p1 = {0}", p1);
 Console::WriteLine("p2 = {0}", p2);
 Console::WriteLine("p3 = {0}", p3);
 Console::WriteLine("p4 = {0}", p4);
 p2 = p1;
 Console::WriteLine("p2 = {0}", p2);
}
  第一次運行后,4個Point的輸出如下:

Point p1, p2(3,7), p3(9,1), p4 = p2;
p1 = [0](0,0)
p2 = [0](3,7)
p3 = [1](9,1)
p4 = [0](3,7)
  Point p1由默認構造函數創建,它的ID為零,但卻恰好也是第一個Point的正確ID值,默認的坐標值也為零。而p2用到了自己編寫的構造函數,其分配了一個可用的ID,也就是零,這樣,我們有了兩個一樣的ID。

  同樣地,p3得到了ID值1,接下來,把p2逐位復制給p4,p4的ID與p2相同。在執行p2 = p1逐位復制之后,p1與p2兩個對象都有了相同的p1的ID。

  程序第二次運行后,輸出如下:

p1 = [0](0,0)
p2 = [2](3,7)
p3 = [3](9,1)
p4 = [2](3,7)
p2 = [0](0,0)
  在此可看到,p1的ID值總為零。

  顯而易見,引用類與值類是各有千秋,不是在每種場合,都可以調換使用的。 基本類型映射

  遵照標準C++的精神,對CLI值類型的基本類型映射,都已經全部在定義中實現了,就Microsoft Visual C++而言,映射關系如表1所示。

C++/CLI類型CLI值類型boolSystem::Booleanwchar_tSystem::Charsigned charSystem::SByteunsigned charSystem::BytecharSystem::SByte或 System::Byteshort intSystem::Int16unsigned short intSystem::UInt16int System::Int32unsigned intSystem::UInt32long long intSystem::Int64unsigned long long intSystem::UInt64floatSystem::SingledoubleSystem::Double    表1:C++/CLI與CLI值類的映射關系

  另外,還有一種值類型:System::Decimal,但沒有對應的C++/CLI類型。

  請看以下表達式,它們都涉及到訪問前述CLI值類型的靜態或實例成員。

Int32::MaxValue
Double::Parse("123.45e-1")
10.2f.ToString()
(10 + 5.9).ToString()
(100).ToString()
100 .ToString()
  因應Visual C++的映射,10.2f的類型為float,其映射為System::Single,并調用了其ToString函數;類似地,(10 + 5.9)類型為double,因此調用了System::Double的ToString。顯然,從語義的角度來看,帶有圓括號的100與其后帶有一個空格的100,這種寫法是多余的,但是,假如忽略它們,100與其后的句點將會解析為一個帶有標識符的double常量,這會導致語法錯誤。

  復數問題

  例4,演示了一個有著實部與虛部的復數的值類型。

  例4:


using namespace System;
public value class Complex
{
 double real;
 double imag;
 public:
  static initonly Complex i;
  static Complex()
  {
   i = Complex(0.0, 1.0);
  }
  Complex(double real)
  {
   this->real = real;
   this->imag = 0.0;
  }
  Complex(double real, double imag)
  {
   this->real = real;
   this->imag = imag;
  }
  property double Real
  {
   double get() { return real; }
   void set(double value) { real = value; }
  }
  property double Imag
  {
   double get() { return imag; }
   void set(double value) { imag = value; }
  }
  static Complex operator+(Complex z1, Complex z2)
  {
   return Complex(z1.real + z2.real, z1.imag + z2.imag);
  }
  static Complex operator-(Complex z1, Complex z2)
  {
   return Complex(z1.real - z2.real, z1.imag - z2.imag);
  }
  String^ ToString() override  
  {
   if (imag < 0.0)
   {
    return String::Format("({0} - {1}i)", real, -imag);
   }
   else if (1.0/imag == Double::NegativeInfinity)
   {
    return String::Format("({0} - 0.0i)", real);
   }
   else
   {
    return String::Format("({0} + {1}i)", real, +imag);
   }
  }
 };                                                                         
  CLI要求使用IEEE浮點表示法,這是一種比IEC 10559更正式的表示法,其中,零在single與double中表示為全部位為零。正因為此,所以可安全地使用CLI提供的默認構造值。

  程序中,定義了一個復數i,其表示-1的平方根,這樣,復數類型就可以提供具有此值的public只讀常量,而這是由一個public static成員及一個static構造函數共同完成的。因為Complex在此不是一個基本類型,所以i不能成為一個只讀(readonly)成員,因為無論如何,這都需要用一個常量表達式來初始化它,但這種事是不存在的。所以,我們能做的,就是讓i成為initonly,并在static構造函數中初始化它。例5是測試程序及輸出。

  例5:

using namespace System;
int main()
{
 Complex c1;
 Complex c2(12.5);
 Complex c3(-1.23, -4.5);
 Complex c4 = c2 + c3;
 Complex c5 = c2 - c3;

 Console::WriteLine("c1: {0}", c1);
 Console::WriteLine("c2: {0}", c2);
 Console::WriteLine("c3: {0}", c3);
 Console::WriteLine("c4: {0}", c4);
 Console::WriteLine("c5: {0}", c5);
 Console::WriteLine("i: {0}", Complex::i);
 Console::WriteLine("c3.Real: {0}", c3.Real);
 Console::WriteLine("c3.Imag: {0}", c3.Imag);
}

c1: (0 + 0i)
c2: (12.5 + 0i)
c3: (-1.23 - 4.5i)
c4: (11.27 - 4.5i)
c5: (13.73 + 4.5i)
i: (0 + 1i)
c3.Real: -1.23
c3.Imag: -4.5
  一些其他事項
  
  注重,一個值類型不應包含:

  ·類型為本地C++數組、本地類類型或位字段的數據成員

  ·包含局部類的成員函數

  ·為friend的成員

  ·析構函數

  一個傳值、傳址、傳引用、或追蹤引用的函數,可傳遞進或返回一個值類。

  在引用類T的實例構造函數或成員函數中,this的類型為"指向T的句柄",然而,對值類型而言,this為interior_ptr<T>。
 
像Point與Complex這樣的簡單值類型實例是完全自我包含的--但卻不是必須的,舉例來說,與引用類型相似,一個值類型也能包含指向本地堆的指針及垃圾回收堆中對象的句柄。在這種情況下,清理釋放值類型自身所占用的內存可不是一件簡單的事情,因為每種類型的數據成員在超出作用域時,都需要進行清理。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
91av在线播放视频| 成人h片在线播放免费网站| 91综合免费在线| 91在线网站视频| 亚洲最新在线视频| 欧美丝袜美女中出在线| 欧美激情一区二区三区在线视频观看| 91精品久久久久久久久中文字幕| 亚洲色图35p| 亚洲欧洲国产精品| 国产精品午夜一区二区欲梦| 亚洲精品一区二区三区不| 欧美视频一二三| 国产欧美欧洲在线观看| 国产精品美女视频网站| 久久五月情影视| 国产福利成人在线| 亚洲国产精品电影| 国产精品久久久久久中文字| 国产aaa精品| 国产国语刺激对白av不卡| 国产成人精品免费久久久久| 国产精品成人在线| 日韩久久精品成人| 色综合伊人色综合网| 亚洲黄一区二区| 精品久久久香蕉免费精品视频| 国产欧美日韩中文字幕在线| 中文字幕精品视频| 欧美视频免费在线观看| 68精品久久久久久欧美| 色噜噜狠狠色综合网图区| 国产精品日韩精品| 国产精品久久久久久婷婷天堂| 亚洲精品中文字幕女同| 亚洲高清久久久久久| 亚洲自拍偷拍视频| 超碰日本道色综合久久综合| 91亚洲国产成人精品性色| 中文字幕日韩欧美在线| 欧美大成色www永久网站婷| 亚洲电影免费观看高清| 亚洲r级在线观看| 日本不卡视频在线播放| 久久精品视频在线| 日韩一区视频在线| 欧美激情乱人伦一区| 欧美成人免费全部| 在线免费看av不卡| 最好看的2019的中文字幕视频| 97激碰免费视频| 91黑丝高跟在线| 成人国产精品一区| 成人福利免费观看| 欧美激情精品久久久久| 久久久久五月天| 亚洲国产高清福利视频| 久久综合伊人77777| 97视频色精品| 国产a级全部精品| 夜夜嗨av色综合久久久综合网| 国语自产在线不卡| 911国产网站尤物在线观看| 国产亚洲欧洲高清一区| 成人精品网站在线观看| 久久久在线免费观看| 国产精品91在线观看| 国产精品99蜜臀久久不卡二区| 亚洲国产成人久久综合| 久久韩国免费视频| 国产精品99久久99久久久二8| 欧美电影院免费观看| 北条麻妃99精品青青久久| 中文字幕亚洲激情| 日韩中文字幕在线视频播放| 久久精品国产一区二区电影| 日韩成人网免费视频| 亚洲人成在线观看| 亚洲va国产va天堂va久久| 欧美日韩成人在线观看| 欧美疯狂xxxx大交乱88av| 91久久国产精品91久久性色| 91黑丝在线观看| 国产精品久久婷婷六月丁香| 亚洲开心激情网| 亚洲在线观看视频| 国内精品久久久久| 久久久久女教师免费一区| 2019中文字幕免费视频| 亚洲最大的网站| 欧美洲成人男女午夜视频| 国产精品国产自产拍高清av水多| 国产精品揄拍一区二区| 成人久久久久久久| 国产精品亚洲一区二区三区| 国产精品高清免费在线观看| 中文字幕亚洲综合久久| 日本道色综合久久影院| 色诱女教师一区二区三区| 国产伊人精品在线| 国产日产亚洲精品| 欧美乱大交做爰xxxⅹ性3| 久久精品久久久久久| 欧美精品久久久久久久免费观看| 九九久久久久久久久激情| 久久五月天综合| 欧美区二区三区| 高清欧美一区二区三区| 综合网中文字幕| 欧美激情二区三区| 欧美午夜片欧美片在线观看| 亚洲欧美日韩中文在线制服| 国产伊人精品在线| 久久久极品av| 欧美乱人伦中文字幕在线| 亚洲人成网站免费播放| 亚洲成人激情视频| 国产视频丨精品|在线观看| 欧美精品成人91久久久久久久| 欧美激情视频在线| 亚洲大尺度美女在线| 日韩中文字幕在线免费观看| 日韩精品在线看| 国产区精品视频| 亚洲午夜av久久乱码| 91精品国产自产在线| 亚洲va国产va天堂va久久| 国产午夜精品理论片a级探花| 精品动漫一区二区三区| 久久视频在线视频| 亚洲免费电影一区| 成人性生交大片免费看视频直播| 综合网中文字幕| 中文字幕日韩精品在线观看| 久久这里只有精品99| 亚洲精品日韩久久久| 亚洲综合色av| 韩国三级日本三级少妇99| 久久精品国产亚洲精品2020| 中文字幕精品av| 日韩性生活视频| 亚洲二区在线播放视频| 久久精品国产99国产精品澳门| 欧美日韩视频在线| 中文字幕亚洲一区二区三区| 欧美裸体xxxx极品少妇软件| 高清亚洲成在人网站天堂| 久久精品免费电影| 91精品久久久久久久久| 992tv成人免费视频| 欧美性精品220| 68精品国产免费久久久久久婷婷| 精品国产老师黑色丝袜高跟鞋| 欧美日韩国产二区| 国产香蕉一区二区三区在线视频| 91久久中文字幕| 亚洲视频在线播放| 欧美精品久久久久久久久久| 亚洲第一精品电影| 国产丝袜高跟一区| 亚洲影视中文字幕| 日韩精品视频在线播放| 最新的欧美黄色| 久久资源免费视频|