Șablon (programare)
În programarea calculatoarelor, șabloanele sunt o caracteristică a limbajului de programare C++ ce permit scrierea de cod fără a lua în considerare tipul de dată ce va fi utilizat până la urmă. Șabloanele permit programare generică în C++.
Șabloanele sunt foarte utile programatorilor în C++, mai ales când sunt combinate cu tehnica moștenirilor multiple și a supraîncărcării operatorilor. Biblioteca Standard de Șabloane (STL) a limbajului C++ aduce multe funcții utile într-un cadru de șabloane conectate.
Sinteză tehnică
modificareExistă două feluri de șabloane. Un șablon funcție se comportă ca o funcție ce poate accepta argumente de tipuri foarte diferite. De exemplu, Biblioteca Standard de Șabloane a limbajului C++ conține șablonul funcție max(x, y)
ce returnează x sau y, pe cel mai mare dintre cele două argumente. max()
ar putea fi declarat cam așa:
template <class a>
a max(a x, a y)
{
if (x < y)
return y;
else
return x;
}
Acest șablon poate fi apelat într-un mod identic cu apelul de funcție:
cout << max(3, 7); // afișează 7
Prin examinarea argumentelor, compilatorul deduce că acesta este un apel la max(int, int)
și produce (în engleză "instantiates") o versiune a funcției în care tipul a
devine int
.
Acest procedeu este valid pentru toate cazurile în care argumentele x
și y
sunt de tip întreg, șir de caractere, sau de orice alt tip pentru care expresia "x < y
" are sens. În cazul în care v-ați definit propriul tip de dată, puteți folosi supraîncărcarea operatorilor pentru a defini înțelesul lui <
pentru tipul ales, dând astfel voie să folosiți funcția max()
. În acest mic exemplu, asta poate să apară ca fiind un câștig nesemnificativ, dar în contextul unei biblioteci cuprinzătoare ca STL-ul această caracteristică dă posibilitatea programatorului să obțină o funcționalitate extinsă pentru un nou tip de dată, chiar prin definirea a numai câtorva operatori pentru acest tip. Doar definind <
se creează posibilitatea folosirii unui tip cu algoritmi standard ca sort()
, stable_sort()
, și binary_search()
; în structuri de date cum ar fi set
-urile, heap-urile, și vectorii asociativi; și tot așa.
Drept contraexemplu , tipul standard complex
nu definește operatorul <
, pentru că nu există o ordine strictă pe numerele complexe. Astfel, max(x, y)
va genera o eroare la compilare dacă x și y sunt valori de tip complex
. Tot așa, alte șabloane care se bazează pe <
nu pot fi aplicate la date de tip complex
. Din nefericire, compilatoarele generează de ceva vreme mesaje de eroare oarecum criptice și nefolositoare în cazul acestui tip de eroare. Dacă se are în vedere ca un anumit obiect să adere la o metodă protocolară se poate trece peste acest impediment.
Un șablon clasă extinde același concept peste clase. Șabloanele clasă sunt folosite de obicei pentru a face containere generice. De exemplu, biblioteca STL are un container de tip listă înlănțuită. Pentru a face o listă înlănțuită de întregi, se va scrie list<int>
. O listă de șiruri de caractere este notată list<string>
. O list
ă are un set de funcții standard asociate, ce funcționează indiferent ce vei pune între paranteze.
Avantaje și dezavantaje
modificare
Câteva utilizări ale șabloanelor, cum ar fi funcția max()
, au fost mai devreme suplinite de către preprocesor prin intermediul macrourilor. De exemplu, iată un cod macro pentru max()
:
#define max(a,b) ((a) < (b) ? (b) : (a))
Macrourile și șabloanele sunt amândouă translatate în timpul compilării. Codul unui macro este întotdeauna inserat în program în locul unde apare un apel către acesta; pe când șabloanele sunt tratate ca funcții, deși compilatorul poate decide să insereze pe loc cod în loc de un apel de funcție, dacă consideră acest lucru oportun. Astfel macroinstrucțiunile și șabloanele funcție nu constituie o corvoadă în plus la momentrul execuției.
În orice caz, șabloanele sunt în general considerate ca fiind o îmbunătățire a macrourilor pentru aceste utilizări. Șabloanele sunt sigure din punctul de vedere al coerenței tipului de dată utilizată. Șabloanele ocolesc câteva din erorile frecvent întâlnite în cod ce abuzează de macroinstrucțiuni. Poate e lucrul cel mai important, șabloanele au fost gândite ca să aibă o aplicabilitate mult mai mare decât macrourile.
Există trei mari inconveniente întâlnite la utilizarea șabloanelor. În primul rând, foarte multe compilatoare au avut un suport limitat pentru șabloane, astfel încât utilizarea șabloanelor poate determina scăderea portabilității codului sursă. În al doilea rând, aproape toate compilatoarele produc mesaje de eroare neproductive și derutante când sunt detectate erori în codul șablonului. Aceasta poate face ca șabloanele să fie greu de programat. În al treilea rând, fiecare utilizare a unui șablon poate determina generarea de către compilator a unei noi versiuni de cod pentru noua instanță a șablonului, deci utilizarea fără discernământ a șabloanelor poate duce la încărcarea codului, rezultând executabile excesiv de mari.
Caracteristici de programare generică în alte limbaje
modificareȘabloanele au fost lăsate în afara unor limbaje bazate pe C++, cum ar fi Java și C# 1.0, în primul rând din cauza problemelor cu șabloanele în C++. Aceste limbaje au adoptat alte metode de a face față acelorași probleme. Adoptarea de către Java a genericelor emulează comportarea șabloanelor, dar este ceva foarte diferit din punct de vedere tehnic. C# a adăugat generice (tipuri parametrizate) în .NET 2.0.
Genericele în limbajul Ada datează dinaintea șabloanelor.
Bibliografie
modificare- Doina Logofătu: Algoritmi fundamentali in C++. Aplicații, Ed. 1, Editura Polirom, Iași, 2007, ISBN 9734600939.