60
C++/CLI 概概 概概概 [email protected] (Email/MSN) 2007/1/25

Introduction to C++ over CLI

  • Upload
    -

  • View
    1.738

  • Download
    1

Embed Size (px)

DESCRIPTION

本講題將對C++/CLI做一個概觀性的介紹。在C++/CLI之前,.NET平台上的C++開發方案,多半只能選擇採用Managed C++。無可諱言的,Managed C++本身存在一些改善的空間,諸如:語法的優雅與寫作的流暢、對泛型程式設計的支援等等。然而,在著名的C++語言大師Stan Lippman及Herb Shtter加入VC++的團隊中時,重新制定後的C++/CLI卻讓這些問題得到了解決的方案。在Visual Studio 2005中,完全支援C++標準的C++/CLI加入了新語法及語義,針對.NET環境提供了最直接的支援。有了C++/CLI,原先標準的C++能力不僅不會受損,而C++/CLI中的標準擴充,也使得C++在.NET平台上獲得額外的加持。C++/CLI有了.NET的加持,一舉具備了reflection及垃圾回收的能力。.NET所提供的標準類別庫,也都可為其所用。再加上C++/CLI混合了unmanaged及managed兩種執行環境,更使得C++/CLI具備更多效率的空間,同時能夠開發系統層級的應用程式。有了C++/CLI,在.NET平台上的C++程式員如同取得一把新的寶劍。

Citation preview

Page 1: Introduction to C++ over CLI

C++/CLI 概觀C++/CLI 概觀

王建興[email protected]

(Email/MSN)2007/1/25

Page 2: Introduction to C++ over CLI

About QingAbout Qing

Education Ph.D. Candidate, Department of Computer Science, National

Tsing-Hua University, Taiwan Research interests: distribute network management, mobile agent,

VoIP, and p2p networking Software Development Skills

Programming languages: 80x86 assembly, C/C++, Java, C# J2EE development and Web programming: EJB, JSP/Servlet Network programming: TCP/IP, socket programming Object Oriented Design/Programming Design Patterns and Software Architecture Distributed Network Management System Peer-to-Peer Networking

Book Translation Thinking in Java 2nd Edition, in Traditional Chinese Essential C++, in Traditional Chinese

Page 3: Introduction to C++ over CLI

AgendaAgenda

何謂 C++/CLI C++/CLI中的型別宣告 Handle vs. Pointer Deterministic Destruction of C++/CLIS C++/CLI中的陣列 C++/CLI 對 Property的支援 C++/CLI的四種編譯模式 Templates 及 Generics C++/CLI的標準化

Page 4: Introduction to C++ over CLI

在 C++/CLI出現前, .NET上的 C++程式員恐怕只有一個字可以形容

在 C++/CLI出現前, .NET上的 C++程式員恐怕只有一個字可以形容

Page 5: Introduction to C++ over CLI

.NET上的 C++程式員為什麼悶? (1/2).NET上的 C++程式員為什麼悶? (1/2)

僅管有了Managed Extension for C++,但卻存在一些對程式員的困擾

不夠流暢優雅的語法 例如:雙底線的關鍵字們

對 CLI的支援不夠支接 例如:缺乏 for-each語法,不支援 property

C++ 與 .NET之間的整合不夠好 例如:無法在 CLI型別上使用 template,也無法在

C++型別上運用 CLI的機制,例如垃圾回收

*http://www.codeproject.com/managedcpp/cppcliintro01.asp

Page 6: Introduction to C++ over CLI

.NET上的 C++程式員為什麼悶? (2/2).NET上的 C++程式員為什麼悶? (2/2)

有兩種形式的指標: unmanaged 指標及 managed指標,其用法及表示容易造成混淆

無法產生 verifiable的程式碼

Page 7: Introduction to C++ over CLI

為什麼不學 C#就好了?為什麼不學 C#就好了?

多學一個程式語言 C++最佳化能力較強 C++具備 deterministic destruction(即使編譯為MSI

L) C++程式員在 C++的特性支持下,生產力較高

STL template specialization

Page 8: Introduction to C++ over CLI

好消息是…好消息是…

.Net上的 C++程式員不用再悶了

Page 9: Introduction to C++ over CLI

