青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

旅途

如果想飛得高,就該把地平線(xiàn)忘掉

C++/CLR泛型與C++模板之間的對(duì)比

Visual Studio 2005把泛型編程的類(lèi)型參數(shù)模型引入了微軟.NET框架組件。C++/CLI支持兩種類(lèi)型參數(shù)機(jī)制--通用語(yǔ)言運(yùn)行時(shí)(CLR)泛型和C++模板。本文將介紹兩者之間的一些區(qū)別--特別是參數(shù)列表和類(lèi)型約束模型之間的區(qū)別。

  參數(shù)列表又回來(lái)了

  參數(shù)列表與函數(shù)的信號(hào)(signature)類(lèi)似:它標(biāo)明了參數(shù)的數(shù)量和每個(gè)參數(shù)的類(lèi)型,并把給每個(gè)參數(shù)關(guān)聯(lián)一個(gè)唯一的標(biāo)識(shí)符,這樣在模板定義的內(nèi)部,每個(gè)參數(shù)就可以被唯一地引用。

  參數(shù)在模板或泛型的定義中起占位符(placeholder)的作用。用戶(hù)通過(guò)提供綁定到參數(shù)的實(shí)際值來(lái)建立對(duì)象實(shí)例。參數(shù)化類(lèi)型的實(shí)例化并非簡(jiǎn)單的文本替代(宏擴(kuò)展機(jī)制就是使用文本替代的)。相反地,它把實(shí)際的用戶(hù)值綁定到定義中的相關(guān)的形式參數(shù)上。

  在泛型中,每個(gè)參數(shù)都表現(xiàn)為Object類(lèi)型或衍生自O(shè)bject的類(lèi)型。在本文后面你可以看到,這約束了你可能執(zhí)行的操作類(lèi)型或通過(guò)類(lèi)型參數(shù)聲明的對(duì)象。你可以通過(guò)提供更加明確的約束來(lái)調(diào)整這些約束關(guān)系。這些明確的約束引用那些衍生出實(shí)際類(lèi)型參數(shù)的基類(lèi)或接口集合。

  模板除了支持類(lèi)型參數(shù)之外,還支持表達(dá)式和模板參數(shù)。此外,模板還支持默認(rèn)的參數(shù)值。這些都是按照位置而不是名稱(chēng)來(lái)分解的。在兩種機(jī)制之下,類(lèi)型參數(shù)都是與類(lèi)或類(lèi)型名稱(chēng)關(guān)鍵字一起引入的。

  參數(shù)列表的額外的模板功能

  模板作為類(lèi)型參數(shù)的補(bǔ)充,允許兩種類(lèi)型的參數(shù):非類(lèi)型(non-type)參數(shù)和模板參數(shù)。我們將分別簡(jiǎn)短地介紹一下。

   非類(lèi)型參數(shù)受常數(shù)表達(dá)式的約束。我們應(yīng)該立即想到它是數(shù)值型或字符串常量。例如,如果選擇提供固定大小的堆棧,你就可能同時(shí)指定一個(gè)非類(lèi)型的大小參數(shù)和 元素類(lèi)型參數(shù),這樣就可以同時(shí)按照元素類(lèi)別和大小來(lái)劃分堆棧實(shí)例的類(lèi)別。例如,你可以在代碼1中看到帶有非類(lèi)型參數(shù)的固定大小的堆棧。

  代碼1:帶有非類(lèi)型固定大小的堆棧

template <class elemType, int size>
public ref class tStack
{
 array<elemType> ^m_stack;
 int top;

 public:
  tStack() : top( 0 )
  { m_stack = gcnew array<elemType>( size ); }
};

  此外,如果模板類(lèi)設(shè)計(jì)者可以為每個(gè)參數(shù)指定默認(rèn)值,使用起來(lái)就可能方便多了。例如,把緩沖區(qū)的默認(rèn)大小設(shè)置為1KB就是很好的。在模板機(jī)制下,可以給參數(shù)提供默認(rèn)值,如下所示:

// 帶有默認(rèn)值的模板聲明
template <class elemType, int size = 1024>
public ref class FixedSizeStack {};

  用戶(hù)可以通過(guò)提供明確的第二個(gè)值來(lái)重載默認(rèn)大小值:

// 最多128個(gè)字符串實(shí)例的堆棧
FixedSizeState<String^, 128> ^tbs = gcnew FixedSizeStack<String^, 128>;

  否則,由于沒(méi)有提供第二個(gè)參數(shù),它使用了相關(guān)的默認(rèn)值,如下所示:

