قالب در ++C — راهنمای جامع

۱۳۰۹ بازدید
آخرین به‌روزرسانی: ۰۳ مهر ۱۴۰۲
زمان مطالعه: ۶ دقیقه
قالب در ++C — راهنمای جامع

در این راهنما در مورد مفهوم قالب در ++C صحبت می‌کنیم. به این ترتیب با قدرت قالب‌ها برای برنامه‌نویسی ژنریک آشنا خواهید شد. اگر مایل هستید بخش قبلی این سری مقالات راهنمای جامع زبان برنامه‌نویسی ++C را مطالعه کنید، روی لینک زیر کلیک کنید:

قالب‌ها یکی از قدرتمندترین قابلیت‌های زبان ++C محسوب می‌شوند که به شما امکان می‌دهند برنامه‌های ژنریک بنویسید. به بیان ساده می‌توانید یک تابع یا کلاس منفرد ایجاد کنید که با بهره‌گیری از قالب‌ها با انواع داده مختلف کار می‌کند. قالب‌ها عموماً در کدبیس های بزرگ و به منظور ایجاد قابلیت استفاده مجدد از کد و افزایش انعطاف‌پذیری برنامه‌ها مورد استفاده قرار می‌گیرند.

مفهوم قالب را می‌توان به دو روش استفاده کرد:

  • قالب تابع
  • قالب کلاس

قالب تابع

قالب تابع همانند تابع معمولی عمل می‌کند، اما یک تفاوت کلیدی دارد. یک قالب تابع منفرد می‌تواند همزمان با انواع داده مختلفی کار کند، اما یک تابع معمولی منفرد تنها با یک مجموعه داده کار می‌کند. به طور معمول اگر لازم باشد عملیات یکسانی روی دو یا چند نوع داده اجرا شود، از روش function overloading استفاده می‌کنیم و دو تابع با اعلان‌های مورد نیاز می‌نویسیم. با این حال، رویکرد بهتر آن است که از قالب‌های تابع استفاده کنیم، زیرا می‌توانید وظیفه یکسانی را با نوشتن کد کمتر و کد با قابلیت نگهداری اجرا کنید.

چگونه یک قالب تابع را اعلان کنیم؟

یک قالب تابع با کلیدواژه template به همراه پارامتر (های) قالب، درون براکت های <> اعلان می‌شود که در ادامه اعلان تابع می‌آید:

1template <class T>
2T someFunction(T arg)
3{
4   ... .. ...
5}

در کد فوق T یک آرگومان قالب است که به انواع داده مختلف (int و float) دسترسی دارد و class یک کلیدواژه است. همچنین می‌توانید از typename به جای مثال فوق استفاده کنید. زمانی که یک آرگومان نوع داده به ()someFunction ارسال شود، کامپایلر یک نسخه جدید از ()someFunction برای نوع داده مفروض تولید می‌کند.

مثال 1: قالب تابع برای یافتن بزرگ‌ترین عدد

برنامه زیر با بهره‌گیری از قالب‌ها بزرگ‌ترین عدد را در میان دو عدد نمایش می‌دهد:

1// If two characters are passed to function template, character with larger ASCII value is displayed.
2#include <iostream>
3using namespace std;
4// template function
5template <class T>
6T Large(T n1, T n2)
7{
8	return (n1 > n2) ? n1 : n2;
9}
10int main()
11{
12	int i1, i2;
13	float f1, f2;
14	char c1, c2;
15	cout << "Enter two integers:\n";
16	cin >> i1 >> i2;
17	cout << Large(i1, i2) <<" is larger." << endl;
18	cout << "\nEnter two floating-point numbers:\n";
19	cin >> f1 >> f2;
20	cout << Large(f1, f2) <<" is larger." << endl;
21	cout << "\nEnter two characters:\n";
22	cin >> c1 >> c2;
23	cout << Large(c1, c2) << " has larger ASCII value.";
24	return 0;
25}

خروجی

Enter two integers:
5
10
10 is larger.

Enter two floating-point numbers:
12.4
10.2
12.4 is larger.

Enter two characters:
z
Z
z has larger ASCII value.