C++/CLI所帶來的拯救C++/CLI所帶來的拯救

優雅流暢的語法 對 CLI的直接支援

property,泛型,垃圾回收等機制全都有了直接的支援

在 unmanaged classes上這些機制也都適用 妥善的橋接 .NET 與 C++ 透過 C++/CLI編譯出來的程式碼,是 fully verifiable

*http://www.codeproject.com/managedcpp/cppcliintro01.asp

Page 10: Introduction to C++ over CLI

何謂 C++/CLI?何謂 C++/CLI?

C++所支援的靜態物件模型,目標放在對執行檔速度及大小的最佳化上

CLI則為一支援動態元件編程模型的多階架構 C++/CLI中的” /”,代表 C++ 與 CLI之間的 binding 何謂 C++/CLI

近似說法 1 : C++/CLI 將 C++靜態的物件模型繫結(bind) 至 CLI的動態元件模型

近似說法 2 : C++/CLI 將 .NET編程模型整合進到C++中

*Stanley B. Lippman, http://msdn.microsoft.com/msdnmag/issues/06/00/PureC/default.aspx

Page 11: Introduction to C++ over CLI

C++/CLI就是 C++ X CLIC++/CLI就是 C++ X CLI

確定性的記憶體管理 Template Native types STL 、 generic algorithms 指標 複製建構及指派

垃圾收集, finalizer 泛型 Reference 及 value types Interface Verifiability Security Properties, delegates,

events 功能強力的 BCL

C++的特點 CLI的特點

C++/CLI發揮 C++ 及 CLI的相乘效果

Page 12: Introduction to C++ over CLI

C++/CLI的目標就是C++/CLI的目標就是

無接縫式的整合Unmanaged 及 Managed Code

Page 13: Introduction to C++ over CLI

C++ 及 CLI物件模型的比較C++ 及 CLI物件模型的比較

物件儲存空間類型多樣化 static, stack, 以及 heap

物件的生命期類型多樣化 static object有著和程式相同的生命期

stack上的 object,則在和scope({…})的生命期相同

heap上的 object,則由程式員自行操控其生命期

物件建構及指派的深層拷貝模型

編譯時,原始碼中必須含括所有動用型別的資訊

物件儲存空間類型單純 Value type儲存於 stack Reference type儲存於

managed heap上 物件的生命期具不確定性

Reference types須倚靠垃圾收集器回收

物件的指派採淺層參考語義 編譯時,型別資訊由所使用型別的 metadata提供

C++的靜態物件模型 CLI的動態物件模型

Page 14: Introduction to C++ over CLI

C++/CLI中的型別宣告C++/CLI中的型別宣告

在 C++/CLI中可宣告下述型別

宣告語法 所宣告的型別

class N {…} C++原生類別(過去 C++程式員所用)

ref class R {…} CLR 的 reference type

value class V {…} CLR 的 value type

interface class I {…}

CLR 的 interface type

enum class E {…} CLR 的 enumeration type

Page 15: Introduction to C++ over CLI

C++ 與 CTS型別的對應C++ 與 CTS型別的對應

C++ Type CTS Signed Type CTS Unsigned Type

char Sbyte Byte

short int Int16 UInt16

int, __int32 Int32 UInt32

long int Int32 UInt32

__int64 Int64 UInt64

float Single N/A

double Double N/A

long double Double N/A

bool Boolean N/A

Page 16: Introduction to C++ over CLI

各型別的用途各型別的用途

原生型別 具備 native code的語義及優點 即使被編譯成MSIL亦如此

Reference Type 可被垃圾收集器回收,提供簡便的記憶體管理模式

Value Type 輕量級的型別(例如像整數之類的型別)

Interface Type 宣告 CLR中的介面型別

Enumeration Type 宣告 CLR中的列舉型別

Page 17: Introduction to C++ over CLI

例:在 C++/CLI中宣告 Reference Type例:在 C++/CLI中宣告 Reference Type

ref class Qing

{

public:

void sayHello();

};

void Qing::sayHello()

{

Console::WriteLine("Hello!");

}

多半宣告在 .h檔裡

多半宣告在 .pp檔裡

Page 18: Introduction to C++ over CLI

Handle vs. PointerHandle vs. Pointer

