C++/CLI所支持的基本類型
例如int
double
bool等
在某些方面可以說是沿襲了ISO
C++中的類型——同樣的用法會在C++/CLI中得到同樣的結果
例如加法或者賦值操作
但是C++/CLI也為這些基本類型引入了一些新的東西
在通用類型系統(CTS)中
每一個基本類型都在System命名空間中存在一個對應的類(見表
)
例如int實際上完全等價於System::Int
我們可以使用二者中的任何一個來聲明一個整數
int ival =
;
Int
ival
=
;
出於移植性的考慮
在使用這些基本類型時
我們推薦大家使用內建的關鍵詞
而非System命名空間中的類名
表 基本類型和它們在System命名空間中對應的類 對於System命名空間中類的公有靜態成員
我們既可以通過內建的關鍵字
也可以通過System命名空間中的類名來訪問
例如
為了獲取一個數值類型的取值范圍
我們可以直接使用內建的關鍵字來訪問其靜態屬性MaxValue和MinValue
int imaxval = int::MaxValue;
int iminval = Int
::MinValue;
每個數值類型都支持一個名為Parse的成員函數
用以將一個字符串轉化為其所表示的數值
例如
給定下面的字符串
String^ bonus =
$
;
調用Parse會將myBonus初始化為
double myBonus = double::Parse( bonus
ns );
其中ns表示對一些NumberStyles枚舉類型取位或(bitwise or)運算的結果
NumberStyles是位於System::Globalization命名空間中的一個枚舉類型
用於表征對空白
貨幣符號
小數點或者逗號等的處理
看下面的代碼
using namespace System;
using namespace System::Globalization;
double bonusString( String^ bonus )
{
NumberStyles ns = NumberStyles::AllowLeadingWhite;
ns |= NumberStyles::AllowCurrencySymbol;
ns |= NumberStyles::AllowThousands;
ns |= NumberStyles::AllowDecimalPoint;
return double::Parse( bonus
ns );
}
我們也可以使用轉型符號來在類型間進行顯式的轉換
int ival = ( int ) myBonus;
或者使用System::Convert類的一些轉換方法
例如ToDouble()
ToInt
()
ToDateTime()等:
int ival
= Convert::ToInt
( myBonus );
兩種轉換方法采用的策略有所不同
顯式轉型會直接對小數部分進行截斷
而Convert的成員函數則采用的是捨入算法
例如上面的例子中ival賦值後的結果為
而ival
賦值後的結果為
我們還可以直接使用字面常量(literal)來調用其對應類型的成員函數
雖然這乍看起來有些怪異
例如
我們可以編寫如下代碼
Console::Write(
{
} :
(
)
ToString() );
其中(
)
ToString()返回的是字面常量整數
的字符串表示
注意
外面的圓括號是必須的
因為它會使得編譯器將後面的成員選擇操作符點號綁定到整數
上
而不是將
解析為一個double類型的字面常量——那樣的話
後面的ToString()將變得不合法
為什麼我們有時候需要這樣做呢?一種可能的情況是將一個字符串傳遞給Console的成員函數要比傳遞實際的數值來的更加高效
對於字符以及字符串這樣的字面常量
我們也可以像上面的整數一樣調用它們的成員函數
但是它們的行為有一點點晦澀
例如
下面的代碼
Console::WriteLine((
a
)
ToString() );
將在控制台上打印出
而非
a
這個字符
要將字符
a
打印出來
我們需要將其首先轉型為System::Char
Console::WriteLine(((wchar_t)
a
)
ToString() );
C++/CLI對字符串字面常量采取了特殊的處理策略
從某種程度上來講
字符串字面常量在C++/CLI中的類型更接近System::String
而非C風格的字符串指針
顯然
這將對重載函數的辨析產生影響
例如
public ref class R {
public:
void foo( System::String^ ); // (
)
void foo( std::string ); // (
)
void foo( const char* ); // (
)
};
void bar( R^ r )
{
// 調用哪一個foo呢?
r
>foo(
Pooh
);
}
在ISO
C++中
這將被辨析為第
個foo()
因為字符串字面常量更接近const char*
而非ISO
C++標准庫中的string類型
但是
在C++/CLI中
上面的調用將被辨析為第
個foo()
因為現在字符串字面常量被認為更接近System::String
而非字符指針
要理解其中的緣由
讓我們往後退兩步
先來看看ISO
C++和C++/CLI如何辨析一個重載函數
然後再來看ISO
C++和C++/CLI如何辨析一個字符串字面常量
一個重載函數的辨析過程通常包含以下三個步驟
.選擇候選函數集合
候選函數是指那些從詞法范疇來看與所調用函數名相匹配的函數
例如
由於我們上面是在R的一個實例上調用foo()
所以所有名稱為foo但卻不是R或者其基類的成員的那些函數將不被認為是候選函數
這樣看來
我們現在有三個候選函數
即R中三個名稱為foo的成員函數
如果這個階段得到的候選函數集合為空
那麼調用將告失敗
.從候選函數集合中選擇可用函數集合
可用函數是指函數聲明時的參數個數和它們的類型與調用時所指定的相匹配的那些函數
在我們上面的例子中
三個候選函數都是可用函數
如果這個階段得到的可用函數集合為空
那麼調用也將失敗
.從可用函數集合中選擇最匹配的函數
這個階段將會對實際傳遞的參數和可用函數所聲明的參數之間的轉換進行一個排名
對於只含一個參數的函數來說
這個過程比較簡單
但是對於含有多個參數的函數來說
這個過程就變得相對有些復雜
如果沒有一個最佳的匹配函數勝出
那麼調用將告失敗
也就是說各個可用函數的參數類型到實際參數類型之間的轉換被認為一樣的好
換言之多個調用之間產生了混淆
那麼現在擺在我們面前有兩個問題
(
)我們實際傳遞的參數
Pooh
到底是什麼類型?(
)在判定類型轉換的優劣時采用的是什麼算法?
在ISO
C++中
字符串字面常量
Pooh
的類型為const char[
]——注意
在字符串字面常量後面有一個隱含的截斷字符null
在上面的例子中顯然不存在這樣的精確匹配
因此必須應用某種形式的類型轉換
這樣
兩個ISO
C++候選函數(
)和(
)將進行競爭
void foo( std::string ); // (
)
void foo( const char* ); // (
)
那麼編譯器如何從中判斷可用函數呢?C++語言對類型轉換按照優先順序定義有一個層級結構
在這個結構中
如果一種轉換優於另一種轉換
那麼它將被排在前面
在C++/CLI中
我們將CLI類型的行為也集成到了ISO
C++的標准類型轉換層級結構中
下面是對集成之後的層級結構的一個描述
)精確匹配是最好的
需要注意的是精確匹配並不意味著實際傳遞的參數類型和函數聲明的形式參數類型完全匹配
它們只需要
足夠接近
就可以了
我們下面將會看到
足夠接近
對於ISO
C++和C++/CLI中的字符串字面常量有著一些不同的含義
)在標准轉換中
拓寬轉換要優於非拓寬轉換
例如
將short拓寬為int要優於將int轉換為double
)標准轉換優於裝箱(boxing)轉換
例如
將int轉換為double優於將int裝箱為Object
)裝箱轉換優於用戶自定義的隱式轉換
)用戶自定義的隱式轉換優於沒有任何轉換!
)否則
用戶必須使用顯式的轉型符號來表示期望的轉換
對於上面兩個ISO
C++下的候選函數
將字符串字面常量轉換為一個std::string屬於上面第
條
即隱式調用string的構造器來創建一個臨時string對象
而將字符串字面常量轉換為一個const char* 屬於上面第
條
第
條優於第
條
因此
參數為const char*的那個函數在這場競爭中勝出
這種歸屬在第
條
精確匹配
下的trivial conversions實際上在技術的定義上是很嚴格的
總共有
種這樣的trivial conversions可以被歸為精確匹配
即使在這
種trivial conversions中
為了規范語言對類型的選擇
它們也有一個優先級的排序
大多數讀者和程序員可能對於這樣的細節沒有多大興趣
並且通常情況下我們也無須深入到這些細節的地方
但是如果我們要得到一個直觀的語言行為
並且確保它們在不同的實現上表現相同
這些規則的存在就很有必要
這是因為作為一門編程語言
它的行為一般要具有某種程度的
類型感知
能力
從而允許程序員忽略這些細節
下面讓我們來對這
種trivial conversions做一簡單的了解
其中
種被稱為左值轉換(lvalue transformation)
左值(lvalue)是一個可尋址的
可被執行寫操作的程序實體
第
種為限定性轉換(qualification conversion)
例如
在一個類型聲明上加一個const修飾符就屬於這種轉換
其中
種左值轉換優於限定性轉換
在我們上面的例子中
由本地數組到指針的轉換
即由const char [
]到const char *
就是一種左值轉換
在大多數情況下
我們甚至不將這看作一種轉換
這種形式的左值轉換在C++/CLI中仍然適用
但是在我們將System::String類引入之後
字符串字面常量到const char*的轉換就不再是最好的匹配了
實際上
在C++/CLI中
Pooh
這樣的字符串字面常量的類型既是const char[
From:http://tw.wingwit.com/Article/program/ASP/201311/21784.html