符號^
先回答第三個問題:
包含pragma once語句的文件只會被編譯一次。
其他問題的答案下面都有:
我們來看看C++/CLI中是怎樣來定義託管類型的:
如果要創建一個對於在託管堆中對象的應用(reference class),我們可以使用下面的兩個關鍵詞:
ref class
ref struct
其中,struct意味着默認情況下它的成員的訪問級別爲public,而class意味着默認情況下它的成員的訪問級別爲private。
如果要創建值類型(value class),那麼可以使用下面的關鍵詞:
value class
value struct
同樣,對於接口,關鍵詞爲interface class。
所以,我們就可以看到這樣的定義:
public ref class Block { ... };
public value class Vector { ... };
public interface class IMyFile { ... };
如果我們需要指定一個抽象(Abstract)的類,那麼語法爲:
public ref class Shape abstract {};
public ref class Shape2D abstract : public Shape{};
也可以指定爲Sealed類型,以及Sealed和Abstract共用:
public ref class String sealed {};
public ref class State abstract sealed{};
創建了託管類型的對象,就要有指向他們的指針。這裏是剛開始學習C++/CLI的時候,讓人有些不習慣的地方,因爲定義了一個全新的操作符^。
我們可以先來看看原來的_gc *和新的^的一些具體例子,然後再來感覺那個更好一些:
public __gc class Form1 : public System::Windows::Forms::Form {
private:
System::ComponentModel::Container __gc *components;
Button __gc *button1;
DataGrid __gc *myDataGrid;
DataSet __gc *myDataSet;
void PrintValues( Array* myArr )
{
System::Collections::IEnumerator* myEnumerator =
myArr->GetEnumerator();
Array *localArray = myArr->Copy();
// ...
}
};
public ref class Form1: public System::Windows::Forms::Form{
private:
System::ComponentModel::Container^ components;
Button^ button1;
DataGrid^ myDataGrid;
DataSet^ myDataSet;
void PrintValues( Array^ myArr )
{
System::Collections::IEnumerator^ myEnumerator =
myArr->GetEnumerator();
Array ^localArray = myArr->Copy();
// ...
}
};
是不是^更加自然呢?
可能會有人問:爲什麼不使用C++中原來的指針符號*呢?呵呵,因爲這是託管代碼啊!如果對象定義在非託管堆上,當然使用*了,但如果定義在託管堆上,就不能再簡單地使用*了。我們可以看看下面的例子:
Button^ button1 = gcnew Button; // OK: managed heap
int * pi1 = new int; // OK: native heap
interior_ptr<Int32> pi2 = gcnew Int32; // OK: managed heap
這裏說明兩點:
1. 在C++/CLI中,同時使用gcnew,來說明對象是創建在託管堆上的。
2. 關於interior_ptr,留待後面解釋。
同時,在C++/CLI中,數字0不再代表空地址,而僅僅代表數字0。空地址有一個關鍵字:nullptr。所以,下面的代碼就是把0給boxing了,再傳給指針obj:
Object^ obj=0;
而只有下面的語句,才真正把一個空指針給指針obj:
Object^ obj=nullptr;
順便,談談boxing。boxing就是說,當你想把一個值(value)當作一個對象(object)的時候,發生的事情。例如上面的語句中,就是把一個值0變成了一個object對象。具體在後臺發生的事情爲:
1. 首先,這個值會被壓入堆棧。
2. CLR接着會把這個值彈出堆棧,然後分配一塊空間,來存儲這個值以及對象頭信息。
3. 接着,一個新創建的對象的引用,會被壓入堆棧中。
4. 最後,把這個引用對象彈出堆棧,存儲在本地變量中。
可見,代價非常大。所以,一般情況下,不要隨便使用boxing(當然還有unboxing),因爲對性能影響太大。
CLI數組的定義
C++/CLI中,數組定於爲:
void PrintValues( array<Object^>^ myArr );
void PrintValues( array<int,3>^ myArr );
同時,還可以使用gcnew定義的時候,直接賦值:
array<Object^>^ myArray =
gcnew array<Object^>(4){ 1, 1, 2, 3 }
而且,還可以定義返回類型爲CLI數組的函數:
array<Int32>^ f();
array<int>^ GetArray();
包含pragma once語句的文件只會被編譯一次。
其他問題的答案下面都有:
我們來看看C++/CLI中是怎樣來定義託管類型的:
如果要創建一個對於在託管堆中對象的應用(reference class),我們可以使用下面的兩個關鍵詞:
ref class
ref struct
其中,struct意味着默認情況下它的成員的訪問級別爲public,而class意味着默認情況下它的成員的訪問級別爲private。
如果要創建值類型(value class),那麼可以使用下面的關鍵詞:
value class
value struct
同樣,對於接口,關鍵詞爲interface class。
所以,我們就可以看到這樣的定義:
public ref class Block { ... };
public value class Vector { ... };
public interface class IMyFile { ... };
如果我們需要指定一個抽象(Abstract)的類,那麼語法爲:
public ref class Shape abstract {};
public ref class Shape2D abstract : public Shape{};
也可以指定爲Sealed類型,以及Sealed和Abstract共用:
public ref class String sealed {};
public ref class State abstract sealed{};
創建了託管類型的對象,就要有指向他們的指針。這裏是剛開始學習C++/CLI的時候,讓人有些不習慣的地方,因爲定義了一個全新的操作符^。
我們可以先來看看原來的_gc *和新的^的一些具體例子,然後再來感覺那個更好一些:
public __gc class Form1 : public System::Windows::Forms::Form {
private:
System::ComponentModel::Container __gc *components;
Button __gc *button1;
DataGrid __gc *myDataGrid;
DataSet __gc *myDataSet;
void PrintValues( Array* myArr )
{
System::Collections::IEnumerator* myEnumerator =
myArr->GetEnumerator();
Array *localArray = myArr->Copy();
// ...
}
};
public ref class Form1: public System::Windows::Forms::Form{
private:
System::ComponentModel::Container^ components;
Button^ button1;
DataGrid^ myDataGrid;
DataSet^ myDataSet;
void PrintValues( Array^ myArr )
{
System::Collections::IEnumerator^ myEnumerator =
myArr->GetEnumerator();
Array ^localArray = myArr->Copy();
// ...
}
};
是不是^更加自然呢?
可能會有人問:爲什麼不使用C++中原來的指針符號*呢?呵呵,因爲這是託管代碼啊!如果對象定義在非託管堆上,當然使用*了,但如果定義在託管堆上,就不能再簡單地使用*了。我們可以看看下面的例子:
Button^ button1 = gcnew Button; // OK: managed heap
int * pi1 = new int; // OK: native heap
interior_ptr<Int32> pi2 = gcnew Int32; // OK: managed heap
這裏說明兩點:
1. 在C++/CLI中,同時使用gcnew,來說明對象是創建在託管堆上的。
2. 關於interior_ptr,留待後面解釋。
同時,在C++/CLI中,數字0不再代表空地址,而僅僅代表數字0。空地址有一個關鍵字:nullptr。所以,下面的代碼就是把0給boxing了,再傳給指針obj:
Object^ obj=0;
而只有下面的語句,才真正把一個空指針給指針obj:
Object^ obj=nullptr;
順便,談談boxing。boxing就是說,當你想把一個值(value)當作一個對象(object)的時候,發生的事情。例如上面的語句中,就是把一個值0變成了一個object對象。具體在後臺發生的事情爲:
1. 首先,這個值會被壓入堆棧。
2. CLR接着會把這個值彈出堆棧,然後分配一塊空間,來存儲這個值以及對象頭信息。
3. 接着,一個新創建的對象的引用,會被壓入堆棧中。
4. 最後,把這個引用對象彈出堆棧,存儲在本地變量中。
可見,代價非常大。所以,一般情況下,不要隨便使用boxing(當然還有unboxing),因爲對性能影響太大。
CLI數組的定義
C++/CLI中,數組定於爲:
void PrintValues( array<Object^>^ myArr );
void PrintValues( array<int,3>^ myArr );
同時,還可以使用gcnew定義的時候,直接賦值:
array<Object^>^ myArray =
gcnew array<Object^>(4){ 1, 1, 2, 3 }
而且,還可以定義返回類型爲CLI數組的函數:
array<Int32>^ f();
array<int>^ GetArray();
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.