C++: أساسيات الدوال
آخر تحديث: 2026-08-26
في الدروس الساببة، كان كل الكود مكتوبًا داخل دالة
main.لكن مع نمو البرامج، تصبح دالة
mainطويلة وصعبة الصيانة.الدوال تحل هذه المشكلة — تقسيم الكود إلى وحدات صغيرة، كل مسؤولة عن مهمة واحدة.
1. ما هي الدالة؟
(1) 1.1 الدوال في الحياة اليومية
| سيناريو من الحياة | المقابل البرمجي |
|---|---|
| تضغط زر "التشغيل" على جهاز التحكم بالتلفاز | استدعاء دالة turnOnTV() |
| التلفاز ينفذ تلقائيًا سلسلة عمليات (تشغيل، بحث القنوات، عرض الصورة) | الكود داخل جسم الدالة |
| لا تحتاج لمعرفة كيف يعمل التلفاز داخليًا | خاصية "التغليف" للدوال |
الدالة هي كتلة كود تنفذ مهمة محددة، يمكن استدعاؤها بشكل متكرر.
(2) 1.2 لماذا نحتاج الدوال؟
بدون دوال (مثال سيئ):
#include <iostream>
int main() {
// Calculate area of the first rectangle
double width1 = 5.0, height1 = 3.0;
double area1 = width1 * height1;
std::cout << "Area 1: " << area1 << std::endl;
// Calculate area of the second rectangle
double width2 = 7.0, height2 = 2.5;
double area2 = width2 * height2;
std::cout << "Area 2: " << area2 << std::endl;
// Calculate area of the third rectangle
double width3 = 4.0, height3 = 6.0;
double area3 = width3 * height3;
std::cout << "Area 3: " << area3 << std::endl;
return 0;
}
بالدوال (مثال جيد):
#include <iostream>
// Define the function
double calculateArea(double width, double height) {
return width * height;
}
int main() {
std::cout << "Area 1: " << calculateArea(5.0, 3.0) << std::endl;
std::cout << "Area 2: " << calculateArea(7.0, 2.5) << std::endl;
std::cout << "Area 3: " << calculateArea(4.0, 6.0) << std::endl;
return 0;
}
مقارنة:
| بدون دوال | بدوال |
|---|---|
| تكرار الكود (نسخ ولصق) | إعادة استخدام الكود (اكتب مرة واحدة) |
| تغيير المنطق يتطلب تغييرات في أماكن متعددة | غيّر جسم الدالة في مكان واحد فقط |
| صعوبة الصيانة | سهولة الصيانة |
2. تعريف الدالة
(1) 2.1 الصياغة الأساسية
ReturnType functionName(parameterList) {
// function body
return returnValue; // if return type is not void
}
(2) 2.2 أجزاء الدالة
| الجزء | المعنى | المثال |
|---|---|---|
| نوع الإرجاع | نوع القيمة التي تُرجعها الدالة | int، double، void (بدون إرجاع) |
| اسم الدالة | اسم الدالة (يتبع قواعد تسمية المتغيرات) | calculateArea، printHello |
| قائمة المعلمات | المدخلات التي تستقبلها الدالة (يمكن أن تكون فارغة) | (double w, double h) |
| جسم الدالة | الكود الذي تنفذه الدالة | { return w * h; } |
| return | يُرجع النتيجة إلى المستدعي | return area; |
▶ مثال 1: تعريف دالة بسيطة (صعوبة ⭐)
#include <iostream>
// Function definition: calculate the sum of two numbers
int add(int a, int b) {
return a + b;
}
int main() {
int result = add(3, 5); // Call the function
std::cout << "3 + 5 = " << result << std::endl;
return 0;
}
الخرج:
3 + 5 = 8
3. استدعاء الدوال
(1) 3.1 صياغة الاستدعاء
functionName(argumentList);
| المصطلح | المعنى | المثال |
|---|---|---|
| تعريف الدالة | كتابة كود الدالة | int add(int a, int b) { ... } |
| استدعاء الدالة | استخدام الدالة | add(3, 5); |
| المعامل الشكلي (parameter) | المعلمات في تعريف الدالة | int a, int b |
| المعامل الفعلي (argument) | القيم الممررة عند استدعاء الدالة | 3, 5 |
💡 نقطة مهمة: المعاملات الفعلية تُنسخ إلى المعاملات الشكلية (سنتعلم عن المراجع لاحقًا، حيث لا حاجة للنسخ).
4. قيم الإرجاع
(1) 4.1 جملة return
return له غرضان:
- إرجاع نتيجة إلى المستدعي
- إنهاء الدالة (الكود بعد return لن يُنفَّذ)
#include <iostream>
int max(int a, int b) {
if (a > b) {
return a; // End function, return a
} else {
return b; // End function, return b
}
std::cout << "This line never executes" << std::endl; // Dead code
}
int main() {
std::cout << "Maximum: " << max(10, 20) << std::endl;
return 0;
}
(2) 4.2 الدوال بدون قيمة إرجاع (void)
إذا لم تكن الدالة بحاجة لإرجاع قيمة، استخدم void كنوع الإرجاع:
#include <iostream>
void printWelcome() { // void means no return value
std::cout << "========== Welcome ==========" << std::endl;
std::cout << "This is a void function, no return needed" << std::endl;
}
int main() {
printWelcome(); // Call void function, no need to receive a return value
return 0;
}
💡 نصيحة: يمكنك أيضًا كتابة return; (بدون قيمة) في دالة void للخروج مبكرًا.
void printIfPositive(int x) {
if (x <= 0) {
return; // Exit the function early
}
std::cout << x << " is positive" << std::endl;
}
5. النماذج الأولية للدوال (تصريحات الدوال)
(1) 5.1 المشكلة: يجب تعريف الدوال قبل استدعائها
#include <iostream>
int main() {
std::cout << add(3, 5) << std::endl; // ❌ Error: compiler hasn't seen add's definition yet
return 0;
}
int add(int a, int b) {
return a + b;
}
رسالة خطأ الترجمة:
error: 'add' was not declared in this scope
(2) 5.2 الحل: النماذج الأولية للدوال
النموذج الأولي للدالة (يسمى أيضًا تصريح الدالة) يخبر المترجم "هذه الدالة موجودة"، بينما يمكن تعريف جسم الدالة الفعلي لاحقًا.
#include <iostream>
int add(int a, int b); // Function prototype (ends with semicolon!)
int main() {
std::cout << add(3, 5) << std::endl; // ✅ Compiler knows add exists
return 0;
}
int add(int a, int b) { // Function definition
return a + b;
}
💡 القواعد:
- النماذج الأولية للدوال تنتهي بـ فاصلة منقوطة
- يمكن حذف أسماء المعلمات، فقط الأنواع مطلوبة:
int add(int, int); - لكن يُنصح بالاحتفاظ بأسماء المعلمات لسهولة القراءة
6. تطبيق: آلة حاسبة بالدوال
▶ مثال 2: آلة حاسبة باستخدام الدوال (صعوبة ⭐⭐)
#include <iostream>
#include <iomanip>
// Function prototypes
double add(double a, double b);
double subtract(double a, double b);
double multiply(double a, double b);
double divide(double a, double b);
int main() {
double num1, num2;
char op;
std::cout << "Please enter the first number: ";
std::cin >> num1;
std::cout << "Please enter an operator (+ - * /): ";
std::cin >> op;
std::cout << "Please enter the second number: ";
std::cin >> num2;
std::cout << std::fixed << std::setprecision(2);
switch (op) {
case '+':
std::cout << "Result: " << add(num1, num2) << std::endl;
break;
case '-':
std::cout << "Result: " << subtract(num1, num2) << std::endl;
break;
case '*':
std::cout << "Result: " << multiply(num1, num2) << std::endl;
break;
case '/':
if (num2 != 0) {
std::cout << "Result: " << divide(num1, num2) << std::endl;
} else {
std::cout << "Error: Divisor cannot be 0!" << std::endl;
}
break;
default:
std::cout << "Error: Unsupported operator!" << std::endl;
break;
}
return 0;
}
// Function definitions
double add(double a, double b) {
return a + b;
}
double subtract(double a, double b) {
return a - b;
}
double multiply(double a, double b) {
return a * b;
}
double divide(double a, double b) {
return a / b;
}
الخرج:
Please enter the first number:
Please enter an operator (+ - * /):
Please enter the second number:
Result:
Result:
Result:
Result:
Error: Divisor cannot be 0!
Error: Unsupported operator!
7. الأخطاء الشائعة
(1) 7.1 نسيان كتابة نموذج أولي للدالة
خطأ:
int main() {
foo(); // ❌ Compiler doesn't know what foo is yet
return 0;
}
void foo() {
std::cout << "Hello" << std::endl;
}
إصلاح: أضف نموذجًا أوليًا للدالة:
void foo(); // ✅ Function prototype
int main() {
foo();
return 0;
}
void foo() {
std::cout << "Hello" << std::endl;
}
(2) 7.2 عدم تطابق النموذج الأولي مع التعريف
خطأ:
int foo(int a); // Prototype: returns int
int main() {
foo(5);
return 0;
}
double foo(int a) { // ❌ Error: definition returns double, doesn't match prototype
return a + 0.5;
}
(3) 7.3 نسيان كتابة return
خطأ:
int add(int a, int b) {
int sum = a + b;
// ❌ Forgot to write return
}
int main() {
int result = add(3, 5);
std::cout << result << std::endl; // Outputs garbage value
return 0;
}
💡 نصيحة: قد لا يحذرك مترجم C++ من return مفقود، لكن سلوك البرنامج غير معرف (قد يُخرج قيم عشوائية، قد ينهار).
❓ أسئلة شائعة
int add(int, int); صالح نحويًا؛ int add(int a, int b); موصى به لسهولة القراءة.std::tuple (C++11 وما بعدها)return; (بدون قيمة) يمكنه الخروج من دالة void مبكرًا.▶ مثال 3: قيمة إرجاع الدالة (صعوبة ⭐)
#include <iostream>
int max(int a, int b) {
return (a > b) ? a : b;
}
int main() {
int x = 10, y = 20;
std::cout << "Larger value: " << max(x, y) << std::endl;
return 0;
}
الخرج:
Larger value: 20
return. العامل الثلاثي ? : يمكنه تبسيط الفحوص الشرطية البسيطة.
📖 ملخص
- الدوال هي كتل كود تنفذ مهامًا محددة ويمكن إعادة استخدامها
- صياغة تعريف الدالة:
ReturnType functionName(parameterList) { functionBody } - النماذج الأولية للدوال تخبر المترجم بوجود دالة، تنتهي بفاصلة منقوطة
returnيُرجع نتيجة وينهي الدالة- دوال
voidلا تُرجع قيمة - يمكن تصريح الدوال أولًا (نموذج أولي) وتعريفها لاحقًا
📝 تمارين
-
أساسي (صعوبة ⭐): اكتب دالة
int multiply(int a, int b)تُرجع جداء عددين صحيحين. استدعِها في دالةmain. -
متوسط (صعوبة ⭐⭐): اكتب دالة
bool isPrime(int n)تحدد هل العدد الصحيح أولي. -
عدد أولي: عدد قابل للقسمة فقط على 1 وعلى نفسه (مثل 2، 3، 5، 7، 11)
-
في دالة
main، دع المستخدم يدخل عددًا صحيحًا، استدعِisPrime، وأخرج النتيجة -
تحدي (صعوبة ⭐⭐⭐): اكتب برنامجًا يحتوي الدوال التالية:
-
int fibonacci(int n): تُرجع العدد الفيبوناتشي رقم n -
void printFibonacci(int n): تُخرج أول n عدد فيبوناتشي
في دالة main، دع المستخدم يدخل n، أولًا أخرج الأعداد n الأولى، ثم أخرج قيمة العدد رقم n.
- الدوال هي كتل كود قابلة لإعادة الاستخدام تقلل التكرار
- عناصر الدالة الأربعة: نوع الإرجاع، اسم الدالة، قائمة المعلمات، جسم الدالة
- تصريحات النماذج الأولية للدوال تُعلم المترجم بوجود الدالة
- return يُرجع قيمة وينهي تنفيذ الدالة
- دوال void لا تُرجع قيمة؛ يمكن استخدام return; للخروج مبكرًا
8. 🚀 الخطوة التالية
الآن بعد أن تعلمت أساسيات الدوال، سنتعلم بعد ذلك تمرير معلمات الدوال (الدرس 11) — تعلم كيفية تمرير المعلمات إلى الدوال والفرق بين "التمرير بالقيمة" و"التمرير بالمرجع".