丁香五月婷婷黄色视频_97在线看观看免费_男女xo嘿咻嘿咻动态图_最近更新在线中文字幕人妻

?

模板偏特化翻譯 為什么基類的成員在父類中調(diào)用必須指明作用域或者使用this->?

日期:2023-03-11 12:39:36 / 人氣: 435 / 發(fā)布者:成都翻譯公司

在obj類模板調(diào)用含有模板參數(shù)的類成員函數(shù)之前,其實(shí)就是在”成員訪問運(yùn)算符(.我們看到,這個(gè)程序中Father類對(duì)象Obj1的成員函數(shù)Foo并沒有調(diào)用從Base類中繼承的exit函數(shù),我們應(yīng)該這樣改正這個(gè)程序(明確exit函數(shù)的歸屬位置,即我們到底要調(diào)用那里的exit函數(shù))。當(dāng)模板實(shí)例化時(shí),模板的全特化,模板的偏特化都適用時(shí)的調(diào)用順序:

C++ 模板的技術(shù)基礎(chǔ)

內(nèi)容

關(guān)鍵字 typename 的使用

#include???
using?namespace?std;??
#include???
??
template???
void?PrintElement(T?const&?obj)??
{??
????typename?T::const_iterator?cpos;??
????typename?T::const_iterator?end?=?obj.cend();??
????for?(cpos?=?obj.cbegin();?cpos?!=?end;?cpos++)??
????{??
????????cout?<?Obj{?1,2,3,4,5,6,7,8,9,10?};??
????PrintElement(Obj);??
}??

有時(shí)T是一個(gè)類,其他類嵌套在該類中。例如,在STL標(biāo)準(zhǔn)模板庫中的vector類中,就有“const_iterator只讀迭代器”、“迭代器可讀可寫迭代器”等常用的嵌套類類型。.

當(dāng)我們構(gòu)建模板時(shí),我們會(huì)發(fā)現(xiàn)編譯器不會(huì)給我們?nèi)魏翁崾拘畔?。這是因?yàn)樵趯?shí)例化模板之前,編譯器不知道參數(shù) T 是什么類型。你在編譯器不知道時(shí)使用 T : :const_iterator,其他編譯器不知道你是什么。您可以使用 :: 訪問很多東西。類類型中的靜態(tài)靜態(tài)成員變量也可以通過類類型 T 加 :: 作用域訪問器來訪問。所以我們要讓編譯器知道 T::const_iterator 是 T 類型的嵌套子類類型模板偏特化翻譯,我們必須用 typename 聲明它。

例如:(解釋typename關(guān)鍵字的作用)

在上面的程序中,因?yàn)橛衪ypename,編譯器認(rèn)為ptr是一個(gè)T::SubType類型的指針,但是如果沒有typename呢?這時(shí)候編譯器會(huì)把T::SubType當(dāng)作T類型的靜態(tài)成員變量,那么T::SubType * ptr被認(rèn)為是兩個(gè)變量的相乘(編譯器認(rèn)為*是乘號(hào)?),如果你編譯如果你這樣操作設(shè)備,你的程序就會(huì)報(bào)錯(cuò),然后就涼了。

.模板構(gòu)造

#include???
#include???
using?namespace?std;??
??
template???
void?PrintBitset(bitset?const&?obj)??
{??
????cout?<,?allocator?>()?<?Obj;??
????PrintBitset(Obj);??
}?

???????

看上面的例子,我們會(huì)覺得有些不對(duì)勁,為什么要加一個(gè)“.template”呢?我們先來分析一下這個(gè)例子的特點(diǎn):

① obj 是一個(gè)包含模板參數(shù)的類對(duì)象;

② to_string 是包含模板參數(shù)的類成員函數(shù);

在這種情況下,為了防止編譯器:

把它想象成“兩個(gè)成員正在比較大小”:

我們這樣做:

#include???
#include???
using?namespace?std;??
??
template???
void?PrintBitset(bitset?const&?obj)??
{??
????cout?<,?allocator?>()?<?Obj;??
????PrintBitset(Obj);??
}??