C++/CLI中將 native C++型別及 CLI型別區分開來 C++/CLI中同樣具備指向 CLI型別的”指標”,但採用了不同的符號來表示,同時賦予一個不同的名稱,以資區別 這個名稱就是 Handle(相對於 Pointer) 這個符號就是 ^(相對於 *)

建構 native C++型別及 CLI型別的關鍵字也已有所區隔 new:產生 native C++型別 gcnew:產生 CLI型別( gc 意指 garbage collected,垃圾回收之意)

Page 19: Introduction to C++ over CLI

透過 Handle建構並運用 CLI型別透過 Handle建構並運用 CLI型別

Qing ^qing = gcnew Qing();

qing->sayHello();

Page 20: Introduction to C++ over CLI

使用 Pointer 和 Handle的差異使用 Pointer 和 Handle的差異

Pointer用來在 native heap中配置空間 語法: T* t = new T; 指標指向的位置是穩定的(不受 GC 影響),甚至可以被轉型為 int

倘若未自行釋放記憶體( delete),則會產生memory leak

Handle用來在 managed heap中配置空間 語法: T^ t = gcnew T; GC 會自動釋放位於 managed heap中的物件所佔用的空間

但程式員仍可針對 managed heap上的物件呼叫 delete

Page 21: Introduction to C++ over CLI

不同的兩種物件生成及運用模式不同的兩種物件生成及運用模式

Native Managed

Pointer / Handle * ^

Reference & %

Allocate new gcnew

Free delete delete

Use Native Heap Use Managed

Heap

Use Stack

Verifiability * and & never ^ and % always

*Kate Gregory, “Moving C++ Applications to the Common Language Runtime”

Page 22: Introduction to C++ over CLI

於 Native/CLI型別中混用 Pointer/Handle (1/2)於 Native/CLI型別中混用 Pointer/Handle (1/2)

在 CLI型別中使用 Handle

在 CLI型別中使用 Pointer

ref class R

{

private:

String ^str;

}

ref class R

{

private:

std::string* str;

}

Page 23: Introduction to C++ over CLI

於 Native/CLI型別中混用 Pointer/Handle (2/2)於 Native/CLI型別中混用 Pointer/Handle (2/2)

在 Native型別中使用 Handle

gcroot<T>是用來包裝System.Runtime.InteropServices.GCHandle的一個template class

*http://www.codeproject.com/managedcpp/ijw_unmanaged.asp

class N

{

private:

gcroot<String^> str;;

}

Page 24: Introduction to C++ over CLI

Tracking Reference Operator %Tracking Reference Operator %

&之於 pointer,相當於%之於 handle

R1 ^pr1 = gcnew R1();

R1 %r1 = *pr1;

Console::WriteLine(r1.ToString());

不再是 ->同樣使用 *

Page 25: Introduction to C++ over CLI

Tracking Reference的效應Tracking Reference的效應

array<String^>^ arr = gcnew array<String^>(3);

int i = 0;

for each(String^% s in arr)

s = gcnew String(i++.ToString());

for each(String^ s in arr)

Console::WriteLine(s);

執行結果:012

array<String^>^ arr = gcnew array<String^>(3);

int i = 0;

for each(String^ s in arr)

s = gcnew String(i++.ToString());

for each(String^ s in arr)

Console::WriteLine(s);

執行結果:

Page 26: Introduction to C++ over CLI

CLI 的 Non-Deterministic FinalizationCLI 的 Non-Deterministic Finalization

CLI的垃圾回收機制,會在記憶體傾向不足時,將不再使用被物件佔用的記憶體空間回收再用

當物件佔用的記憶體空間確定被回收前的一刻,該物件的 Finalize() 會被呼叫,此即為 finalization(終始化)動作

Finalization執行的時機及是否會被執行任誰都說不得準 所以被稱為 non-deterministic finalization

Page 27: Introduction to C++ over CLI

DisposalDisposal

對於記憶體資源而言, non-deterministic finalization不成問題

但對非記憶體資料(例如資料庫、檔案), 面對 non-deterministic finalization的程式員得多費心才能使程式如預期的運作

對 .NET 而言,慣例上清理此類資料的動作,會定義於名為 Close() 或 Dispose()的方法中

