templates c with examples
Lær de forskjellige aspektene av maler i C ++.
Maler er en av de kraftigste funksjonene i C ++. Maler gir oss koden som er uavhengig av datatypen.
Med andre ord, ved hjelp av maler, kan vi skrive en generisk kode som fungerer på hvilken som helst datatype. Vi trenger bare å sende datatypen som en parameter. Denne parameteren som passerer datatypen kalles også et typenavn.
I denne opplæringen vil vi utforske alt om maler og dets forskjellige aspekter i detalj.
=> Klikk her for den absolutte C ++ treningsserien.
forskjellige typer testing i qa
Hva du vil lære:
- Hva er maler?
- Hvordan bruke maler / implementering?
- typename Vs. klasse nøkkelord
- Mal Instantiering og spesialisering
- Mal spesialisering
- C ++ variabelmaler
- Konklusjon
- Anbefalt lesing
Hva er maler?
Som nevnt ovenfor er maler generiske, dvs. uavhengige av datatypen. Maler brukes hovedsakelig for å sikre gjenbrukbarhet og fleksibilitet i programmene. Vi kan bare lage en enkel funksjon eller en klasse som tar datatypen som en parameter og implementerer koden som fungerer for enhver datatype.
For eksempel, hvis vi vil at en sorteringsalgoritme skal fungere for alle numeriske datatyper samt tegnstrenger, så vil vi bare skrive en funksjon som tar datatypen som et argument og implementere sorteringsteknikken.
Avhengig av datatypen (typenavn) som sendes til sorteringsalgoritmen, kan vi deretter sortere dataene uavhengig av datatypen. På denne måten trenger vi ikke skrive ti algoritmer for ti datatyper.
Dermed kan maler brukes i applikasjoner der vi krever at koden skal kunne brukes for mer enn én datatype. Maler brukes også i applikasjoner der gjenbrukbarhet er av største betydning.
Hvordan bruke maler / implementering?
Maler kan implementeres på to måter:
- Som en funksjonsmal
- Som klassemall
Funksjonsmal
Funksjonsmal er akkurat som en normal funksjon, men den eneste forskjellen er at normal funksjon bare kan fungere på en datatype og en funksjonsmalkode kan fungere på flere datatyper.
Selv om vi faktisk kan overbelaste en normal funksjon for å jobbe med forskjellige datatyper, er funksjonsmaler alltid mer nyttige ettersom vi må skrive det eneste programmet, og det kan fungere på alle datatyper.
Deretter vil vi se implementeringen av funksjonsmaler.
Den generelle syntaksen til funksjonsmalen er:
template T function_name(T args){ …… //function body }
Her er T malargumentet som godtar forskjellige datatyper og klasse er et nøkkelord. I stedet for nøkkelordklassen kan vi også skrive ‘typename’.
Når en bestemt datatype overføres til funksjonsnavn, lages en kopi av denne funksjonen av kompilatoren med denne datatypen som argument og funksjon utføres.
La oss se et eksempel for bedre å forstå funksjonsmaler.
#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<Klassemaler Som i funksjonsmaler, kan vi ha et krav om å ha en klasse som ligner på alle andre aspekter, men bare forskjellige datatyper.
I denne situasjonen kan vi ha forskjellige klasser for forskjellige datatyper eller ulik implementering for forskjellige datatyper i samme klasse. Men å gjøre dette vil gjøre koden vår klumpete.
Den beste løsningen for dette er å bruke en malklasse. Malklasse oppfører seg også som funksjonsmaler. Vi må overføre datatypen som en parameter til klassen mens vi oppretter objekter eller ringer til medlemsfunksjoner.
Den generelle syntaksen for klassemalen er:
template class className{ ….. public: T memVar; T memFunction(T args); };
I definisjonen ovenfor fungerer T som en plassholder for datatypen. Offentlige medlemmers memVar og memFunction bruker også T som plassholder for datatyper.
Når en malklasse er definert som ovenfor, kan vi opprette klasseobjekter som følger:
className classObejct1; className classObject2; className classObject3;
La oss implementere et kodeeksempel for å demonstrere klassemaler:
#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 = '< Produksjon:
Maksimum 100 og 75 = 100
Maksimum ‘A’ og ‘a’ = a
Ovennevnte program implementerer et eksempel på en klassemal. Vi har malklassen myclass. Inne i dette har vi en konstruktør som vil initialisere de to medlemmene a og b i klassen. Det er en annen medlemsfunksjon getMaxval som også er en funksjonsmal som maksimalt returnerer a og b.
I hovedfunksjonen konstruerer vi to objekter, myobject of type integer og mychobject of type character. Deretter kaller vi getMaxval-funksjonen på hvert av disse objektene for å bestemme maksimal verdi.
Merk at bortsett fra maltypeparametere (parametere av type T), kan malfunksjoner også ha vanlige parametere som normale funksjoner og også standardparameterverdier.
typename Vs. klasse nøkkelord
Mens vi deklarerer malklasse eller funksjon, bruker vi ett av de to nøkkelordene klasse eller typenavn. Disse to ordene er semantisk ekvivalente og kan brukes om hverandre.
Men i noen tilfeller kan vi ikke bruke disse ordene som likeverdige. For eksempel, når vi bruker avhengige datatyper i maler som “typedef”, bruker vi typenavn i stedet for klasse.
Klassens nøkkelord må også brukes når vi eksplisitt må instansere en mal.
Mal Instantiering og spesialisering
Malene er skrevet på en generisk måte, noe som betyr at det er en generell implementering uavhengig av datatype. I henhold til datatypen som er gitt, må vi generere en konkret klasse for hver datatype.
For eksempel, hvis vi har en mal-sorteringsalgoritme, kan vi generere en konkret klasse for sortering, en annen klasse for sortering osv. Dette kalles instantiering av malen.
Vi erstatter malargumentene (faktiske datatyper) for malparametrene i definisjonen av malklassen.
For eksempel,
template class sort {};
Når vi passerer datatype, erstatter kompilatoren datatypen med ‘T’ slik at sorteringsalgoritmen blir sortert.
Hver gang vi bruker malklasse eller -funksjon, er det behov for en forekomst når vi passerer en bestemt datatype. Hvis denne forekomsten ikke allerede er tilstede, oppretter kompilatoren en med den spesifikke datatypen. Dette er den implisitte instantiasjonen.
En ulempe ved implisitt instantiering er at kompilatoren genererer forekomstklasse bare for argumentene som brukes for øyeblikket. Dette betyr at hvis vi ønsker å generere et bibliotek med forekomster før bruken av disse forekomster, må vi gå til eksplisitt instantiering.
Et eksempel på malerklæring er gitt nedenfor:
template class Array(T)
Kan eksplisitt instanseres som:
template class Array
Når en klasse blir instantiert, blir alle dens medlemmer også instantiert.
Mal spesialisering
Når vi programmerer ved hjelp av maler, kan vi komme overfor en situasjon slik at vi kan kreve en spesiell implementering for en bestemt datatype. Når en slik situasjon oppstår, går vi for malspesialisering.
I mal-spesialisering implementerer vi en spesiell oppførsel for en bestemt datatype bortsett fra den opprinnelige maldefinisjonen for de andre datatypene.
For eksempel, vurdere at vi har en malklasse ‘ myIncrement ’ som har en konstruktør til å initialisere en verdi og en malfunksjon toIncrement som øker verdien med 1.
Denne spesielle klassen fungerer perfekt for alle datatypene bortsett fra røye. I stedet for å øke verdien for røye, hvorfor ikke gi den en spesiell oppførsel og konvertere tegnet til store bokstaver i stedet?
For å gjøre dette, kan vi gå til malspesialisering for char-datatypen.
Denne implementeringen er vist i nedenstående kodeeksempel.
#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: '< Produksjon:
Inkrementert int-verdi: 8
Stor bokstav: S
Inkrementert dobbel verdi: 12

I det ovennevnte programmet som viser mal-spesialisering, se hvordan vi har erklært en spesialmal for røyetype. Vi erklærer først den opprinnelige klassen, og deretter 'spesialiserer vi' den for røyetype. For å begynne spesialisering bruker vi tom malerklæring “mal”.
Så etter kursnavnet inkluderer vi datatypen. Etter disse to endringene er klassen skrevet for røyetypen.
Vær oppmerksom på at det ikke er noen forskjell mellom instantiering av røyetype og andre typer i hovedfunksjonen. Den eneste forskjellen er at vi omdefinerer den spesialiserte klassen.
Merk at vi må definere alle medlemmene i den spesialiserte klassen, selv om de er nøyaktig de samme i generisk / original malklassen. Dette er fordi vi ikke har arvfunksjon for medlemmer fra den generiske malen til den spesialiserte malen.
C ++ variabelmaler
Så langt har vi sett funksjonsmaler som tar et fast antall argumenter. Det er også maler som tar et variabelt antall argumenter. Disse funksjonsmalene kalles variadiske maler. Variadiske maler er en av de nyeste funksjonene i C ++ 11.
Variadiske maler tar et variabelt antall argumenter som er typesikre, og argumentene løses på kompileringstidspunktet.
La oss ta et komplett programmeringseksempel for å forstå dette.
#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 = '< Ovennevnte eksempel viser variadisk funksjon, “summering”. Som vist ovenfor trenger vi først en basefunksjon som implementerer basissaken. Deretter implementerer vi den variatiske funksjonen på toppen av denne funksjonen.
I summeringsvariabelen for variabel funksjon kalles “typename… args” malparameterpakke mens 'Args ... args' kalles funksjonsparameterpakke .
Etter å ha skrevet en funksjonsmal som implementerer basissaken, skriver vi en variabel funksjon som implementerer den generelle saken. Den varadiske funksjonen er skrevet på samme måte som rekursjonen som vist for summering (args ...). Det første argumentet er skilt fra funksjonsparameterpakken til type T (første).
For hver oppfordring til summering blir parameterlisten smalere av ett argument, og til slutt blir grunntilstanden nådd. Utgangen viser summeringen for lange heltall og tegn.
Konklusjon
Med dette avslutter vi denne opplæringen om maler i C ++. Maler hjelper oss med å gjøre programmene våre generiske, dvs. uavhengige av typen.
Les også = >> Opplæring i kolmemal
Generiske programmer står alltid på toppen av de andre programmene, ettersom vi ikke trenger å skrive separate programmer for hver datatype. Dermed kan utvikling av generiske typesikre programmer være et viktig skritt mot effektiv programmering.
=> Sjekk In-Depth C ++ Training Tutorials Here.
Anbefalt lesing
- Python hovedveiledning med praktiske eksempler
- Hvordan datadrevet testing fungerer (eksempler på QTP og selen)
- Multitrading i C ++ med eksempler
- Python DateTime Tutorial med eksempler
- Eksempel på prøvesaksmal med eksempler på prøvesaker (Last ned)
- Klipp kommandoen i Unix med eksempler
- Eksempelmal for akseptrapport med eksempler
- Unix Cat Command Syntax, Alternativer med eksempler