// 最多1024個(gè)字符串實(shí)例的堆棧
FixedSizeStack<String^> ^tbs = gcnew FixedSizeStack<String^>;

  使用默認(rèn)的參數(shù)值是標(biāo)準(zhǔn)模板庫(kù)(STL)的一個(gè)基本的設(shè)計(jì)特征。例如,下面的聲明就來(lái)自ISO-C++標(biāo)準(zhǔn):

// ISO-C++名字空間std中的默認(rèn)類(lèi)型參數(shù)值示例
{
 template <class T, class Container = deque<T> >
 class queue;

 template <class T, class Allocator = allocator<T> >
 class vector;
 // ...
}

  你可以提供默認(rèn)的元素類(lèi)型,如下所示:

// 帶有默認(rèn)的元素類(lèi)型的模板聲明
template <class elemType=String^, int size=1024>
public ref class tStack {};

  從設(shè)計(jì)的角度來(lái)說(shuō)很難證明它的正確性,因?yàn)橐话銇?lái)說(shuō)容器不會(huì)集中在在單個(gè)默認(rèn)類(lèi)型上。

   指針也可以作為非類(lèi)型參數(shù),因?yàn)閷?duì)象或函數(shù)的地址在編譯時(shí)就已知了,因此是一個(gè)常量表達(dá)式。例如,你可能希望為堆棧類(lèi)提供第三個(gè)參數(shù),這個(gè)參數(shù)指明遇到 特定條件的時(shí)候使用的回調(diào)處理程序。明智地使用typedef可以大幅度簡(jiǎn)化那些表面上看起來(lái)很復(fù)雜的聲明,如下所示:

typedef void (*handler)( ... array<Object^>^ );
template <class elemType, int size, handler cback >
public ref class tStack {};

  當(dāng)然,你可以為處理程序提供默認(rèn)值--在這個(gè)例子中,是一個(gè)已有的方法的地址。例如,下面的緩沖區(qū)聲明就提供了大小和處理程序:

void defaultHandler( ... array<Object^>^ ){ ... }

template < class elemType,
int size = 1024,
handler cback = &defaultHandler >
public ref class tStack {};

  由于默認(rèn)值的位置次序優(yōu)先于命名次序,因此如果不提供明確的大小值(即使這個(gè)大小與默認(rèn)值是重復(fù)的),就無(wú)法提供重載的處理程序的。下面就是可能用到的修改堆棧的方法:

void demonstration()
{
 // 默認(rèn)的大小和處理程序
 tStack<String^> ^ts1 = nullptr;
 // 默認(rèn)的處理程序
 tStack<String^, 128> ^ts2 = gcnew tStack<String^, 128>;
 // 重載所有的三個(gè)參數(shù)
 tStack<String^, 512, &yourHandler> ^ts3;
}

  模板支持的第二種額外的參數(shù)就是template模板參數(shù)--也就是這個(gè)模板參數(shù)本身表現(xiàn)為一個(gè)模板。例如:

// template模板參數(shù)
template <template <class T> class arena, class arenaType>
class Editor {
arena<arenaType> m_arena;
// ...
};

   Editor模板類(lèi)列出了兩個(gè)模板參數(shù)arena和arenaType。ArenaType是一個(gè)模板類(lèi)型參數(shù);你可以傳遞整型、字符串型、自定義類(lèi)型 等等。Arena是一個(gè)template模板參數(shù)。帶有單個(gè)模板類(lèi)型參數(shù)的任何模板類(lèi)都可以綁定到arena。m_arena是一個(gè)綁定到 arenaType模板類(lèi)型參數(shù)的模板類(lèi)實(shí)例。例如:

// 模板緩沖區(qū)類(lèi)
template <class elemType>
public ref class tBuffer {};

void f()
{
 Editor<tBuffer,String^> ^textEditor;
 Editor<tBuffer,char> ^blitEditor;
 // ...
}

類(lèi)型參數(shù)約束

  如果你把參數(shù)化類(lèi)型簡(jiǎn)單地作為存儲(chǔ)和檢索元素的容器,那么你可以略過(guò)這一部分了。當(dāng)你需要調(diào)用某個(gè)類(lèi)型參數(shù)(例如在比較兩個(gè)對(duì)象,查看它們相等或者其中一個(gè)小于另一個(gè)的時(shí)候,或者通過(guò)類(lèi)型參數(shù)調(diào)用方法名稱(chēng)或嵌套類(lèi)型的時(shí)候)上的操作的時(shí)候,才會(huì)考慮約束的問(wèn)題。例如:

