templates c with examples
Lär dig de olika aspekterna av mallar i C ++.
Mallar är en av de mest kraftfulla funktionerna i C ++. Mallar ger oss koden som är oberoende av datatypen.
Med andra ord, med hjälp av mallar kan vi skriva en generisk kod som fungerar på vilken datatyp som helst. Vi behöver bara skicka datatypen som en parameter. Denna parameter som passerar datatypen kallas också ett typnamn.
I denna handledning kommer vi att utforska allt om mallar och dess olika aspekter i detalj.
=> Klicka här för den absoluta C ++ träningsserien.
Vad du kommer att lära dig:
- Vad är mallar?
- Hur använder jag mallar / implementering?
- typnamn Vs. klassnyckelord
- Mallinstantiering och specialisering
- Mall specialisering
- C ++ variabla mallar
- Slutsats
- Rekommenderad läsning
Vad är mallar?
Som nämnts ovan är mallar generiska, dvs. oberoende av datatypen. Mallar används främst för att säkerställa kodåteranvändbarhet och flexibilitet i programmen. Vi kan bara skapa en enkel funktion eller en klass som tar datatypen som en parameter och implementerar koden som fungerar för alla datatyper.
Till exempel, om vi vill att en sorteringsalgoritm ska fungera för alla numeriska datatyper samt teckensträngar, så skriver vi bara en funktion som tar datatypen som ett argument och implementerar sorteringstekniken.
Beroende på datatyp (typnamn) som skickas till sorteringsalgoritmen kan vi sedan sortera data oavsett datatyp. På det här sättet behöver vi inte skriva tio algoritmer för tio datatyper.
bästa underhållsprogramvara för Windows 10
Således kan mallar användas i applikationer där vi kräver att koden ska kunna användas för mer än en datatyp. Mallar används också i applikationer där kodåteranvändbarhet är av största vikt.
Hur använder jag mallar / implementering?
Mallar kan implementeras på två sätt:
- Som en funktionsmall
- Som en klassmall
Funktionsmall
Funktionsmall är precis som en normal funktion, men den enda skillnaden är att normal funktion bara kan fungera på en datatyp och en funktionsmallkod kan fungera på flera datatyper.
Medan vi faktiskt kan överbelasta en normal funktion för att arbeta med olika datatyper, är funktionsmallar alltid mer användbara eftersom vi måste skriva det enda programmet och det kan fungera på alla datatyper.
Därefter ser vi implementeringen av funktionsmallar.
Den allmänna syntaxen för funktionsmallen är:
template T function_name(T args){ …… //function body }
Här är T mallargumentet som accepterar olika datatyper och klass är ett nyckelord. Istället för nyckelordsklassen kan vi också skriva 'typnamn'.
När en viss datatyp skickas till funktionsnamn görs en kopia av denna funktion av kompilatorn med denna datatyp som argument och funktion körs.
Låt oss se ett exempel för att bättre förstå funktionsmallar.
#include using namespace std; template void func_swap(T &arg1, T &arg2) { T temp; temp = arg1; arg1 = arg2; arg2 = temp; } int main() { int num1 = 10, num2 = 20; double d1 = 100.53, d2 = 435.54; char ch1 = 'A', ch2 = 'Z'; cout << 'Original data
'; cout << 'num1 = ' << num1 << ' num2 = ' << num2< I huvudfunktionen definierar vi data av typen int, dubbel och char. Vi kallar funktion func_swap med varje typ av data. Sedan visar vi de bytte data för varje datatyp.
Således visar detta att vi inte behöver skriva tre funktioner för tre datatyper. Det räcker att bara skriva en funktion och göra den till en mallfunktion så att den är oberoende av datatypen.
Klassmallar
Liksom i funktionsmallar kan vi ha ett krav på att ha en klass som liknar alla andra aspekter men bara olika datatyper.
I den här situationen kan vi ha olika klasser för olika datatyper eller olika implementeringar för olika datatyper i samma klass. Men att göra detta kommer att göra vår kod skrymmande.
Den bästa lösningen för detta är att använda en mallklass. Mallklassen beter sig också som funktionsmallar. Vi måste skicka datatyp som en parameter till klassen medan vi skapar objekt eller anropar medlemsfunktioner.
Den allmänna syntaxen för klassmallen är:
template class className{ ….. public: T memVar; T memFunction(T args); };
I ovanstående definition fungerar T som en platshållare för datatypen. De offentliga medlemmarnas memVar och memFunction använder också T som platshållare för datatyper.
När en mallklass har definierats som ovan kan vi skapa klassobjekt enligt följande:
className classObejct1; className classObject2; className classObject3;
Låt oss implementera ett kodexempel för att visa klassmallar:
#include using namespace std; template class myclass { T a, b; public: myclass (T first, T second) {a=first; b=second;} T getMaxval (); }; template T myclass::getMaxval () { return (a>b? a : b); } int main () { myclass myobject (100, 75); cout<<'Maximum of 100 and 75 = '< Produktion:
Maximalt 100 och 75 = 100
Maximalt “A” och “a” = a
Ovanstående program implementerar ett exempel på en klassmall. Vi har mallklassen myclass. Inuti detta har vi en konstruktör som initialiserar de två medlemmarna a och b i klassen. Det finns en annan medlemsfunktion getMaxval som också är en funktionsmall som returnerar maximalt a och b.
I huvudfunktionen konstruerar vi två objekt, myobject av typen heltal och mychobject av typtecken. Sedan kallar vi getMaxval-funktionen på vart och ett av dessa objekt för att bestämma maximalt värde.
Observera att förutom malltypsparametrar (parametrar av typ T) kan mallfunktioner också ha vanliga parametrar som normala funktioner och även standardparametervärden.
typnamn Vs. klassnyckelord
När vi förklarar mallklass eller funktion använder vi ett av de två nyckelordsklassen eller typnamnet. Dessa två ord är semantiskt ekvivalenta och kan användas omväxlande.
Men i vissa fall kan vi inte använda dessa ord som likvärdiga. Till exempel, när vi använder beroende datatyper i mallar som “typedef” använder vi typnamn istället för klass.
Dessutom måste klassnyckelordet användas när vi uttryckligen måste initiera en mall.
Mallinstantiering och specialisering
Mallarna är skrivna på ett generiskt sätt, vilket innebär att det är en allmän implementering oavsett datatyp. Enligt den angivna datatypen måste vi skapa en konkret klass för varje datatyp.
Till exempel, om vi har en mallsorteringsalgoritm kan vi generera en konkret klass för sortering, en annan klass för sortering etc. Detta kallas instantiering av mallen.
Vi ersätter mallargumenten (faktiska datatyper) för mallparametrarna i definitionen av mallklassen.
Till exempel,
template class sort {};
När vi skickar datatyp ersätter kompilatorn datatypen med 'T' så att sorteringsalgoritmen blir sorterad.
Varje gång vi använder mallklass eller funktion finns det ett behov av en instans när vi skickar en viss datatyp. Om denna instans inte redan finns skapar kompilatorn en med den specifika datatypen. Detta är den implicita instantieringen.
En nackdel med implicit instantiering är att kompilatorn genererar instansklass endast för de argument som används för närvarande. Detta innebär att om vi vill skapa ett bibliotek med instanser före användningen av dessa instanser, måste vi gå till uttrycklig instantiering.
Ett exempel på malldeklaration ges nedan:
template class Array(T)
Kan uttryckligen instansieras som:
template class Array
När en klass instansieras instiftas också alla dess medlemmar.
Mall specialisering
När vi programmerar med mallar kan vi komma att ställas inför en sådan situation att vi kan kräva en speciell implementering för en viss datatyp. När en sådan situation inträffar går vi till mallspecialisering.
I mallspecialisering implementerar vi ett speciellt beteende för en viss datatyp bortsett från den ursprungliga maldefinitionen för de andra datatyperna.
Till exempel, anser att vi har en mallklass ” myIncrement ' som har en konstruktör för att initiera ett värde och en mallfunktion toIncrement som ökar värdet med 1.
Den här klassen fungerar perfekt för alla datatyper utom för char. Istället för att öka värdet för char, varför inte ge det ett speciellt beteende och konvertera tecknet till versaler istället?
För att göra detta kan vi gå till mallspecialisering för char-datatypen.
Denna implementering visas i nedanstående kodexempel.
#include using namespace std; // class template: template class myIncrement { T value; public: myIncrement (T arg) {value=arg;} T toIncrement () {return ++value;} }; // class template specialization: template class myIncrement { char value; public: myIncrement (char arg) {value=arg;} char uppercase () { if ((value>='a')&&(value<='z')) value+='A'-'a'; return value; } }; int main () { myIncrement myint (7); myIncrement mychar ('s'); myIncrement mydouble(11.0); cout<<'Incremented int value: '<< myint.toIncrement()<< endl; cout<<'Uppercase value: '< Produktion:
Inkrementerat int-värde: 8
Versaler: S
Inkrementerat dubbelt värde: 12

I det ovanstående programmet som visar mallspecialisering, se hur vi har förklarat en specialmall för char-typ. Vi förklarar först den ursprungliga klassen och sedan specialiserar vi den för rödingstyp. För att påbörja specialiseringen använder vi tom malldeklaration ”mall”.
Sedan inkluderar vi datatypen efter klassnamnet. Efter dessa två ändringar skrivs klassen för char-typen.
Observera att det i huvudfunktionen inte finns någon skillnad mellan instantiering av char-typ och andra typer. Den enda skillnaden är att vi omdefinierar specialklassen.
Observera att vi måste definiera alla medlemmar i den specialiserade klassen även om de är exakt desamma i generisk / original mallklassen. Detta beror på att vi inte har arvfunktion för medlemmar från den generiska mallen till den specialmallen.
C ++ variabla mallar
Hittills har vi sett funktionsmallar som tar ett fast antal argument. Det finns också mallar som tar ett varierande antal argument. Dessa funktionsmallar kallas variabla mallar. Variadiska mallar är en av de senaste funktionerna i C ++ 11.
Variadiska mallar tar ett variabelt antal argument som är typsäkra och argumenten löses vid sammanställningstid.
Låt oss ta ett komplett programmeringsexempel för att förstå detta.
#include #include using namespace std; template T summation(T val) { return val; } template T summation(T first, Args... args) { return first + summation(args...); } int main() { long sum = summation(1, 2, 3, 8, 7); cout<<'Sum of long numbers = '< Ovanstående exempel visar variadisk funktion, 'summering'. Som visas ovan behöver vi först en basfunktion som implementerar basfodralet. Sedan implementerar vi den variadiska funktionen på toppen av den här funktionen.
I den summerade variabelfunktionen kallas 'typnamn ... args' mallparameterpaket medan 'Args ... args' kallas funktionsparameterpaket .
Efter att ha skrivit en funktionsmall som implementerar basfallet skriver vi en variadisk funktion som implementerar det allmänna fallet. Den variadiska funktionen skrivs på samma sätt som rekursionen som visas för summering (args ...). Det första argumentet separeras från funktionsparameterpaketet till typ T (första).
För varje samtal till summering blir parameterlistan smalare med ett argument och så småningom uppnås basvillkoret. Utgången visar summeringen för långa heltal och tecken.
Slutsats
Med detta avslutar vi den här guiden om mallar i C ++. Mallar hjälper oss att göra våra program generiska, dvs. oberoende av typ.
Läs också = >> Kolvmallhandledning
Generiska program står alltid ovanpå de andra programmen eftersom vi inte behöver skriva separata program för varje datatyp. Således kan utveckling av generiska typsäkra program vara ett viktigt steg mot effektiv programmering.
=> Kontrollera de fördjupade C ++ -utbildningsövningarna här.
Rekommenderad läsning
- Pythons huvudfunktionshandledning med praktiska exempel
- Hur datadriven testning fungerar (exempel på QTP och selen)
- Multitrådning i C ++ med exempel
- Python DateTime-handledning med exempel
- Exempel på testfallsmall med testfallsexempel (Ladda ner)
- Klipp kommandot i Unix med exempel
- Exempelmall för godkännandeprovrapport med exempel
- Unix Cat Command Syntax, alternativ med exempel