در برنامه فوق یک قالب تابع به نام ()Large تعریف شده است که دو آرگومان n1 و n2 با نوع داده T قبول می‌کند. T نشان می‌دهد که آرگومان‌ها می‌توانند دارای هر نوع داده‌ای باشند. تابع ()Large بزرگ‌ترین عدد را از میان دو آرگومان با استفاده از یک عملیات شرطی بازگشت می‌دهد. درون تابع ()main متغیرهایی با سه نوع متفاوت int ،float و char اعلان شده‌اند. در ادامه این متغیرها به قالب تابع Large()‎ به صورت تابع‌های نرمال ارسال می‌شوند.

در طی زمان اجرا وقتی که یک عدد صحیح به تابع قالبی ارسال شود، کامپایلر می‌داند که باید تابع ()Large را برای پذیرش آرگومان int تولید کند و به این صورت عمل می‌کند. به طور مشابه در صورتی که داده‌های اعشاری و char ارسال شوند، کامپایلر نوع داده آرگومان را شناخته و تابع ()Large را بر همین مبنا تولید می‌کند. به این ترتیب تنها با استفاده از یک قالب تابع منفرد سه تابع نرمال را پیاده‌سازی کرده‌ایم و به این ترتیب کد قابلیت نگهداری بیشتری می‌یابد.

مثال 2: تعویض داده‌ها با استفاده از قالب‌های تابع

برنامه زیر داده‌ها را با استفاده از قالب‌های تابع تعویض می‌کند:

1#include <iostream>
2using namespace std;
3template <typename T>
4void Swap(T &n1, T &n2)
5{
6	T temp;
7	temp = n1;
8	n1 = n2;
9	n2 = temp;
10}
11int main()
12{
13	int i1 = 1, i2 = 2;
14	float f1 = 1.1, f2 = 2.2;
15	char c1 = 'a', c2 = 'b';
16	cout << "Before passing data to function template.\n";
17	cout << "i1 = " << i1 << "\ni2 = " << i2;
18	cout << "\nf1 = " << f1 << "\nf2 = " << f2;
19	cout << "\nc1 = " << c1 << "\nc2 = " << c2;
20	Swap(i1, i2);
21	Swap(f1, f2);
22	Swap(c1, c2);
23        cout << "\n\nAfter passing data to function template.\n";
24	cout << "i1 = " << i1 << "\ni2 = " << i2;
25	cout << "\nf1 = " << f1 << "\nf2 = " << f2;
26	cout << "\nc1 = " << c1 << "\nc2 = " << c2;
27	return 0;
28}

خروجی

Before passing data to function template.
i1 = 1
i2 = 2
f1 = 1.1
f2 = 2.2
c1 = a
c2 = b

After passing data to function template.
i1 = 2
i2 = 1
f1 = 2.2
f2 = 1.1
c1 = b
c2 = a

در این برنامه به جای فراخوانی کردن تابع با ارسال یک مقدار، یک «فراخوانی با ارجاع» (call by reference) ارائه می‌شود. قالب تابع ()swap دو آرگومان می‌گیرد و آن‌ها را با ارجاع تعویض می‌کند.

قالب‌های کلاس

قالب‌های کلاس نیز همانند قالب‌های تابع برای اجرای عملیات کلاسی ژنریک مورد استفاده قرار می‌گیرند. برخی اوقات لازم می‌شود یک پیاده‌سازی کلاس داشته باشیم که برای همه کلاس‌ها یکسان باشد و تنها نوع داده‌های مورد استفاده متفاوت باشد. به طور معمول در این حالت باید یک کلاس برای هر نوع داده متفاوت ایجاد کنیم و یا درون کلاس منفرد از مغیرهای عضو و تابع‌های متفاوتی استفاده کنیم. روش فوق موجب می‌شود که کدبیس حجیم شود و نگهداری آن دشوار باشد، چون یک تغییر در یک کلاس/تابع باید در همه کلاس‌ها/ تابع‌ها اعمال شود. اما قالب‌های کلاس این کار را برای ما آسان می‌سازند و همچنین امکان استفاده مجدد از کد یک کلاس برای انواع داده مختلف را فراهم می‌کنند.