但這麼一來,程式員得自行呼叫 Close() 或 Dispose()來進行清理動作

Page 28: Introduction to C++ over CLI

Deterministic DestructionDeterministic Destruction

C++/CLI 除了 CLI上原先就有的 finalizer之外,還提供了 destructor.

ref class R1

{

public:

R1() {}

~R1() {}

protected:

!R1() {}

};

constructor

destructor

finalizer

* 注意: C++/CLI 使用了 C# 中用來表示 Finalizer 的符號來表示 Destructor

Page 29: Introduction to C++ over CLI

Finalizer vs. DestructorFinalizer vs. Destructor

C++/CLI中的 Destructor最終會被編譯成為 Dispose(),如果用 C#的相對應程式碼來看的話,會像是:

GC::SuppressFinalize() 會要求系統不要呼叫物件的finalizer(),避免物件被清理兩次

public void Dispose()//IDisposable::Dispose

{

GC.SuppressFinalize(this);

}

*http://www.codeproject.com/managedcpp/cppclidtors.asp*http://msdn2.microsoft.com/en-us/library/system.gc.suppressfinalize.aspx

Page 30: Introduction to C++ over CLI

Why SuppressFinalize? Why SuppressFinalize?

public class FileStream : Stream {

public override void Close() {

// Clean up this object: flush data and close file

// There is no reason to Finalize this object now

GC.SuppressFinalize(this);

}

protected override void Finalize() {

Close(); // Clean up this object: flush data and close file

}

// Rest of FileStream methods go here

}*http://www.codeproject.com/managedcpp/cppclidtors.asp

如果程式員自行呼叫了 Close(),但 GC又呼叫了 Finalize()便會引發Close()被叫用兩次

Page 31: Introduction to C++ over CLI

自動進行的 Disposal自動進行的 Disposal

{

SqlConnection conn(connString);

}

constructor 會被呼叫

destructor 會被自動呼叫

{

SqlConnection ^pConn = gcnew SqlConnection(connString);

}

constructor 會被呼叫

之後就要等待 GC 動作了

Page 32: Introduction to C++ over CLI

C++/CLI中的陣列C++/CLI中的陣列

使用Managed Heap 的 Managed Array,其基礎型別皆為 System::Array 使用 C++/CLI的陣列時,可以想像存在一個虛擬的 template

http://www.codeproject.com/managedcpp/cppcliarrays.asp

namespace stdcli::language

{

template<typename T, int rank = 1>

ref class array : System::Array {};

}

Page 33: Introduction to C++ over CLI

陣列定義語法陣列定義語法

一維陣列語法

多維度陣列語法

array<String ^>^strArray = gcnew array<String ^>(10);

for(int i=0;i<strArray->Length;i++)

{

strArray[i] = ""+i;

Console::WriteLine(strArray[i]);

}

array<String ^, 3>^strArray = gcnew array<String ^, 3>(4, 3, 2);

維度 每個維度的長度

Page 34: Introduction to C++ over CLI

陣列的初始化陣列的初始化

array<String^>^ strarr = gcnew array<String^> {“String1", “String2"};

array<String^>^ strarr2 = {“String1", “String2"};

array<Object^,2> ^ objarr = {{“String1", 1}, {“String2", 2}};

Page 35: Introduction to C++ over CLI

參數陣列參數陣列

C++/CLI支援參數陣列,參數陣列必須是最後一個參數 用…來標示參數陣列

void testParamArray(String ^s, ... array<String ^>^ params)

{

Console::WriteLine(s+": ");

for(int i=0;i<params->Length;i++)

Console::WriteLine(params[i]);

}

int main(array<System::String ^> ^args)

{

testParamArray("Hello", "qing");

testParamArray("Hello", "qing", "chrisma");

}

Page 36: Introduction to C++ over CLI

Property的語法Property的語法

ref class UserAccount {

public:

property String^ ID {

String^ get(){return id;}

virtual void set(String^ value){id = value;}

}

private:

String^ id;

};

就和 C# 的定義方式類似

Page 37: Introduction to C++ over CLI

Index Property的語法Index Property的語法