obj 類模板在調(diào)用包含模板參數(shù)的類成員函數(shù)之前,實(shí)際上是在“成員訪問運(yùn)算符(.)”之后插入了模板關(guān)鍵字。其實(shí)在VS2017中試過很多次模板偏特化翻譯,感覺.template關(guān)鍵字加不加。沒有區(qū)別。我覺得《C++模板》一書中提到的這部分注意事項(xiàng)應(yīng)該是針對(duì)某些編譯器的。不同的編譯器的性能通常略有不同,可能會(huì)出現(xiàn)在這里。錯(cuò)誤,我覺得*好加上template關(guān)鍵字,這樣可以保證你的程序在任何編譯器中編譯都不會(huì)出錯(cuò)。

實(shí)踐小項(xiàng)目

要求:我們有N個(gè)人的團(tuán)隊(duì),每個(gè)團(tuán)隊(duì)的每個(gè)工人都有“姓名,每周工作時(shí)間(h)和每周工資(100元)”,我們要問這個(gè)團(tuán)隊(duì)的平均小時(shí)平均工資工資*高的人以及相應(yīng)工作人員的姓名。

代碼示例:

團(tuán)隊(duì).hpp

#include???
#include???
#include???
using?namespace?std;??
??
template???
class?Team;??
??
class?Worker??
{??
????template???
????friend?class?Team;??
private:??
????string?name;??
????int?NowSalary;??
????int?WorkTime;??
public:??
????Worker()?{};??
????Worker(const?Worker&?Obj)??
????{??
????????this->name?=?Obj.name;??
????????this->NowSalary?=?Obj.NowSalary;??
????????this->WorkTime?=?Obj.WorkTime;??
????}??
????Worker(string?name,?int?NowSalary,?int?WorkTime)??
????{??
????????this->name?=?name;??
????????this->NowSalary?=?NowSalary;??
????????this->WorkTime?=?WorkTime;??
????}??
????Worker&?operator?=?(const?Worker&?Obj)??
????{??
????????this->name?=?Obj.name;??
????????this->NowSalary?=?Obj.NowSalary;??
????????this->WorkTime?=?Obj.WorkTime;??
????????return?*this;??
????}??
????Worker&?operator?=?(const?Worker&&?Obj)??
????{??
????????this->name?=?Obj.name;??
????????this->NowSalary?=?Obj.NowSalary;??
????????this->WorkTime?=?Obj.WorkTime;??
????????return?*this;??
????}??
????bool?operator?>?(const?Worker&?obj)?const??
????{??
????????return?this->NowSalary?/?this->WorkTime?>?obj.NowSalary?/?obj.WorkTime;??
????}??
????bool?operator?NowSalary?/?this->WorkTime???
class?Team??
{??
private:??
????Worker*?workers;??
????int?Pos;??
????int?MaxSalaryPerHour;??
????string?name;??
public:??
????Team()??
????{??
????????workers?=?new?Worker[N];??
????????Pos?=?0;??
????????MaxSalaryPerHour?=?0;??
????????name?=?"無";??
????}??
????void?Push(const?Worker&?Obj)??
????{??
????????if?(Pos?>=?N)??
????????{??
????????????throw?out_of_range("Over?Max?Range!");??
????????}??
????????workers[Pos]?=?Obj;??
????????Pos++;??
????}??
????void?Pop()??
????{??
????????if?(Pos?==?0)??
????????{??
????????????throw?out_of_range("Empty!");??
????????}??
????????Worker*?NewWorkers?=?new?Worker[--Pos];??
????????for?(int?i?=?0;?i???
????void?SearchMax()??
????{??
????????Worker?TheWorker;??
????????for?(int?i?=?0;?i??workers[i?+?1]???workers[i]?:?workers[i?+?1];??
????????}??
????????this->MaxSalaryPerHour?=?TheWorker.NowSalary?/?TheWorker.WorkTime;??
????????this->name?=?TheWorker.name;??
????????cout?<MaxSalaryPerHour?<name?<

主程序

#include???
using?namespace?std;??
#include?"Worker.hpp"??
#include???
??
Worker?Max(const?Worker&?var1,?const?Worker&?var2)??
{??
????return?var1?>?var2???var1?:?var2;??
}??
??
int?main()??
{??
????Team<4>?Obj1;??
????try??
????{??
????????Obj1.Push(Worker("張三",?19,?10));??
????????Obj1.Push(Worker("李四",?17,?12));??
????????Obj1.Push(Worker("王五",?10,?2));??
????????Obj1.Push(Worker("趙六",?19,?14));??
??
????????Obj1.template?SearchMax();??
????}??
????catch?(const?out_of_range&?exp)??
????{??
????????cout?<

為什么必須在父類中調(diào)用基類的成員來指定作用域或者使用this->?

代碼示例:

#include???
using?namespace?std;??
??
template???
class?Base??
{??
public:??
????void?exit()???
????{??
????????cout?<??
class?Father:?Base??
{??
public:??
????void?Foo()??
????{??
????????exit();??
????}??
};??
??
int?main()??
{??
????Father?Obj1;??
????Obj1.Foo();??
}??

操作結(jié)果:

我們看到這個(gè)程序中Father類對(duì)象Obj1的成員函數(shù)Foo并沒有調(diào)用繼承自Base類的exit函數(shù)。我們應(yīng)該像這樣更正這個(gè)程序(明確exit函數(shù)屬于哪里,也就是我們要調(diào)用exit函數(shù)的地方)。

代碼示例:

#include???
using?namespace?std;??
??
template???
class?Base??
{??
public:??
????void?exit()???
????{??
????????cout?<??
class?Father:?Base??
{??
public:??
????void?Foo()??
????{??
????????this->exit();?//?Base::exit()??
????}??
};??
??
int?main()??
{??
????Father?Obj1;??
????Obj1.Foo();??
}?

???????

與之前的程序相比,我們?cè)谕顺龊瘮?shù)中添加了 this->pointer/Base::scope 運(yùn)算符。使用其中之一(this->pointer 或 Base::scope 運(yùn)算符),編譯器可以確保退出函數(shù)不是從外部傳入,而是父類本身(this->pointer)/從基類繼承基礎(chǔ)(基礎(chǔ)::范圍運(yùn)算符)。

操作結(jié)果:

在《C++模板》一書中,有一段話講述了我上面所說的:

會(huì)員模板的優(yōu)點(diǎn)

我們有時(shí)會(huì)因?yàn)椤安煌愋偷淖远x Stacks 之間”無法相互賦值而感到惱火。為什么Stack類型對(duì)象不能調(diào)用Stack模板類中的overload=assignment運(yùn)算符給Stack類型對(duì)象賦值?

其實(shí)我們重載的=賦值運(yùn)算符是在模板類實(shí)例化(Stack)的時(shí)候使用的,確定了可以賦值的兩個(gè)對(duì)象的類類型:

主程序

#include?"Stack.hpp"??
#include???
using?namespace?std;??
??
int?main()??
{??
????Stack?Stack_Obj1(90);??
????Stack?Stack_Obj2;??
????Stack_Obj2?=?Stack_Obj1;??
}??

堆棧文件

#include???
using?namespace?std;??
#include???
??
template??>??
class?Stack??
{??
private:??
????CONT?element;??
public:??
????Stack()?=?default;??
????Stack(const?T&?obj);??
????Stack(const?Stack&?obj);??
??
????Stack&?operator?=?(const?Stack&?obj);??
????T&?operator?[]?(const?int&?order);??
};??
??
template??*/>??
T&?Stack::operator[](const?int&?order)??
{??
????return?this->element.at(order);??
}??
??
template??*/>??
Stack&?Stack::operator=(const?Stack&?obj)??
{??
????this->element.clear();??
????this->element.assign(obj.element.begin(),?obj.element.end());??
}??
??
template??*/>??
Stack::Stack(const?Stack&?obj)??
{??
????this->element.clear();??
????this->element.assign(obj.begin(),?obj.end());??
}??
??
template??*/>??
Stack::Stack(const?T&?obj)??
{??
????this->element.clear();??
????this->element.push_front(obj);??
}??

操作結(jié)果:

為什么會(huì)發(fā)生這種情況,請(qǐng)讓我詳細(xì)說明:

① 首先,我們使用 Stack 獲取實(shí)例化的模板。每個(gè)模板的賦值運(yùn)算符兩端的操作變量必須是變量類型;

②我們用“Stack_Obj1 = Stack_Obj2”來說明=賦值運(yùn)算符兩端的操作變量必須與Stack_Obj1變量的類型相同,即Stack類型;

③我們右邊的操作變量Stack_Obj2的操作類型是Stack類型的。編譯器一下子就糊涂了。我沒有=賦值運(yùn)算符可以同時(shí)操作兩種不同類型的變量相互賦值?那我就報(bào)錯(cuò)!

如何改進(jìn)它?這時(shí),成員模板的優(yōu)點(diǎn)就出來了:成員模板的主要優(yōu)點(diǎn)是“可以自由定義重載運(yùn)算符的操作對(duì)象,使一個(gè)運(yùn)算符可以同時(shí)操作兩種不同類型的變量。 ”

改進(jìn)的代碼(Stack.hpp):

#include???
using?namespace?std;??
#include???
??
template??>??
class?Stack??
{??
private:??
????CONT?element;??
public:??
????Stack()?=?default;??
????Stack(const?T&?obj);??
????Stack(const?Stack&?obj);??
??
????template???
????Stack&?operator?=?(const?Stack&?obj);??
??
????T&?operator?[]?(const?int&?order);??
????T&?Top();??
????void?Push(const?T&?obj);??
????void?Pop();??
????bool?empty();??
};??
??
template??*/>??
bool?Stack::empty()??
{??
????return?this->element.empty();??
}??
??
template??*/>??
void?Stack::Pop()??
{??
????if?(this->element.empty())??
????{??
????????throw?out_of_range("Empty!");??
????}??
????this->element.pop_front();??
}??
??
template??*/>??
void?Stack::Push(const?T&?obj)??
{??
????this->element.push_front(obj);??
}??
??
template??*/>??
T&?Stack::Top()??
{??
????if?(this->element.empty())??
????{??
????????throw?out_of_range("Empty!");??
????}??
????return?*(this->element.end()?-?1);??
}??
??
template???
template???
Stack&?Stack::operator=(const?Stack&?obj)??
{??
????if?((void*)this?!=?(void*)&obj)??
????{??
????????return?*this;??
????}??
??
????Stack?TempStack(obj);??
????this->element.clear();??
????while?(!TempStack.empty())??
????{??
????????this->element.push_front(TempStack.Top());??
????????TempStack.Pop();??
????}??
}??
??
template??*/>??
T&?Stack::operator[](const?int&?order)??
{??
????return?this->element.at(order);??
}??
??
??
template??*/>??
Stack::Stack(const?Stack&?obj)??
{??
????Stack?TempStack(obj);??
????this->element.clear();??
????while?(!TempStack.empty())??
????{??
????????this->element.push_front(TempStack.Top());??
????????TempStack.Pop();??
????}??
}??
??
template??*/>??
Stack::Stack(const?T&?obj)??
{??
????this->element.clear();??
????this->element.push_front(obj);??
}??

你可能會(huì)糊涂,沒關(guān)系,下面是Stack類的成員函數(shù)列表:

class?Stack??
{??
private:??
????CONT?element;??
public:??
????Stack()?=?default;??
????Stack(const?T&?obj);??
????Stack(const?Stack&?obj);??
??
????template???
????Stack&?operator?=?(const?Stack&?obj);??
??
????T&?operator?[]?(const?int&?order);??
????T&?Top();??
????void?Push(const?T&?obj);??
????void?Pop();??
????bool?empty();??
};??

我們知道,當(dāng)我們?cè)诔蓡T函數(shù)中傳入的參數(shù)是類對(duì)象時(shí),是不能通過類對(duì)象直接訪問該對(duì)象的私有成員數(shù)據(jù)的。我們只能通過類類型提供的外設(shè)接口以某種方式訪問??對(duì)象的數(shù)據(jù)。,為了不改變傳入的類對(duì)象的原有屬性,將傳入的類對(duì)象完全復(fù)制到我們要操作的類對(duì)象中,我們進(jìn)行如下操作:

① 清除我們要操作的類對(duì)象中的數(shù)據(jù);

②創(chuàng)建與傳入對(duì)象類型相同的臨時(shí)變量,在定義時(shí)調(diào)用復(fù)制構(gòu)造函數(shù)將參數(shù)數(shù)據(jù)復(fù)制到臨時(shí)對(duì)象中;

③看到我提供給大家的成員函數(shù)列表中,*顯眼的有兩個(gè)函數(shù)Top和Pop。我們可以使用while循環(huán)先訪問臨時(shí)對(duì)象的頂部元素,將元素push_front移入容器,然后Pop釋放它。丟棄棧頂元素,迭代直到臨時(shí)變量中的元素為空;

④ 當(dāng)談到“如何判斷臨時(shí)對(duì)象中的元素是否為空?”時(shí),Stack類中的empty成員函數(shù)可以幫到我們。

說實(shí)話,當(dāng)我第一次遇到Stack自定義類的時(shí)候,我也納悶為什么不直接操作Stack的成員數(shù)據(jù)呢?Stack自定義類類型的成員數(shù)據(jù)的訪問權(quán)限設(shè)置為public不好嗎?事實(shí)上,這是反過來的。我們希望該程序僅以我們想要的方式運(yùn)行。我們可以對(duì)STL容器進(jìn)行處理,利用精華構(gòu)造出我們想要的“新容器”,但我們*關(guān)注的是“安全、安全、安全!” 只有經(jīng)過封裝,我們要提供的外設(shè)接口才暴露給操作者,才能保證程序的絕對(duì)安全!

模板專業(yè)化

其實(shí)模板特化就是我們常說的重載,但是我們這里的重載只是模板的類型參數(shù)列表不同,*重要的一點(diǎn)是“模板特化是針對(duì)類類型的”,函數(shù)模板沒有這個(gè)特征:

應(yīng)用于函數(shù)模板時(shí),編譯器報(bào)錯(cuò)!

模板全專業(yè)化

一個(gè)模板稱為全特化條件:1.必須有一個(gè)主模板類2.模板類型是完全指定的。

代碼示例:

#include???
using?namespace?std;??
??
template???
class?Base??
{??
public:??
????void?ShowInf()??
????{??
????????cout?<??
class?Base???
{??
public:??
????void?ShowInf()??
????{??
????????cout?<?Obj;??
????Obj.ShowInf();??
}??

操作結(jié)果:

模板偏特化

偏特化是介于兩者之間的模板。它的模板名稱與主版本模板的名稱相同。但是,在其模板類型中,有明確的部分和未明確的部分。

注意:部分特化的條件:1.必須有主模板,2.模板類型部分明確。

類型參數(shù)為指針時(shí)模板的部分特化

代碼示例:

#include???
using?namespace?std;??
??
template???
class?Base??
{??
public:??
????void?ShowInf()??
????{??
????????cout?<??// 如果模板實(shí)例化參數(shù)T為指針類型,則調(diào)用該模板進(jìn)行實(shí)例化操作
class?Base???
{??
public:??
????void?ShowInf()??
????{??
????????cout?<?Obj;??
????Obj.ShowInf();??
}??

操作結(jié)果:

類型參數(shù)部分實(shí)例化期間的部分模板特化

代碼示例:

#include???
using?namespace?std;??
??
template???
class?Base??
{??
public:??
????void?ShowInf()??
????{??
????????cout?<??
class?Base???
{??
public:??
????void?ShowInf()??
????{??
????????cout?<?Obj;??
????Obj.ShowInf();??
}??

操作結(jié)果:

當(dāng)兩個(gè)類型參數(shù) T1 和 T2 相同時(shí)模板的部分特化

代碼示例:

#include???
using?namespace?std;??
??
template???
class?Base??
{??
public:??
????void?ShowInf()??
????{??
????????cout?<??
class?Base???
{??
public:??
????void?ShowInf()??
????{??
????????cout?<?Obj;??
????Obj.ShowInf();??
}??

操作結(jié)果:

模板實(shí)例化時(shí),模板的全特化和模板的部分特化適用于調(diào)用序列:

注意:類類型一旦聲明為模板,就不能有同名的普通類的版本,即類模板和同名的普通類不能共存!

優(yōu)先級(jí):全專班>半專班>大師版模板班

代碼示例:

#include???
using?namespace?std;??
??
template???
class?Base??
{??
public:??
????void?ShowInf()??
????{??
????????cout?<??
class?Base??
{??
public:??
????void?ShowInf()??
????{??
????????cout?<??
class?Base???
{??
public:??
????void?ShowInf()??
????{??
????????cout?<?Obj;??
????Obj.ShowInf();??
}??

操作結(jié)果:

函數(shù)模板的重載(類似于類模板的特化)

代碼示例:

#include???
using?namespace?std;??
??
template???
void?ShowInf(T?obj)??
{??
????cout?<??
void?ShowInf(int?obj)??
{??
????cout?<

操作結(jié)果:

從這個(gè)例子可以看出,當(dāng)函數(shù)的普通版本和函數(shù)模板的專用版本都滿足要求時(shí),調(diào)用順序如下:

優(yōu)先順序:普通功能版>功能模板專業(yè)版>功能模板主版

模板“模板參數(shù)”

為什么需要模板的“模板參數(shù)”?

*重要的原因是“方便”!怎么方便?我們以 Stack 為例。如果我們想允許容器存儲(chǔ)指定的 Stack 元素,我們這樣做:

template?>???
class?Stack?{??
private:??
??Cont?elems;?//?elements??
??......??
};??

當(dāng)我們實(shí)例化一個(gè) Stack 類的對(duì)象時(shí),我們通常會(huì)這樣做:

Stack>?dblStack;??

但是這樣做的缺點(diǎn)是需要指定兩次元素類型,但是這兩種類型是一樣的。

使用模板模板參數(shù)允許我們?cè)诼暶?Stack 類模板時(shí)只指定容器的類型,而不指定容器中元素的類型。例如:

template??class?Cont?=?std::deque>??
class?Stack?{??
private:??
??Cont?elems;?//?elements??
public:??
??void?push(T?const?&);?//?push?element??
??void?pop();???????????//?pop?element??
??T?const?&top()?const;?//?return?top?element??
??bool?empty()?const?{??//?return?whether?the?stack?is?empty??
????return?elems.empty();??
??}??
??...??
};??

此時(shí),當(dāng)我們實(shí)例化 Stack 模板時(shí),我們執(zhí)行以下操作:

Stack?vStack;??????//?integer?stack?that?uses?a?vector??

與第一種方法的區(qū)別在于:第二個(gè)模板參數(shù)是一個(gè)類模板。

在這一點(diǎn)上,一切看起來都那么順利,真的嗎?

例如:

#include???
using?namespace?std;??
#include???
??
template??class?CONT?>??
class?Base??
{??
??
};??
??
int?main()??
{??
????Base?obj;??
}??

操作結(jié)果:

錯(cuò)誤原因:

其實(shí)參數(shù)不匹配是有原因的,我們傳入的參數(shù)是錯(cuò)誤的,為什么?讓我們回想一下:STL 標(biāo)準(zhǔn)容器類型實(shí)際上是一種模板類型。實(shí)例化一個(gè)STL容器的時(shí)候,通常是一個(gè)vector,但是vector容器里面其實(shí)有兩個(gè)參數(shù)。第二個(gè)參數(shù)是“容器空間配置器分配器”。為了完全匹配vector模板類的類型,我們做如下調(diào)整:

#include???
using?namespace?std;??
#include???
??
template??>?class?CONT?>??
class?Base??
{??
??
};??
??
int?main()??
{??
????Base?obj;??
}??

在這種情況下,程序運(yùn)行完全正常。

將字符串傳遞給模板的注意事項(xiàng)

有人問為什么錯(cuò)了?我們知道,適用字符數(shù)組的大小比較應(yīng)該遵循“字符數(shù)組中元素個(gè)數(shù)相同”的原則。這里的“apple”參數(shù)推導(dǎo)出的T是const char[6]類型(隱含'