熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

C++轉向C#要注意的幾個變化

2013-11-13 10:14:24  來源: .NET編程 

  引言

  每隔年左右編程人員就需要花費大量的時間和精力去學習新的編程技術年代是Unix和C年代是Windows和C++現在又輪到了微軟的NETFramework和C #盡管需要學習新的技術但由此帶來的好處卻遠高於付出的勞動幸運的是使用C#和NET進行的大多數工程的分析和設計與在C++和Windows中沒有本質的變化在本篇文章中我將介紹如何實現由C++到C#的飛躍

  已經有許多文章介紹過C#對C++的改進在這裡我就不再重復這些問題了在這裡我將重點討論由C++轉向C#時最大的變化由不可管理的環境向可管理的環境的變化此外我還會提出一些C#編程人員容易犯的錯誤供大家參考此外還將說明一些C#語言的能夠影響編程的新功能

  轉向可管理的環境

  C++的設計目標是低級的與平台無關的面向對象編程語言C#則是一種高級的面向組件的編程語言向可管理環境的轉變意味著你編程方式思考的重大轉變C#不再處理細微的控制而是讓架構幫助你處理這些重要的問題例如在C++中我們就可以使用new在棧中堆中甚至是內存中的某一特定位置創建一個對象

  在NET的可管理環境中我們再不用進行那樣細微的控制了在選擇了要創建的類型後它的位置就是固定的了簡單類型(intsdouble和long)的對象總是被創建在棧中(除非它們是被包含在其他的對象中)類總是被創建在堆中我們無法控制對象是創建在堆中哪個位置的也沒有辦法得到這個地址不能將對象放置在內存中的某一特定位置(當然也有突破這些限制的方法但那是很另類的方法)我們再也不能控制對象的生存周期C#沒有destructor碎片收集程序會將對象所占用的內存進行回收但這是非顯性地進行的

  正是C#的這種結構反映了其基礎架構其中沒有多重繼承和模板因為在一個可管理的碎片收集環境中多重繼承是很難高效地實現的

  C#中的簡單類型僅僅是對通用語言運行庫(CLR)中類型的簡單映射例如C#中的int是對SystemInt的映射C#中的數據類型不是由語言本身決定的而是由CLR決定的事實上如果仍然想在C#中使用在VisualBasic中創建的對象就必須使自己的編程習慣更符合CLR的規定

  另一方面可管理的環境和CLR也給我們帶來了好處除了碎片收集和所有NET語言中統一的數據類型外它還提供給我們一個功能強大的面向組件的編程語言無須對後期綁定提供特別的支持類型發現和後期綁定都是被內置在語言中的屬性是C#語言中的第一類的成員事件和代理也是

  可管理環境最主要的優點是NETFramework盡管在所有的NET語文中都可以使用這種框架但C#可以更好地使用NET框架中豐富的類接口和對象

  Traps

  C#看起來與C++非常相似這使得我們在由C++轉向C#時比較輕松但其中也有一些容易出錯的地方在C++中編寫得非常漂亮的代碼在C#中會不能通過編譯甚至會出現意想不到的結果C#與C++之間在語法上的變化並不大編譯器能夠發現這二者之間大部分的差異我在這裡就不再多費筆墨了在這裡我介紹幾個容易出問題的比較重要的變化

  引用類型和值類型

  在C#中值類型和引用類型數據是有區別的簡單類型(intlongdouble等)和結構屬於值類型數據類和對象屬於引用類型數據除非是包含在引用類型的變量中與在C++中一樣值類型變量的值存儲在棧中引用類型的變量也存儲在棧中但它的值是一個存儲在堆中的對象的地址這一點也與C++類似值類型變量是將自己的值傳遞給方法而引用類型變量則將自己的指針傳遞給方法

  結構

    C#中的結構與C++中有非常明顯的區別在C++中結構更象是類除了缺省的繼承外其缺省的訪問權限是public而不是private在C#中結構與類截然不同它是用來封裝輕型對象的是值類型的數據類型在傳遞時傳送的是變量的值而不是其地址此外它們也有一些不適用於類的限制例如它是不能繼承的也沒有除SystemValueType之外的基本類結構還不能定義一個缺省的constructor

  另一方面由於結構比類的效率要高因此它非常適合於創建輕型對象因此如果它的缺點對你的軟件沒有影響使用結構比使用類效率要高得多尤其是對於小對象而言

  所有的一切都是對象

  在C#中所有的東西都是由繼承Object得到的包括創建的類和intstructs等值類型的變量Object類提供了一些有用的方法例如ToString使用ToString的一個例子是與SystemConsoleWriteLine一起使用它可以接受一個字符串和許多對象與使用printf語句不同要使用WriteLine需要提供代換變量假設myEmployee是用戶定義的Employee類的一個實例myCounter是用戶定義的Counter類的一個實例

  
  ConsoleWriteLine(Theemployee:{}thecountervalue:{}
  myEmployeemyCounter);

  其中的WriteLine會調用每個對象的ObjectToString方法替換作為參數返回的變量如果Employee類不覆蓋ToString就會調用缺省的實現(由SystemObject繼承得到的)它將把類的名字作為一個字符串返回Counter會覆蓋ToString返回一個整型的變量因此上面代碼的輸出為

  
  Theemployee:Employeethecountervalue:

  如果向WriteLine傳遞一個整型變量會發生什麼情況呢?由於不能對整型變量調用ToString編譯器將自動將整型變量封裝在一個對象的實例中當WriteLine調用ToString時對象就會返回表示整型變量值的字符串下面的代碼就說明了這個問題

  類的使用

  
  usingSystem;
  //不覆蓋ToString的類
  publicclassEmployee
  {
  }
  //覆蓋了ToString的類
  publicclassCounter
  {
  privateinttheVal;
  publicCounter(inttheVal)
  {
  thistheVal=theVal;
  }
  publicoverridestringToString()
  {
  ConsoleWriteLine(CallingCounterToString());
  returntheValToString();
  }
  }

  
  publicclassTester
  {
  publicstaticvoidMain()
  {
  //創建類的實例
  Testert=new Tester();
  //調用非靜態成員
  //(mustbethroughaninstance)
  tRun();
  }
  //演示調用ToString的非靜態方法
  publicvoidRun()
  {
  EmployeemyEmployee=newEmployee();
  CountermyCounter=newCounter();
  ConsoleWriteLine(Theemployee:{}thecountervalue:{}
  myEmployeemyCounter);
  intmyInt=;
  ConsoleWriteLine(Herearetwointegers:{}and{}myInt);
  }
  }

  引用型參數和輸出型參數

  與C++中相同C#中的方法也只能有一個返回值在C++中我們通過將指針或索引作為參數而克服了這個限制被調用的方法改變其中的參數調用方法就可以得到新的值了

  向方法中傳遞一個索引作為參數時只能嚴格地按傳遞索引或指針所能夠提供的方式訪問原來的對象對於值類型變量而言就不能采用這種方法了如果要通過引用型參數傳遞值型變量就需要在其前面加上ref關健字如下所示

  
  publicvoidGetStats(refintagerefintIDrefintyearsServed)

  需要注意的是既需要在方法的定義中使用ref關健字也需要在對方法的實際調用中使用ref關健字

  
  FredGetStats(refagerefIDrefyearsServed);

  現在我們可以在調用方法中定義ageID和yearsServed變量並將它們傳遞給GetStats得到改變後的值

  C#要求明確的賦值也就是說在調用GetStats方法之前必須對ageID和yearsServed這三個局部變量進行初始化這一工作似乎有點多余因為我們僅僅使用它們從GetStats中得到新的變量的值為了解決這一問題C#提供了out關健字表示我們可以向方法中傳遞沒有被初始化的變量這些變量將通過引用變量的方式進行傳遞

  
  publicvoidGetStats(outintageoutintIDoutintyearsServed)

  當然了調用方法也必須作出相應的變化

  
  FredGetStats(outageoutIDoutyearsServed);


From:http://tw.wingwit.com/Article/program/net/201311/13017.html
  • 上一篇文章:

  • 下一篇文章:
  • 推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.