ref class OnlineUserList{

public:

property UserAccount^ User[int] {

UserAccount^ get(int idx){return (UserAccount^) alUser[idx];}

}

OnlineUserList()

{

alUser = gcnew System::Collections::ArrayList();

}

// …

private:

System::Collections::ArrayList ^alUser;

};

Page 38: Introduction to C++ over CLI

Refernece Type 允許單一繼承多重實作Refernece Type 允許單一繼承多重實作

ref class R abstract {};

public ref class R2 : R, IClone, IComparable, IDisposable, IEnumerable

{

};

所有 reference type都繼承自 System::Object

最多繼承一個類別,但可以實作多個介面

Page 39: Introduction to C++ over CLI

Exception HandlingException Handling

try

{

throw gcnew Exception("qing");

}

catch(System::Exception^ e)

{

Console::WriteLine(e->StackTrace);

}

Page 40: Introduction to C++ over CLI

CLR編譯模式:共有四種可供選擇CLR編譯模式:共有四種可供選擇

Mix( /clr) 包含 managed/unmanaged code

Pure( /clr:pure ) 僅包含 managed code 但仍可使用 #include 並呼叫原生 API

Verifiable( clr:safe) 僅包含 verifiable code

Managed Extensions for C++( clr:oldSyntax ) 用來編譯舊式的程式碼

Page 41: Introduction to C++ over CLI

在 VS 2005中選擇編譯模式在 VS 2005中選擇編譯模式

Page 42: Introduction to C++ over CLI

編譯模式之間的關連性編譯模式之間的關連性

Native CLR

Co

de

Da

ta

MachineCode

CLRData / Types

NativeData / Types

MSILCode

Mixed C++/clrNative C++

Verifiable C++/clr:safe

Pure C++/clr:pure

Page 43: Introduction to C++ over CLI

CLR編譯模式帶來的應用CLR編譯模式帶來的應用

在 C++應用程式中直接使用 BCL 或以 .NET 寫成的library 大幅提高生產力

將 native code的功能,以 .NET物件模型的方式對外提供 便於其他 .NET應用程式使用( ASP.NET)

Page 44: Introduction to C++ over CLI

決定Managed/Unmanaged的交界處決定Managed/Unmanaged的交界處

C++managed

C++ CRT, STL, etcOne call to foo()

Hundreds of calls

C# or C++managed

C++ CRT, STL, etcOne call to foo()

Hundreds of calls

C# C++ CRT, STL, etcHundreds of calls

C++One call to foo()

One call

* Kate Gregory, “Moving C++ Applications to the Common Language Runtime”

Page 45: Introduction to C++ over CLI

C++/CLI支援 TemplateC++/CLI支援 Template

template<typename T1, typename T2> class NativeData

{

public:

NativeData(T1 t1)

{

m_t1 = t1;

}

void DoStuff(T2 t2)

{

//...

}

private:

T1 m_t1;

};

*http://www.codeproject.com/managedcpp/cppcligenerics.asp

Page 46: Introduction to C++ over CLI

Tempalte採用 Lazy Constraint (1/2)Tempalte採用 Lazy Constraint (1/2)

template<typename T> class Native

{

public:

void Start(int x)

{

T* t = new T();

t->Bark(x);

t->WagTail();

delete t;

}

};

如何確定 t 有 Bark() 及 WagTail() 兩 methods 呢?

*http://www.codeproject.com/managedcpp/cppcligenerics.asp

Page 47: Introduction to C++ over CLI

Tempalte採用 Lazy Constraint (2/2)Tempalte採用 Lazy Constraint (2/2)

Native<NativeDog> d1;

d1.Start(100);

Native<NativePig> d2;

d2.Start(100);

引發編譯器錯誤:error C2039: 'Bark' : is not a member of 'NativePig'

*http://www.codeproject.com/managedcpp/cppcligenerics.asp

Page 48: Introduction to C++ over CLI

C++/CLI支援 GenericsC++/CLI支援 Generics

generic<typename T1, typename T2> ref class GenericData

{

public:

GenericData(T1 t1)

{

m_t1 = t1;

}

void DoStuff(T2 t2)

{

//...

}

private:

T1 m_t1;

};

*http://www.codeproject.com/managedcpp/cppcligenerics.asp

Page 49: Introduction to C++ over CLI