template <class T>
ref class Demonstration {
 int method() {
  typename T::A *aObj;
  // ...
 }
};

  這段代碼成功地聲明了aObj,它同時(shí)還約束了能夠成功地綁定到你的類(lèi)模板的類(lèi)型參數(shù)。例如,如果你編寫(xiě)下面的代碼,aObj的聲明就是非法的(在這種特定的情況下),編譯器會(huì)報(bào)錯(cuò)誤信息:

int demoMethod()
{
 Demonstration<int> ^demi = gcnew Demonstration<int>( 1024 );
 return dm->method();
}

   當(dāng)然,其特定的約束是,這個(gè)類(lèi)型參數(shù)必須包含一個(gè)叫做A的類(lèi)型的嵌套聲明。如果它的名字叫做B、C或Z都沒(méi)有關(guān)系。更普通的約束是類(lèi)型參數(shù)必須表示一個(gè) 類(lèi),否則就不允許使用T::范圍操作符。我使用int類(lèi)型參數(shù)同時(shí)違反了這兩條約束。例如,Visual C++編譯器會(huì)生成下面的錯(cuò)誤信息:

error C2825: 'T': must be a class or namespace when followed by '::'

   C++模板機(jī)制受到的一條批評(píng)意見(jiàn)是:缺乏用于描述這種類(lèi)型約束的形式語(yǔ)法(請(qǐng)注意,在參數(shù)化類(lèi)型的原始設(shè)計(jì)圖紙中,Bjarne Stroustrup論述了曾經(jīng)考慮過(guò)提供顯式約束語(yǔ)法,但是他對(duì)這種語(yǔ)法不太滿(mǎn)意,并選擇了在那個(gè)時(shí)候不提供這種機(jī)制)。也就是說(shuō),在一般情況下,用戶(hù) 在閱讀源代碼或相關(guān)的文檔,或者編譯自己的代碼并閱讀隨后的編譯器錯(cuò)誤消息的時(shí)候,才能意識(shí)到模板有隱含約束。

  如果你必須提供一個(gè)與模板不匹配的類(lèi)型參數(shù)該怎么辦呢?一方面,我們能做的事情很少。你編寫(xiě)的任何類(lèi)都有一定的假設(shè),這些假設(shè)表現(xiàn)為某些使用方面的約束。很難設(shè)計(jì)出適合每種情況的類(lèi);設(shè)計(jì)出適合每種情況和每種可能的類(lèi)型參數(shù)的模板類(lèi)更加困難。

  另一方面,存在大量的模板特性為用戶(hù)提供了"迂回"空間。例如,類(lèi)模板成員函數(shù)不會(huì)綁定到類(lèi)型參數(shù),直到在代碼中使用該函數(shù)為止(這個(gè)時(shí)候才綁定)。因此,如果你使用模板類(lèi)的時(shí)候,沒(méi)有使用那些使類(lèi)型參數(shù)失效的方法,就不會(huì)遇到問(wèn)題。

   如果這樣也不可行,那么還可以提供該方法的一個(gè)專(zhuān)門(mén)的版本,讓它與你的類(lèi)型參數(shù)關(guān)聯(lián)。在這種情況下,你需要提供Demonstration< int>::方法的一個(gè)專(zhuān)用的實(shí)例,或者,更為普遍的情況是,在提供整數(shù)類(lèi)型參數(shù)的時(shí)候,提供整個(gè)模板類(lèi)的專(zhuān)門(mén)的實(shí)現(xiàn)方式。

  一般來(lái)說(shuō),當(dāng)你提到參數(shù)化類(lèi)型可以支持多種類(lèi)型的時(shí)候,你一般談到的是參數(shù)化的被動(dòng)使用--也就是說(shuō),主要是類(lèi)型的存儲(chǔ)和檢索,而不是積極地操作(處理)它。

   作為模板的設(shè)計(jì)人員,你必須知道自己的實(shí)現(xiàn)對(duì)類(lèi)型參數(shù)的隱含約束條件,并且努力去確保這些條件不是多余的。例如,要求類(lèi)型參數(shù)提供等于和小于操作是合理 的;但是要求它支持小于或等于或XOR位運(yùn)算符就不太合理了。你可以通過(guò)把這些操作分解到不同的接口中,或者要求額外的、表示函數(shù)、委托或函數(shù)對(duì)象的參數(shù) 來(lái)放松對(duì)操作符的依賴(lài)性。例如,代碼2顯示了一個(gè)本地C++程序員使用內(nèi)建的等于操作符實(shí)現(xiàn)的搜索方法。

  代碼2:不利于模板的搜索實(shí)現(xiàn)

template <class elemType, int size=1024>
ref class Container
{
 array<elemType> ^m_buf;
 int next;

 public:
  bool search( elemType et )
  {
   for each ( elemType e in m_buf )
    if ( et == e )
     return true;
    return false;
  }

  Container()
  {
   m_buf = gcnew array<elemType>(size);
   next = 0;
  }

  void add( elemType et )
  {
   if ( next >= size )
    throw gcnew Exception;
    m_buf[ next++ ] = et;
  }

  elemType get( int ix )
  {
   if ( ix < next )
    return m_buf[ ix ];
   throw gcnew Exception;
  }
  // ...
 };

   在這個(gè)搜索函數(shù)中沒(méi)有任何錯(cuò)誤。但是,它不太利于使用模板,因?yàn)轭?lèi)型參數(shù)與等于操作符緊密耦合了。更為靈活的方案是提供第二個(gè)搜索方法,允許用戶(hù)傳遞一 個(gè)對(duì)象來(lái)進(jìn)行比較操作。你可以使用函數(shù)成員模板來(lái)實(shí)現(xiàn)這個(gè)功能。函數(shù)成員模板提供了一個(gè)額外的類(lèi)型參數(shù)。請(qǐng)看一看代碼3。

  代碼3:使用模板

template <class elemType, int size=1024>
ref class Container
{
 // 其它的都相同 ...
 // 這是一個(gè)函數(shù)成員模板...
 // 它可以同時(shí)引用包含的類(lèi)參數(shù)和自有參數(shù)...

 template <class Comparer>
 bool search( elemType et, Comparer comp )
 {
  for each ( elemType e in m_buf )
   if ( comp( et, e ) )
    return true;
 
   return false;
 }
 // ...
};

  現(xiàn)在用戶(hù)可以選擇使用哪一個(gè)方法來(lái)搜索內(nèi)容了:緊密耦合的等于操作符搜索效率較高,但是不適合于所有類(lèi)型;較靈活的成員模板搜索要求傳遞用于比較的類(lèi)型。

  哪些對(duì)象適用這種比較目的?函數(shù)對(duì)象就是普通的用于這種目的的C++設(shè)計(jì)模式。例如,下面就是一個(gè)比較兩個(gè)字符串是否相等的函數(shù)對(duì)象:

class EqualGuy {
 public:
  bool operator()( String^ s1, String^ s2 )
  {
   return s1->CompareTo( s2 ) == 0;
  }
};

  代碼4中的代碼顯示了你如何調(diào)用這兩個(gè)版本的搜索成員函數(shù)模板和傳統(tǒng)的版本。

  代碼4:兩個(gè)搜索函數(shù)

int main()
{
 Container<String^> ^sxc = gcnew Container<String^>;
 sxc->add( "Pooh" );
 sxc->add( "Piglet" );

 // 成員模板搜索 ...
 if ( sxc->search( "Pooh", EqualGuy() ) )
  Console::WriteLine( "found" );
 else Console::WriteLine( "not found" );

  // 傳統(tǒng)的等于搜索 ...
  if ( sxc->search( "Pooh" ) )
   Console::WriteLine( "found" );
  else Console::WriteLine( "not found" );
}

  一旦有了模板的概念,你就會(huì)發(fā)現(xiàn)使用模板幾乎沒(méi)有什么事情不是實(shí)現(xiàn)。至少感覺(jué)是這樣的。
泛型約束

  與模板不同,泛型定義支持形式約束語(yǔ)法,這些語(yǔ)法用于描述可以合法地綁定的類(lèi)型參數(shù)。在我詳細(xì)介紹約束功能之前,我們簡(jiǎn)短地考慮一下為什么泛型選擇了提供約束功能,而模板選擇了不提供這個(gè)功能。我相信,最主要的原因是兩種機(jī)制的綁定時(shí)間之間差異。

  模板在編譯的過(guò)程中綁定,因此無(wú)效的類(lèi)型會(huì)讓程序停止編譯。用戶(hù)必須立即解決這個(gè)問(wèn)題或者把它重新處理成非模板編程方案。執(zhí)行程序的完整性不存在風(fēng)險(xiǎn)。

  另一方面,泛型在運(yùn)行時(shí)綁定,在這個(gè)時(shí)候才發(fā)現(xiàn)用戶(hù)指定的類(lèi)型無(wú)效就已經(jīng)太遲了。因此通用語(yǔ)言結(jié)構(gòu)(CLI)需要一些靜態(tài)(也就是編譯時(shí))機(jī)制來(lái)確保在運(yùn)行時(shí)只會(huì)綁定有效的類(lèi)型。與泛型相關(guān)的約束列表是編譯時(shí)過(guò)濾器,也就是說(shuō),如果違反的時(shí)候,會(huì)阻止程序的建立。

   我們來(lái)看一個(gè)例子。圖5顯示了用泛型實(shí)現(xiàn)的容器類(lèi)。它的搜索方法假設(shè)類(lèi)型參數(shù)衍生自Icomparable,因此它實(shí)現(xiàn)了該接口的CompareTo方 法的一個(gè)實(shí)例。請(qǐng)注意,容器的大小是在構(gòu)造函數(shù)中由用戶(hù)提供的,而不是作為第二個(gè)、非類(lèi)型參數(shù)提供的。你應(yīng)該記得泛型不支持非類(lèi)型參數(shù)的。

  代碼5:作為泛型實(shí)現(xiàn)的容器