اعلان قالب کلاس

برای اعلان قالب کلاس به روش زیر عمل می‌کنیم:

1template <class T>
2class className
3{
4   ... .. ...
5public:
6   T var;
7   T someOperation(T arg);
8   ... .. ...
9};

در اعلان فوق T یک آرگومان قالب است که در واقع مکانی برای نگهداری انواع داده استفاده شده در کلاس به حساب می‌آید. درون بدنه کلاس یک متغیر عضو به نام var و یک تابع عضو به نام someOperation()‎ وجود دارند که هر دو از نوع T هستند.

اعلان یک شیء قالب کلاس

برای ایجاد یک شیء از روی قالب کلاس باید در زمان ایجاد شیء، نوع داده را درون براکت های <> تعریف کنیم:

1className<dataType> classObject;

برای نمونه به مثال زیر توجه کنید:

1className<int> classObject;
2className<float> classObject;
3className<string> classObject;

مثال 3: ماشین حساب ساده با استفاده از قالب کلاس

برنامه زیر اقدام به جمع، تفریق، ضرب و تقسیم دو عدد با استفاده از قالب کلاس می‌کند:

1#include <iostream>
2using namespace std;
3template <class T>
4class Calculator
5{
6private:
7	T num1, num2;
8	
9public:
10	Calculator(T n1, T n2)
11	{
12		num1 = n1;
13		num2 = n2;
14	}
15	
16	void displayResult()
17	{
18		cout << "Numbers are: " << num1 << " and " << num2 << "." << endl;
19		cout << "Addition is: " << add() << endl;
20		cout << "Subtraction is: " << subtract() << endl;
21		cout << "Product is: " << multiply() << endl;
22		cout << "Division is: " << divide() << endl;
23	}
24	
25	T add() { return num1 + num2; }
26	
27	T subtract() { return num1 - num2; }
28	
29	T multiply() { return num1 * num2; }
30	
31	T divide() { return num1 / num2; }
32};
33int main()
34{
35	Calculator<int> intCalc(2, 1);
36	Calculator<float> floatCalc(2.4, 1.2);
37	
38	cout << "Int results:" << endl;
39	intCalc.displayResult();
40	
41	cout << endl << "Float results:" << endl;
42	floatCalc.displayResult();
43	
44	return 0;
45}

خروجی

Int results:
Numbers are: 2 and 1.
Addition is: 3
Subtraction is: 1
Product is: 2
Division is: 2

Float results:
Numbers are: 2.4 and 1.2.
Addition is: 3.6
Subtraction is: 1.2
Product is: 2.88
Division is: 2

در کد فوق یک قالب کلاس به نام Calculator اعلان می‌شود. این کلاس شامل اعضای خصوصی از نوع T: num1 & num2 است و یک سازنده نیز برای مقداردهی اعضا وجود دارد. همچنین قالب کلاس فوق شامل تابع‌های عضو عمومی برای محاسبه مجموع، تفریق، حاصل‌ضرب و حاصل تقسیم اعدادی است که مقداری با نوع داده تعریف شده از سوی کاربر بازگشت می‌دهد. به طور مشابه تابع ()displayResult برای نمایش خروجی نهایی روی صفحه مورد استفاده قرار می‌گیرد.

در تابع ()main دو شیء متفاوت intCalc و floatCalc در Calculator به ترتیب برای نوع‌های داده int و float ایجاد شده‌اند. این مقادیر با استفاده از سازنده مقداردهی می‌شوند. توجه کنید که در زمان ایجاد اشیا از <int> و <float> استفاده کرده‌ایم. به این ترتیب به کامپایلر اعلام می‌کنیم که نوع داده مورد استفاده از سوی کلاس چیست. این کد یک تعریف کلاس برای هر int و float ایجاد می‌کند که در ادامه به تناسب مورد استفاده قرار می‌گیرند. سپس از تابع ()displayResult هر دو شیء برای اجرای عملیات ماشین حساب و نمایش خروجی استفاده می‌شود.

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

بر اساس رای ۷ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
programiz
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *