中文字幕免费精品_亚洲视频自拍_亚洲综合国产激情另类一区_色综合咪咪久久

C++泛型用法
來源:易賢網 閱讀:2192 次 日期:2014-09-05 15:49:24
溫馨提示:易賢網小編為您整理了“C++泛型用法”,方便廣大網友查閱!

我們先來看一個最為常見的泛型類型List<T>的定義

(真正的定義比這個要復雜的多,我這里刪掉了很多東西)

[Serializable]

public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>

{

public T this[int index] { get; set; }

public void Add(T item);

public void Clear();

public bool Contains(T item);

public int IndexOf(T item);

public bool Remove(T item);

public void Sort();

public T[] ToArray();

}

List后面緊跟著一個<T>表示它操作的是一個未指定的數據類型(T代表著一個未指定的數據類型)

可以把T看作一個變量名,T代表著一個類型,在List<T>的源代碼中任何地方都能使用T。

T被用作方法的參數和返回值。

Add方法接收T類型的參數,ToArray方法返回一個T類型的數組

注意:

泛型參數必須以T開頭,要么就叫T,要么就叫TKey或者TValue;

這跟接口要以I開頭是一樣的,這是約定。

下面來看一段使用泛型類型的代碼

var a = new List<int>();

a.Add(1);

a.Add(2);

//這是錯誤的,因為你已經指定了泛型類型為int,就不能在這個容器中放入其他的值

//這是編譯器錯誤,更提升了排錯效率,如果是運行期錯誤,不知道要多么煩人

a.Add("3");

var item = a[2];

請注意上面代碼里的注釋

二、泛型的作用(1):

作為程序員,寫代碼時刻不忘代碼重用。

代碼重用可以分成很多類,其中算法重用就是非常重要的一類,假設你要為一組整型數據寫一個排序算法,又要為一組浮點型數據寫一個排序算法,如果沒有泛型類型,你會怎么做呢?

你可能想到了方法的重載。

寫兩個同名方法,一個方法接收整型數組,另一個方法接收浮點型的數組。

但有了泛型,你就完全不必這么做,只要設計一個方法就夠用了,你甚至可以用這個方法為一組字符串數據排序。

三、泛型的作用(2):

假設你是一個方法的設計者,這個方法需要有一個輸入參數,但你并能確定這個輸入參數的類型,那么你會怎么做呢?

有一部分人可能會馬上反駁:“不可能有這種時候!”

那么我會跟你說,編程是一門經驗型的工作,你的經驗還不夠,還沒有碰到過類似的地方。

另一部分人可能考慮把這個參數的類型設置成Object的,這確實是一種可行的方案,但會造成下面兩個問題,如果我給這個方法傳遞整形的數據(值類型的數據都一樣),就會產生額外的裝箱、拆箱操作,造成性能損耗。

如果你這個方法里的處理邏輯不適用于字符串的參數,而使用者又傳了一個字符串進來,編譯器是不會報錯的,只有在運行期才會報錯。

(如果質管部門沒有測出這個運行期BUG,那么不知道要造成多大的損失呢)

這就是我們常說的:類型不安全。

四、泛型的示例:

像List<T>和Dictionary<TKey,TValue>之類的泛型類型我們經常用到,下面我介紹幾個不常用到的泛型類型。

ObservableCollection<T>

當這個集合發生改變后會有相應的事件得到通知。

請看如下代碼:

static void Main(string[] args)

{

var a = new ObservableCollection<int>();

a.CollectionChanged += a_CollectionChanged;

}

static void a_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)

{

//可以通過Action來判斷是什么操作觸發了事件

//e.Action == NotifyCollectionChangedAction.Add

//可以根據以下兩個屬性來得到更改前和更改后的內容

//e.NewItems;

//e.OldItems;

}

使用這個集合需要引用如下兩個名稱空間

using System.Collections.ObjectModel;

using System.Collections.Specialized;

BlockingCollection<int>是線程安全的集合

來看看下面這段代碼

var bcollec = new BlockingCollection<int>(2);

//試圖添加1-50

Task.Run(() =>

{

//并行循環

Parallel.For(1, 51, i =>

{

bcollec.Add(i);

Console.WriteLine("加入:" + i);

});

});

Thread.Sleep(1000);

Console.WriteLine("調用一次Take");

bcollec.Take();

//等待無限長時間

Thread.Sleep(Timeout.Infinite);

輸出結果為:

加入:1

加入:37

調用一次Take

加入:13

BlockingCollection<int>還可以設置CompleteAdding和IsCompleted屬性來拒絕加入新元素。

.NET類庫還提供了很多的泛型類型,在這里就不一一例舉了。

五、泛型的繼承:

在.net中一切都繼承字Object,泛型也不例外,泛型類型可以繼承自其他類型。

來看一下如下代碼

public class MyType

{

public virtual string getOneStr()

{

return "base object Str";

}

}

public class MyOtherType<T> : MyType

{

public override string getOneStr()

{

return typeof(T).ToString();

}

}

class Program

{

static void Main(string[] args)

{

MyType target = new MyOtherType<int>();

Console.WriteLine(target.getOneStr());

Console.ReadKey();

}

}

泛型類型MyOtherType<T>成功的重寫了非泛型類型MyType的方法。

如果我試圖按如下方式從MyOtherType<T>類型派生子類型就會導致編譯器錯誤。

//編譯期錯誤

public class MyThirdType : MyOtherType<T>

{

}

但是如果寫成這種方式,就不會出錯

public class MyThirdType : MyOtherType<int>

{

public override string getOneStr()

{

return "MyThirdType";

}

}

注意:

如果按照如上寫法,會造成類型不統一的問題,

如果一個方法接收MyThirdType類型的參數,

那么不能將一個MyOtherType<int>的實例傳遞給這個方法, 

然而一個方法如果接收MyOtherType<int>類型的參數,

卻可以把MyThirdType類型的實例傳遞給這個方法,

這是CLR內部實現機制造成的,

這看起來確實很怪異!

寫成如下方式也不會出錯:

public class MyThirdType<T> : MyOtherType<T>

{

public override string getOneStr()

{

return typeof(T).ToString() + " from MyThirdType";

}

}

此中訣竅,只可意會,不可言傳。

六、泛型接口

.NET類庫里有很多泛型的接口,比如:IEnumerator<T>、IList<T>等,這里不對這些接口做詳細描述了,值說說為什么要有泛型接口。

其實泛型接口出現的原因和泛型出現的原因類似,拿IComparable這個接口來說,此接口只描述了一個方法:

int CompareTo(object obj);

大家看到,如果是值類型的參數,勢必會導致裝箱和拆箱操作。

同時,也不是強類型的,不能在編譯期確定參數的類型,有了IComparable<T>就解決掉這個問題了:

int CompareTo(T other);

七、泛型委托

委托描述方法,泛型委托的由來和泛型接口類似。

定義一個泛型委托也比較簡單:

public delegate void MyAction<T>(T obj);

這個委托描述一類方法,這類方法接收T類型的參數,沒有返回值。

來看看使用這個委托的方法:

public delegate void MyAction<T>(T obj);

static void Main(string[] args)

{

var method = new MyAction<int>(printInt);

method(3);

Console.ReadKey();

}

static void printInt(int i)

{

Console.WriteLine(i);

}

由于定義委托比較繁瑣,.NET類庫在System名稱空間,下定義了三種比較常用的泛型委托。

Predicate<T>委托:

public delegate bool Predicate<T>(T obj);

這個委托描述的方法為接收一個T類型的參數,返回一個BOOL類型的值,一般用于比較方法。

Action<T>委托

public delegate void Action<T>(T obj);

public delegate void Action<T1, T2>(T1 arg1, T2 arg2);

這個委托描述的方法,接收一個或多個T類型的參數(最多16個,我這里只寫了兩種類型的定義方式),沒有返回值。

Func<T>委托

public delegate TResult Func<TResult>();

public delegate TResult Func<T, TResult>(T arg);

這個委托描述的方法,接收零個或多個T類型的參數(最多16個,我這里只寫了兩種類型的定義方式),與Action委托不同的是,它有一個返回值,返回值的類型為TResult類型的。

關于委托的描述,您還可以看我這篇文章。

八、泛型方法

泛型類型中的T可以用在這個類型的任何地方,然而有些時候,我們不希望在使用類型的時候就指定T的類型,我們希望在使用這個類型的方法時,再指定T的類型。

來看看如下代碼:

public class MyClass

{

public TParam CompareTo<TParam>(TParam other)

{

Console.WriteLine(other.ToString());

return other;

}

}

上面的代碼中MyClass并不是一個泛型類型,但這個類型中的CompareTo<TParam>()卻是一個泛型方法,TParam可以用在這個方法中的任何地方。

使用泛型方法一般用如下代碼就可以了:

obj.CompareTo<int>(4);

obj.CompareTo<string>("ddd");

然而,你可以寫的更簡單一些,寫成如下的方式:

obj.CompareTo(2);

obj.CompareTo("123");

有人會問:“這不可能,沒有指定CompareTo方法的TParam類型,肯定會編譯出錯的”

我告訴你:不會的,編譯器可以幫你完成類型推斷的工作。

注意:

如果你為一個方法指定了兩個泛型參數,而且這兩個參數的類型都是T,那么如果你想使用類型推斷,你必須傳遞兩個相同類型的參數給這個方法,不能一個參數用string類型,另一個用object類型,這會導致編譯錯誤。

九、泛型約束

我們設計了一個泛型類型,很多時候,我們不希望使用者傳入任意類型的參數,也就是說,我們希望“約束”一下T的類型。

來看看如下代碼:

public class MyClass<T> where T : IComparable<T>

{

public int CompareTo(T other)

{

return 0;

}

}

上面的代碼要求T類型必須實現了IComparable<T>接口。

如你所見:泛型的約束通過關鍵字where來實現。

泛型方法當然也可以通過類似的方式對泛型參數進行約束。

請看如下代碼:

public class MyClass

{

public TParam CompareTo<TParam>(TParam other) where TParam:class

{

Console.WriteLine(other.ToString());

return other;

}

}

上面代碼中用了class關鍵字約束泛型參數TParam;具體稍后解釋。

注意1:

如果我有一個類型也定義為MyClass<T>但沒有做約束,那么這個時候,做過約束的MyClass<T>將與沒做約束的MyClass<T>沖突,編譯無法通過。

注意2:

當你重寫一個泛型方法時,如果這個方法指定了約束,在重寫這個方法時,不能再指定約束了。

注意3:

雖然我上面的例子寫的是接口約束,但你完全可以寫一個類型,比如說BaseClass。而且,只要是繼承自BaseClass的類型都可以當作T類型使用,你不要試圖約束T為Object類型,編譯不會通過的。(傻子才這么干)

注意4:

有兩個特殊的約束:class和struct。

where T : class 約束T類型必須為引用類型

where T : struct 約束T類型必須為值類型

注意5:

如果你沒有對T進行class約束,

那么你不能寫這樣的代碼:T obj = null; 這無法通過編譯,因為T有可能是值類型的。

如果你沒有對T進行struct約束,也沒有對T進行new約束。

那么你不能寫這樣的代碼:T obj = new T(); 這無法通過編譯,因為值類型肯定有無參數構造器,而引用類型就不一定了。

如果你對T進行了new約束:where T : new(); 那么new T()就是正確的,因為new約束要求T類型有一個公共無參構造器。

注意6:

就算沒有對T進行任何約束,也有一個辦法來處理值類型和引用類型的問題。

T temp = default(T);

如果T為引用類型,那么temp就是null;如果T為值類型,那么temp就是0;

注意7:

試圖對T類型的變量進行強制轉化,一般情況下會報編譯期錯誤。

但你可以先把T轉化成object再把object轉化成你要的類型(一般不推薦這么做,你應該考慮把T轉化成一個約束兼容的類型)。

你也可以考慮用as操作符進行類型轉化,這一般不會報錯,但只能轉化成引用類型。

關于泛型約束的內容,我在這篇文章里也有提到。

十、逆變和協變

一般情況下,我們使用泛型時,由T標記的泛型類型是不能更改的。

也就是說,如下兩種寫法都是錯誤的:

var a = new List<object>();

List<string> b = a;

var c = new List<string>();

List<object> d = c;

注意:這里沒有寫強制轉換,即使寫了強制轉換也是錯誤的,編譯就無法通過,然而泛型提供了逆變和協變的特性,有了這兩種特性,這種轉換就成為了可能。

逆變:

泛型類型T可以從基類型更改為該類的派生類型,用in關鍵字標記逆變形式的類型參數,而且這個參數一般作輸入參數。

協變:

泛型類型T可以從派生類型更改為它的基類型,用out關鍵字來標記協變形式的類型參數,而且這個參數一般作為返回值。

如果我們定義了一個這樣的委托:

public delegate TResult MyAction<in T,out TResult>(T obj);

那么,就可以讓如下代碼通過編譯(不用強制轉換)

var a = new MyAction<object, ArgumentException>(o => new ArgumentException(o.ToString()));

MyAction<string, Exception> b = a;

這就是逆變和協變的威力。

更多信息請查看IT技術專欄

更多信息請查看網絡編程
易賢網手機網站地址:C++泛型用法
由于各方面情況的不斷調整與變化,易賢網提供的所有考試信息和咨詢回復僅供參考,敬請考生以權威部門公布的正式信息和咨詢為準!

2026上岸·考公考編培訓報班

  • 報班類型
  • 姓名
  • 手機號
  • 驗證碼
關于我們 | 聯系我們 | 人才招聘 | 網站聲明 | 網站幫助 | 非正式的簡要咨詢 | 簡要咨詢須知 | 新媒體/短視頻平臺 | 手機站點 | 投訴建議
工業和信息化部備案號:滇ICP備2023014141號-1 云南省教育廳備案號:云教ICP備0901021 滇公網安備53010202001879號 人力資源服務許可證:(云)人服證字(2023)第0102001523號
云南網警備案專用圖標
聯系電話:0871-65099533/13759567129 獲取招聘考試信息及咨詢關注公眾號:hfpxwx
咨詢QQ:1093837350(9:00—18:00)版權所有:易賢網
云南網警報警專用圖標
中文字幕免费精品_亚洲视频自拍_亚洲综合国产激情另类一区_色综合咪咪久久
亚洲啪啪91| 亚洲一区二区免费| 久久亚洲综合网| 美女任你摸久久| 国产日韩在线播放| 日韩亚洲精品在线| 免费不卡在线观看| 国产精品综合视频| 亚洲人妖在线| 欧美α欧美αv大片| 国产精品一区一区三区| 在线中文字幕日韩| 美国十次了思思久久精品导航| 久久久欧美精品sm网站| 国产在线拍偷自揄拍精品| 亚洲精选在线| 欧美日本一区二区视频在线观看| 国产综合香蕉五月婷在线| 午夜精品视频一区| 欧美色大人视频| 亚洲人成网站999久久久综合| 另类专区欧美制服同性| 国产精品卡一卡二卡三| 亚洲欧美日韩精品久久久久| 欧美人交a欧美精品| 亚洲毛片播放| 欧美国产大片| 亚洲国产视频直播| 免费不卡亚洲欧美| 一区二区视频在线观看| 快播亚洲色图| **欧美日韩vr在线| 欧美日韩国产精品自在自线| 亚洲人成精品久久久久| 国产有码在线一区二区视频| 久久蜜臀精品av| 国产一区美女| 欧美顶级少妇做爰| 亚洲欧洲在线视频| 欧美视频在线观看一区二区| 正在播放亚洲| 国产丝袜一区二区三区| 午夜亚洲激情| 国产精品嫩草久久久久| 欧美一区日本一区韩国一区| 国产精品一区二区a| 久久精品欧洲| 在线观看视频一区二区| 欧美精品在线观看91| 一个色综合av| 亚洲美女在线看| 欧美乱妇高清无乱码| 亚洲一卡久久| 国产精品日韩久久久久| 一区二区冒白浆视频| 国产精品午夜视频| 国产精品视频午夜| 欧美成人综合| 亚洲欧洲一区二区天堂久久| 黄色在线一区| 99视频有精品| 国产精品高清免费在线观看| 亚洲午夜精品久久久久久浪潮 | 久久精品亚洲精品| 亚洲一区二区三区视频| 欧美日韩一本到| 亚洲欧美日本精品| 国产一区二区三区高清| 另类国产ts人妖高潮视频| 日韩视频永久免费| 国产欧美一区二区精品性色| 欧美一区二区播放| 亚洲第一中文字幕| 噜噜噜噜噜久久久久久91| 在线国产日韩| 欧美激情亚洲| 亚洲免费人成在线视频观看| 国产一区二区丝袜高跟鞋图片 | 激情久久五月天| 欧美精品xxxxbbbb| 欧美一区二区在线播放| 亚洲欧洲一区| 国产精品视频最多的网站| 久久久久久9| 亚洲午夜三级在线| 国产亚洲观看| 久久资源在线| 亚洲欧美中文日韩在线| 在线精品观看| 国产精品羞羞答答xxdd| 欧美激情精品久久久久久久变态 | 亚洲精品中文字幕在线| 国产精品另类一区| 免费在线观看一区二区| 亚洲欧美综合国产精品一区| 亚洲国产精品成人久久综合一区| 国产精品户外野外| 欧美福利小视频| 亚洲欧美日韩中文视频| 在线日本欧美| 国产农村妇女精品一区二区| 欧美国产日韩在线| 欧美一区二区三区免费视| 国产日本欧美一区二区| 麻豆成人综合网| 亚洲欧美制服中文字幕| 亚洲一区二区高清| 亚洲日本乱码在线观看| 国产资源精品在线观看| 欧美性大战xxxxx久久久| 免费日本视频一区| 久久激情视频久久| 午夜精品久久久久久久99黑人| 久久久亚洲高清| 国产精品白丝av嫩草影院| 99综合精品| 久久亚洲精品网站| 亚洲欧美日韩区| 午夜日韩av| 中文高清一区| 亚洲一区二区精品| 在线视频亚洲一区| 亚洲宅男天堂在线观看无病毒| 99国产精品视频免费观看一公开| 亚洲精品乱码久久久久久蜜桃麻豆| 激情小说另类小说亚洲欧美| 国产精品久久久久国产a级| 国产精品免费网站| 欧美午夜精品一区| 国产日韩欧美在线视频观看| 国产伦精品一区二区三区免费| 国产欧美午夜| 国产日本欧美一区二区| 亚洲成人自拍视频| 亚洲精品久久久久久下一站 | 国产日本亚洲高清| 国内精品美女av在线播放| 国产日韩在线亚洲字幕中文| 国产精品日韩高清| 在线观看日韩www视频免费| 黄色在线成人| 亚洲午夜激情| 午夜精品久久久久久久久| 久久综合久色欧美综合狠狠| 久久在线播放| 欧美高清不卡在线| 国产麻豆日韩| 狠狠色伊人亚洲综合网站色| 亚洲精品在线电影| 亚洲一区www| 免费成人网www| 国产日韩精品一区二区三区在线| 性欧美8khd高清极品| 一本色道久久综合狠狠躁篇的优点| 老司机精品视频网站| 欧美人妖另类| 欧美三级乱码| 欧美日韩三区| 黑人一区二区| 亚洲三级视频| 欧美综合国产精品久久丁香| 久久久噜噜噜久久中文字免| 欧美激情片在线观看| 欧美视频中文一区二区三区在线观看| 欧美精品在线一区| 国产综合av| 亚洲精品久久| 久久精品视频导航| 欧美国产日韩一二三区| 国产亚洲精品美女| 亚洲激情亚洲| 国产精品99久久不卡二区| 噜噜噜躁狠狠躁狠狠精品视频| 欧美精品尤物在线| 黄色资源网久久资源365| 日韩视频在线你懂得| 久久久青草婷婷精品综合日韩| 欧美另类变人与禽xxxxx| 久久精品在线播放| 国产精品magnet| 精品999网站| 小黄鸭精品密入口导航| 久久夜色精品国产欧美乱| 国产精品视频一区二区三区| 亚洲国产裸拍裸体视频在线观看乱了 | 亚洲福利在线看| 在线亚洲自拍| 欧美电影免费观看高清完整版| 国产精品高清免费在线观看| 黄色综合网站| 亚洲欧美日韩一区二区| 久久久久免费视频| 国产精品一卡二| 99国产精品国产精品毛片| 欧美电影资源| 狠狠色狠狠色综合日日tαg| 欧美亚洲专区| 欧美在线高清| 香蕉久久夜色精品| 亚洲欧美日韩天堂一区二区|