generic <class elemType>
public ref class Container
{
 array<elemType> ^m_buf;
 int next;
 int size;
 
public:
 bool search( elemType et )
 {
  for each ( elemType e in m_buf )
   if ( et->CompareTo( e ))
    return true;
   return false;
 }

 Container( int sz )
 {
  m_buf = gcnew array<elemType>(size = sz);
  next = 0;
 }

 // add() 和 get() 是相同的 ...

};

  該泛型類(lèi)的實(shí)現(xiàn)在編譯的時(shí)候失敗了,遇到了如下所示的致命的編譯診斷信息:

error C2039: 'CompareTo' : is not a member of 'System::Object'

   你也許有點(diǎn)糊涂了,這是怎么回事?沒(méi)有人認(rèn)為它是System::Object的成員啊。但是,在這種情況下你就錯(cuò)了。在默認(rèn)情況下,泛型參數(shù)執(zhí)行最嚴(yán) 格的可能的約束:它把自己的所有類(lèi)型約束為Object類(lèi)型。這個(gè)約束條件是對(duì)的,因?yàn)橹辉试SCLI類(lèi)型綁定到泛型上,當(dāng)然,所有的CLI類(lèi)型都多多少少 地衍生自O(shè)bject。因此在默認(rèn)情況下,作為泛型的作者,你的操作非常安全,但是可以使用的操作也是有限的。

  你可能會(huì)想,好吧,我減小靈活性,避免編譯器錯(cuò)誤,用等于操作符代替CompareTo方法,但是它卻引起了更嚴(yán)重的錯(cuò)誤:

error C2676: binary '==' : 'elemType' does not define this operator
or a conversion to a type acceptable to the predefined operator

   同樣,發(fā)生的情況是,每個(gè)類(lèi)型參數(shù)開(kāi)始的時(shí)候都被Object的四個(gè)公共的方法包圍著:ToString、GetType、GetHashCode和 Equals。其效果是,這種在單獨(dú)的類(lèi)型參數(shù)上列出約束條件的工作表現(xiàn)了對(duì)初始的強(qiáng)硬約束條件的逐步放松。換句話(huà)說(shuō),作為泛型的作者,你的任務(wù)是按照泛 型約束列表的約定,采用可以驗(yàn)證的方式來(lái)擴(kuò)展那些允許的操作。我們來(lái)看看如何實(shí)現(xiàn)這樣的事務(wù)。

  我們用約束子句來(lái)引用約束列表,使用非 保留字"where"實(shí)現(xiàn)。它被放置在參數(shù)列表和類(lèi)型聲明之間。實(shí)際的約束包含一個(gè)或多個(gè)接口類(lèi)型和/或一個(gè)類(lèi)類(lèi)型的名稱(chēng)。這些約束顯示了參數(shù)類(lèi)型希望實(shí) 現(xiàn)的或者衍生出類(lèi)型參數(shù)的基類(lèi)。每種類(lèi)型的公共操作集合都被添加到可用的操作中,供類(lèi)型參數(shù)使用。因此,為了讓你的elemType參數(shù)調(diào)用 CompareTo,你必須添加與Icomparable接口關(guān)聯(lián)的約束子句,如下所示:

generic <class elemType>
where elemType : IComparable
public ref class Container
{
 // 類(lèi)的主體沒(méi)有改變 ...
};

   這個(gè)約束子句擴(kuò)展了允許elemType實(shí)例調(diào)用的操作集合,它是隱含的Object約束和顯式的Icomparable約束的公共操作的結(jié)合體。該泛 型定義現(xiàn)在可以編譯和使用了。當(dāng)你指定一個(gè)實(shí)際的類(lèi)型參數(shù)的時(shí)候(如下面的代碼所示),編譯器將驗(yàn)證實(shí)際的類(lèi)型參數(shù)是否與將要綁定的類(lèi)型參數(shù)的約束相匹 配:

