下一代visual studio版本(以前whidbey,現在是visual studio 2005)提供更加豐富的改進的庫檔案和沒有很多幕後精簡和加速的壓力,它的大量配合的工具和新的功能將使開發人員的開發過程變得簡單有趣,對我而言,這些與visual studio 2005對C++的處理相比就顯得有些蒼白,這裡我主要談談在下一代visual studio中C++的變化.
跟底線拜拜
在visual studio.NET中引入了對C++副檔名的處理,副檔名是以兩個底線開始的關鍵字,比如__gc和__property.自從上個版本發布以來,我已經寫了大量的雙底線特徵的代碼,我坦白也不喜歡這樣,我瞭解具體的原因是:帶兩個底線的關鍵字作為特殊的副檔名使它們不會跟標準編譯器相混淆,你可以全面的管理副檔名可以用其他的編譯器來編譯,它忽視__關鍵字。
這是一種解決方案:微軟發現了一種方法不改變程式設計語言的改變,但是會出現下面一些結果:
·開發人員發現文法不自然
·不能被完全的採用
如例,適當的C++處理方法:程式碼:
public __gc class Foo
{
// hundreds of lines of code
__property String* get_Text();
// hundreds of lines of code
__property void set_Text(String*);
// hundreds of lines of code
}; 有良好習慣的程式員把get和put放在每個副檔名的右面,把潛在的變數放在旁邊,但是程式設計語言沒要求你這樣做。它提供無環境支援定界結構讓你明白作為一個單元是正確的,所以它是不自然的跟其它visual studio .NET語言不一樣。但是你如何去處理這個問題那,唯一的方式完成C++轉換成CLR反之就要改變C++.假如你想那樣做,你可以有足夠的自由得到自然一流的語言會給你最好的,你可以取消大量的帶雙劃線的關鍵字。
存留時間和範圍
我喜歡確定的解析,實際上我也喜歡片段收集,我還能舉出更多的,它們有自己的作用而且我也需要它們,假如我只在記憶體中構造一個對象,我希望在我自己清除它前不被清除,
所以記憶體管理是很複雜的。但是,如果你的對象包含一個未管理源檔案如資料庫連結,一個開放檔案,或者類似我要取得一個控制。我想知道它要儘快的離開,用這種模式去處理,但是它不是直接的,簡單的親密支援是最好的辦法。
下面是在原始的C++中,你去完成這些事情:程式碼:
//this is a code fragment
{
try
{
Foo* f=new Foo(/* params */);
//all kinds of code, some of which might throw exceptions
delete f;
}
catch (/* something */)
{
delete f;
//whatever else, or rethrow;
}
}
如果你在堆棧建立對象,生命期是簡單的
程式碼:
//this is a code fragment
{
Foo f;
//all kinds of code, some of which might throw exceptions
}
當f超過範圍,不論是否是意外它將被清除這是自然的。
當對象在管理堆裡時,你不能把它刪除,它將被片段收集清除,如果你想清除管理著源檔案的對象,你可以調用dispose()函數,雖然C#為它提供了的有效結構,但是它仍然不象堆棧那樣簡單。
在新一代的語言(以前是C++/CLI),你在哪裡建立對象不依賴於你建立對象的種類,你可以堆棧中管理對象,它有確定的解析,但它越界時將被清除,如果你願意你可以在管理堆裡建立對象。
這種變化帶來其它的結果,其中最深遠的是你可以把不同的對象放在摸板中或者可以把它看成其它類的成員變數,你可以得到完整的C++存留時間周期,而不是僅僅是把它分配到相應的堆,然後等片段收集來處理它。
解析和定稿
當你為其它語言寫了片段收集對象是,你是否為它寫瞭解析函數?當你使用C++,你可以在堆棧構造對象,解析函數將運行當它越界時,什麼事情會發生當其他C#或VB程式調用這個對象,運行時僅從簡單的方式去處理,它是用dispose()來解析,任何一個C++/CLI對象都有一個可以任意調用的解析函數。
假如你在C#或VB中有dispose()的類,你可能已經寫了一個定論,C++/CLI也有簡便的文法為定論,就象Foo的解析是~Foo,Foo的定論是!Foo(~是位元的not,!是邏輯的not,它們都是提醒是和建構函式對立的),
Finalizer將運行當在管理堆中建立而不被調用,確信它所包含的非管理源檔案被清除,即使其他調用函數忘了去解析。
指標和控制代碼
在C++副檔名管理中,C++的主要限制沒有變化,同樣的符號和文法用做完全的事情,*的含義依賴於你的代碼中的其他位置的資訊,你可以試試下面的代碼: Foo* pf = new Foo();
Foo對象將在哪裡建立?那塊記憶體是否被清除?我能象下面那樣對指標做演算法嗎:
pf++;
答案依賴於Foo是否用__gc關鍵字聲明,假如它是片段收集對象,它只能在管理堆不是在本堆和堆棧中建立,另一方面,如果沒有用__gc聲明,將在本堆中分配記憶體給它,你必須記得去清除它。
如果編譯器有自由去改變語言,就象在C++/CLI上發生的,可以忽視什麼地方生存的什麼類型的類,可以用不同的文法表明它在哪裡生存:
Foo^ hf = gcnew Foo();
這被叫做控制代碼,許多C++團隊好象都是用^符號來標明的,你可以用*和->來解除控制代碼的引用,你可以從執行個體的聲明而不是回過頭從類的聲明中得到生命期的聲明。例如:
程式碼:
ref class R
{
private:
int m_a;
public:
R(int a): m_a(a) {}
};
你可能會認為ref是C++/CLI新的關鍵字,但它不是,“ref class“是關鍵字,你可以有變數是ref而不會引起混亂,其他的關鍵字還有”value class“,”interface class“,”enum class“,幾乎過去所有的C++程式都會有value這個變數,我很高興value沒有變成關鍵字。
Ref class 是一個管理類,一個被設計成生存管理隊中和被片段收集管理的類,象我前面所示的你可以在堆棧中聲明一個執行個體,編譯器會幫你找到它,加上不可見的智能指標。
特性
有很多C++特性的改變,因為我是用C++比較笨拙的特性開始的例子,所以我現在關閉比較相近的C++
程式碼:
ref class R
{
private:
int m_Size;
public:
property int Size
{
int get() { return m_Size; }
void set(int val){m_Size = val;}
}
};
R r;
r.Size = 42;
property是一個關鍵字嗎?有點象,它是一個位置關鍵字,所以你可以有property的變數和函數,而不會引起混亂,它只會在類定義中有特殊的含義,現在在C++/CLI中有單獨的單元提供特性定義,我很喜歡這樣,相信你也是。