Generics採用 Subtype Constraints (1/3)Generics採用 Subtype Constraints (1/3)

generic<typename T> where T:IDog ref class GenRef

{

public:

void Start(int x)

{

T t = Activator::CreateInstance<T>();

t->Bark(x);

t->WagTail();

delete safe_cast<Object^>(t);

}

};

透過限制 T必須實作的介面來進行約束

*http://www.codeproject.com/managedcpp/cppcligenerics.asp

Page 50: Introduction to C++ over CLI

Generics採用 Subtype Constraints (2/3)Generics採用 Subtype Constraints (2/3)

ref class ClrDog : IDog

{

public:

virtual void Bark(int Loudness)

{

Console::WriteLine("ClrDog::Bark {0}",Loudness);

}

virtual void WagTail()

{

Console::WriteLine("ClrDog::WagTail");

}

};

*http://www.codeproject.com/managedcpp/cppcligenerics.asp

Page 51: Introduction to C++ over CLI

Generics採用 Subtype Constraints (3/3)Generics採用 Subtype Constraints (3/3)

GenRef<ClrDog^> g1;

g1.Start(100);

*http://www.codeproject.com/managedcpp/cppcligenerics.asp

Page 52: Introduction to C++ over CLI

使用 Reference Types 於 Template使用 Reference Types 於 Template

template<typename T> class CLR

{

public:

void Start(int x)

{

T^ t = gcnew T();

t->Bark(x);

t->WagTail();

delete t;

}

};

CLR<ClrDog> g2;

g2.Start(100)

Page 53: Introduction to C++ over CLI

將 Template宣告為 Reference Type將 Template宣告為 Reference Type

template<typename T> ref class CLR2

{

public:

void Start(int x)

{

T^ t = gcnew T();

t->Bark(x);

t->WagTail();

delete t;

}

};

CLR2<ClrDog> g3;

g3.Start(100)

Console::WriteLine(g3.GetType()->Name);

執行結果:ClrDog::Bark 100ClrDog::WagTailCLR2<ClrDog>

Page 54: Introduction to C++ over CLI

Generics FunctionsGenerics Functions

generic<typename T> where T:IDog void DoAll(T t)

{

t->Bark(0);

t->WagTail();

}

*http://www.codeproject.com/managedcpp/cppcligenerics.asp

Page 55: Introduction to C++ over CLI

Template vs. GenericsTemplate vs. Generics

Templates are instantiated at compile-time with the source code.

The type checking of a template are performed at the point where the template is defined and instantiated.

Tempaltes allow specialization. Templates allow non-type

parameters. Templates use "lazy structural

constraints".

Generics are instantiated at run-time by the CLR.

The type checking of a generic is peformend at the point where the generic is defined.

Generics are cross-language. Generics do not allow

specialization. Generics do not allow non-type

parameters. Generics use subtype

constraints.

*http://blogs.msdn.com/branbray/archive/2003/11/19/51023.aspx

Page 56: Introduction to C++ over CLI

Verifiable C++Verifiable C++

以 /clr:safe編譯,將會試著產生 verifiable assembly 若使用了不安全的語法時,將會得到錯誤訊息

例如,不能使用指標運算 諸如 tempaltes, deterministic destruction其他功能則是安全的

Page 57: Introduction to C++ over CLI

使用程式庫使用程式庫

使用 managed assembly : #using #using <System.Data.dll>

使用 COM元件: #import #using <msxml4.dll>

使用 Standard C++ Library : #include #include <iostream>

Page 58: Introduction to C++ over CLI

C++/CLI的標準化現況C++/CLI的標準化現況

C++/CLI 在 2005 年 12 月已經成為國際標準( ECMA 372)

Page 59: Introduction to C++ over CLI

ReferenceReference

Hello C++/CLI http://msdn.microsoft.com/msdnmag/issues/06/00/

PureC/default.aspx ECMA-372 : C++/CLI Language Specification

http://www.ecma-international.org/publications/standards/Ecma-372.htm

void Nish(char *szBlog) http://blog.voidnish.com/index.php?cat=2

The Code Project http://www.codeproject.com/managedcpp/#C%2B%2B

%2FCLI

Page 60: Introduction to C++ over CLI

ThanksThanks