int main()
{
 // 正確的:String和int實(shí)現(xiàn)了IComparable
 Container<String^> ^sc;
 Container<int> ^ic;

 //錯(cuò)誤的:StringBuilder沒(méi)有實(shí)現(xiàn)IComparable
 Container<StringBuilder^> ^sbc;
}

  編譯器會(huì)提示某些違反了規(guī)則的信息,例如sbc的定義。但是泛型的實(shí)際的綁定和構(gòu)造已經(jīng)由運(yùn)行時(shí)完成了。

  接著,它會(huì)同時(shí)驗(yàn)證泛型在定義點(diǎn)(編譯器處理你的實(shí)現(xiàn)的時(shí)候)和構(gòu)造點(diǎn)(編譯器根據(jù)相關(guān)的約束條件檢查類(lèi)型參數(shù)的時(shí)候)是否違反了約束。無(wú)論在那個(gè)點(diǎn)失敗都會(huì)出現(xiàn)編譯時(shí)錯(cuò)誤。

  約束子句可以每個(gè)類(lèi)型參數(shù)包含一個(gè)條目。條目的次序不一定跟參數(shù)列表的次序相同。某個(gè)參數(shù)的多個(gè)約束需要使用逗號(hào)分開(kāi)。約束在與每個(gè)參數(shù)相關(guān)的列表中必須唯一,但是可以出現(xiàn)在多個(gè)約束列表中。例如:

generic <class T1, class T2, class T3>
where T1 : IComparable, ICloneable, Image
where T2 : IComparable, ICloneable, Image
where T3 : ISerializable, CompositeImage
public ref class Compositor
{
 // ...
};

   在上面的例子中,出現(xiàn)了三個(gè)約束子句,同時(shí)指定了接口類(lèi)型和一個(gè)類(lèi)類(lèi)型(在每個(gè)列表的末尾)。這些約束是有額外的意義的,即類(lèi)型參數(shù)必須符合所有列出的 約束,而不是符合它的某個(gè)子集。我的同事Jon Wray指出,由于你是作為泛型的作者來(lái)擴(kuò)展操作集合的,因此如果放松了約束條件,那么該泛型的用戶(hù)在選擇類(lèi)型參數(shù)的時(shí)候就得增加更多的約束。

  T1、T2和T3子句可以按照其它的次序放置。但是,不允許跨越兩個(gè)或多個(gè)子句指定某個(gè)類(lèi)型參數(shù)的約束列表。例如,下面的代碼就會(huì)出現(xiàn)違反語(yǔ)法錯(cuò)誤:

generic <class T1, class T2, class T3>
// 錯(cuò)誤的:同一個(gè)參數(shù)不允許有兩個(gè)條目
where T1 : IComparable, ICloneable
where T1 : Image
public ref class Compositor
{
 // ...
};

   類(lèi)約束類(lèi)型必須是未密封的(unsealed)參考類(lèi)(數(shù)值類(lèi)和密封類(lèi)都是不允許的,因?yàn)樗鼈儾辉试S繼承)。有四個(gè)System名字空間類(lèi)是禁止出現(xiàn)在 約束子句中的,它們分別是:System::Array、System::Delegate、 System::Enum和System::ValueType。由于CLI只支持單繼承(single inheritance),約束子句只支持一個(gè)類(lèi)類(lèi)型的包含。約束類(lèi)型至少要像泛型或函數(shù)那樣容易訪問(wèn)。例如,你不能聲明一個(gè)公共泛型并列出一個(gè)或多個(gè)內(nèi) 部可視的約束。

  任何類(lèi)型參數(shù)都可以綁定到一個(gè)約束類(lèi)型。下面是一個(gè)簡(jiǎn)單的例子:

generic <class T1, class T2>
where T1 : IComparable<T1>
where T2 : IComparable<T2>
public ref class Compositor
{
 // ...
};

  約束是不能繼承的。例如,如果我從Compositor繼承得到下面的類(lèi),Compositor的T1和T2上的Icomparable約束不會(huì)應(yīng)用在 BlackWhite_Compositor類(lèi)的同名參數(shù)上:

generic <class T1, class T2>
public ref class BlackWhite_Compositor : Compositor
{
 // ...
};

  當(dāng)這些參數(shù)與基類(lèi)一起使用的時(shí)候,這就有幾分設(shè)計(jì)方面的便利了。為了保證Compositor的完整性,BlackWhite_Compositor必須把Compositor約束傳播給那些傳遞到Compositor子對(duì)象的所有參數(shù)。例如,正確的聲明如下所示:

generic <class T1, class T2>
where T1 : IComparable<T1>
where T2 : IComparable<T2>
public ref class BlackWhite_Compositor : Compositor
{
 // ...
};

  包裝

  你已經(jīng)看到了,在C++/CLI下面,你可以選擇CLR泛型或C++模板?,F(xiàn)在你所擁有的知識(shí)已經(jīng)可以根據(jù)特定的需求作出明智的選擇了。在兩種機(jī)制下,超越元素的存儲(chǔ)和檢索功能的參數(shù)化類(lèi)型都包含了每種類(lèi)型參數(shù)必須支持操作的假設(shè)。

   使用模板的時(shí)候,這些假設(shè)都是隱含的。這給模板的作者帶來(lái)了很大的好處,他們對(duì)于能夠?qū)崿F(xiàn)什么樣的功能有很大的自由度。但是,這對(duì)于模板的使用者是不利 的,他們經(jīng)常面對(duì)某些可能的類(lèi)型參數(shù)上的沒(méi)有正式文檔記載的約束集合。違反這些約束集合就會(huì)導(dǎo)致編譯時(shí)錯(cuò)誤,因此它對(duì)于運(yùn)行時(shí)的完整性不是威脅,模板類(lèi)的 使用可以阻止失敗出現(xiàn)。這種機(jī)制的設(shè)計(jì)偏好傾向于實(shí)現(xiàn)者。

  使用泛型的時(shí)候,這些假設(shè)都被明顯化了,并與約束子句中列舉的基本類(lèi)型 集合相關(guān)聯(lián)。這對(duì)泛型的使用者是有利的,并且保證傳遞給運(yùn)行時(shí)用于類(lèi)型構(gòu)造的任何泛型都是正確的。據(jù)我看來(lái),它在設(shè)計(jì)的自由度上有一些約束,并且使某些模 板設(shè)計(jì)習(xí)慣稍微難以受到支持。對(duì)這些形式約束的違反,無(wú)論使在定義點(diǎn)還是在用戶(hù)指定類(lèi)型參數(shù)的時(shí)候,都會(huì)導(dǎo)致編譯時(shí)錯(cuò)誤。這種機(jī)制的設(shè)計(jì)偏好傾向于消費(fèi) 者。

posted on 2007-10-05 01:56 旅途 閱讀(272) 評(píng)論(0)  編輯 收藏 引用 所屬分類(lèi): C/C++

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            在线免费精品视频| 久久精品国产第一区二区三区最新章节| 亚洲国产精品综合| 一区二区三区在线观看视频| 韩国精品在线观看| 极品少妇一区二区| 亚洲茄子视频| 亚洲性线免费观看视频成熟| 亚洲综合色视频| 久久久午夜电影| 欧美激情小视频| 一区电影在线观看| 久久久www成人免费毛片麻豆| 久久天堂成人| 欧美日韩伦理在线| 国产丝袜一区二区| 亚洲激情在线观看视频免费| 亚洲欧美日韩在线| 欧美~级网站不卡| 一本久道久久久| 久久人91精品久久久久久不卡| 欧美另类视频在线| 国产在线视频欧美一区二区三区| 91久久精品国产91久久性色| 香港久久久电影| 亚洲黄色高清| 欧美一区二区三区精品电影| 欧美电影资源| 激情欧美一区| 午夜精品久久久久久久蜜桃app | 欧美激情一级片一区二区| 亚洲精品一区二区在线观看| 性做久久久久久久免费看| 老色批av在线精品| 国产精品综合久久久| 亚洲理伦电影| 久久久国产精品亚洲一区| 亚洲精品在线视频| 久久人人97超碰国产公开结果 | 亚洲欧美资源在线| 欧美国产一区二区在线观看| 国模精品一区二区三区色天香| 一区二区激情视频| 欧美福利一区二区| 欧美一区二区播放| 国产精品美女久久久| 亚洲人成人一区二区三区| 久久久久久穴| 亚洲综合色噜噜狠狠| 欧美日韩一区二区免费视频| 亚洲精品资源| 亚洲国产美女久久久久| 久久人人超碰| 在线激情影院一区| 免费观看在线综合色| 久久www免费人成看片高清| 国产精品午夜电影| 亚洲欧美日韩人成在线播放| 夜夜嗨一区二区三区| 欧美久久久久免费| 一本大道久久a久久精二百| 91久久精品日日躁夜夜躁国产| 你懂的亚洲视频| 亚洲精品一区二区在线| 亚洲第一伊人| 欧美精品日韩精品| 中文在线一区| 中文国产成人精品| 国产精品美女久久久久久免费| 先锋影音国产精品| 欧美一区观看| 激情国产一区| 欧美成人免费在线| 欧美国产亚洲精品久久久8v| 一本一本a久久| 亚洲愉拍自拍另类高清精品| 国产亚洲福利| 欧美高清在线精品一区| 欧美理论在线| 久久福利一区| 美女视频黄免费的久久| 一区二区三区高清| 亚洲欧美精品在线| 亚洲第一黄色| 一本色道久久| 极品裸体白嫩激情啪啪国产精品| 欧美大片在线影院| 欧美日韩在线不卡一区| 在线欧美影院| 午夜欧美大尺度福利影院在线看| 亚洲视频欧美在线| 国内精品久久久久影院 日本资源| 久久综合给合久久狠狠色| 欧美黑人在线观看| 欧美在线免费播放| 欧美/亚洲一区| 欧美一级二区| 免费成人高清视频| 欧美一区二区播放| 你懂的视频欧美| 欧美一级大片在线观看| 欧美成ee人免费视频| 欧美一区二区在线| 欧美精品在欧美一区二区少妇| 欧美一站二站| 欧美精品在线一区二区| 久久婷婷国产综合尤物精品| 欧美日韩国内| 欧美成人dvd在线视频| 国产精品免费观看在线| 亚洲国产精品www| 国产一区二区三区无遮挡| 亚洲毛片在线看| 亚洲福利专区| 久久精品男女| 欧美一区二区三区成人 | 欧美日在线观看| 久久一二三区| 国产精品夜夜夜| 日韩视频国产视频| 亚洲伦理在线观看| 狂野欧美激情性xxxx| 久久久久久国产精品mv| 国产精品v欧美精品v日本精品动漫| 欧美国产在线视频| 韩日在线一区| 欧美一级一区| 久久久xxx| 国产一区二区三区视频在线观看| 亚洲伊人一本大道中文字幕| 亚洲无亚洲人成网站77777| 欧美精品久久一区| 91久久国产综合久久91精品网站| 樱桃视频在线观看一区| 久久精品91久久香蕉加勒比 | 最近中文字幕mv在线一区二区三区四区| 国产一区二区三区的电影| 亚洲欧美怡红院| 久久精品免费电影| 国产亚洲视频在线观看| 欧美中文在线字幕| 久久天天狠狠| 亚洲国产成人在线| 欧美成人国产| 亚洲精品美女在线观看| 一区二区三区国产在线| 欧美午夜精品久久久久久久 | 亚洲综合国产| 国产精品日韩欧美综合| 午夜视频一区在线观看| 麻豆成人在线| 香蕉亚洲视频| 国产精品尤物福利片在线观看| 亚洲在线中文字幕| 久久黄色影院| 在线成人欧美| 欧美国产第二页| 99综合视频| 久久久久青草大香线综合精品| 在线不卡视频| 欧美日韩国产页| 午夜精品电影| 免费高清在线一区| 一本色道久久综合亚洲精品小说| 国产精品久久久久久亚洲毛片| 久久成人这里只有精品| 欧美国产在线电影| 亚洲综合色自拍一区| 国产一区二区三区日韩欧美| 欧美96在线丨欧| 亚洲伊人伊色伊影伊综合网| 免费成人激情视频| 亚洲永久精品国产| 在线日韩av永久免费观看| 欧美日韩另类综合| 久久久亚洲高清| 国产精品99久久久久久白浆小说| 另类春色校园亚洲| 亚洲综合色网站| 亚洲人成小说网站色在线| 国产日产精品一区二区三区四区的观看方式| 久久久久久黄| 亚洲性视频网址| 亚洲国产成人av| 久久久久久久一区| 亚洲一区三区视频在线观看| 亚洲国产专区校园欧美| 国产精品一二| 欧美精品精品一区| 久久久久久久久久久久久久一区| 国产精品99久久久久久久vr| 亚洲福利视频在线| 裸体女人亚洲精品一区| 欧美一级淫片aaaaaaa视频| 亚洲免费av片| 亚洲精品少妇30p| 永久免费精品影视网站| 国产一区二区三区四区hd| 国产精品区二区三区日本| 欧美日韩国产探花|