لغة السي++هي لغة برمجة متعددة الاستخدامات تم تطويرها كامتداد للغة C في أوائل الثمانينات بواسطة بيارن ستروستروب. تُستخدم السي ++ على نطاق واسع في تطوير البرمجيات، خاصة في التطبيقات التي تتطلب أداءً عاليًا مثل ألعاب الفيديو، الأنظمة المدمجة، والبرامج التجارية المعقدة. تتميز السي++ بدعمها للبرمجة الكائنية (Object-Oriented Programming) بالإضافة إلى البرمجة الإجرائية والبرمجة العامة (Generic Programming)، مما يجعلها مرنة وقوية. كما أن لديها إدارة دقيقة للذاكرة مما يتيح التحكم الكامل في موارد الحاسوب، ولكن هذا يتطلب من المبرمجين العناية بالتعامل مع الذاكرة لتجنب الأخطاء. تعتبر السي++من اللغات الأساسية التي تُدرّس في مجالات علوم الحاسوب والهندسة البرمجية نظرًا لأهميتها التاريخية والتطبيقية.
تاريخ وظهور لغة السي++
لغة السي++ تم تطويرها في الثمانينيات على يد بيرات ستروستروب (Bjarne Stroustrup) في مختبرات AT&T Bell Labs. إليك ملخص لتاريخ وظهور لغة السي++:
- بداية التطوير (1980-1983):
- بدأ بيرات ستروستروب العمل على لغة السي ++ في عام 1980، وكان الهدف من تطويرها هو إضافة ميزات البرمجة الكائنية (Object-Oriented Programming) إلى لغة C، التي كانت شائعة في ذلك الوقت. أطلق على اللغة في البداية اسم “C with Classes”.
- الإصدار الأول (1983):
- في عام 1983، تم تغيير اسم اللغة إلى السي ++، والذي يعكس فكرة أنها تتطور من C. الاسم “C++” يعني “زيادة على C”، حيث أن العلامة “++” في لغة C تشير إلى زيادة قيمة المتغير.
- المعايير الأولية (1985-1989):
- تم إصدار أول نسخة رسمية من السي ++ في عام 1985. هذه النسخة تضمنت ميزات أساسية مثل الفئات (Classes)، الوراثة (Inheritance)، والتحميل الزائد (Overloading).
- تطور اللغة (1990-1998):
- في عام 1990، تم إصدار النسخة الثانية من السي ++ والتي تضمنت تحسينات مثل القوالب (Templates) والفضاءات الاسمية (Namespaces).
- في عام 1998، تم اعتماد معيار ISO/C++ الأول، والمعروف بـ “C++98″، الذي أضفى مزيداً من التنظيم والتوحيد على اللغة.
- التحسينات والتحديثات (2003-2011):
- في عام 2003، تم إصدار تحديث للمعيار تحت اسم “C++03″، والذي قدم تحسينات طفيفة.
- في عام 2011، تم إصدار “C++11″، والذي قدم العديد من التحسينات الكبيرة مثل التعبيرات اللامتزامنة (Lambdas)، وأدوات الذاكرة الذكية، والأنواع المتقدمة مثل auto وnullptr.
- التحديثات المستمرة (2014-2020):
- في عام 2014، تم إصدار “C++14” الذي شمل تحسينات إضافية.
- في عام 2017، تم إصدار “C++17″، والذي قدم ميزات مثل std::optional وstd::variant.
- في عام 2020، تم إصدار “C++20” الذي جاء مع إضافات كبيرة مثل مفاهيم البرمجة (Concepts)، ومجالات النطاق (Ranges)، وتحسينات في الذاكرة.
- التحديثات الحالية (2023 وما بعدها):
- اللغة تستمر في التطور، مع تحسينات مستمرة وإصدارات جديدة تستهدف تعزيز كفاءة الأداء وإضافة ميزات جديدة تلبي احتياجات البرمجة الحديثة.
منذ ظهورها، أصبحت السي++ لغة برمجة أساسية في تطوير البرمجيات، وتستخدم على نطاق واسع في التطبيقات ذات الأداء العالي، البرمجة المدمجة، والتطبيقات المعقدة.
ميزات لغة السي++ مقارنة بـ C
إليك مقارنة بين ميزات السي++ و C، توضح كيف تطورت السي ++ وأضافت مزايا جديدة إلى الأساسيات التي قدمتها C:
- البرمجة الكائنية (Object-Oriented Programming)
- السي ++: تدعم البرمجة الكائنية، بما في ذلك الفئات (Classes)، الوراثة (Inheritance)، والتعددية الشكلية (Polymorphism). يتيح هذا تنظيم الكود بطريقة أكثر هيكلية ومرونة.
- C: لا تدعم البرمجة الكائنية بشكل أصلي؛ تعتمد على البرمجة الهيكلية وتستخدم الهياكل (Structures) لتنظيم البيانات.
- القوالب (Templates)
- السي ++: توفر ميزة القوالب، التي تسمح بكتابة أكواد يمكن أن تعمل مع أنواع بيانات متعددة دون تكرار الكود. تشمل قوالب الدوال والفئات.
- C: لا تحتوي على نظام القوالب. التعامل مع أنواع مختلفة يتطلب كتابة أكواد منفصلة لكل نوع.
- إدارة الذاكرة
- السي ++: تحتوي على مؤشرات ذكية مثل std::unique_ptr وstd::shared_ptr التي تساعد في إدارة الذاكرة تلقائيًا وتقليل خطر تسرب الذاكرة.
- C: تعتمد بشكل أساسي على المؤشرات اليدوية لتخصيص وتحرير الذاكرة، مما يزيد من خطر تسرب الذاكرة والأخطاء المتعلقة بالذاكرة.
- المساحات الاسمية (Namespaces)
- السي ++: تستخدم المساحات الاسمية لتنظيم الكود وتجنب التداخل بين الأسماء، مما يجعل إدارة الأسماء أكثر وضوحًا.
- C: لا تحتوي على مفهوم المساحات الاسمية، مما قد يؤدي إلى مشاكل في التداخل بين الأسماء في البرامج الكبيرة.
- الاستثناءات (Exceptions)
- السي ++: تدعم نظام معالجة الأخطاء باستخدام الاستثناءات، مما يفصل منطق التعامل مع الأخطاء عن منطق البرنامج الأساسي.
- C: لا تحتوي على نظام الاستثناءات؛ يعتمد على أساليب أخرى لمعالجة الأخطاء مثل قيم الإرجاع وإشارات الأخطاء.
هذه الميزات تجعل السي ++ أكثر قوة ومرونة في كتابة الكود وإدارته مقارنة بـ C، وتوفر أدوات إضافية للمبرمجين للتعامل مع التحديات البرمجية المتقدمة.
البرمجة الكائنية (Object-Oriented Programming)
البرمجة الكائنية (Object-Oriented Programming – OOP) هي نموذج برمجة يركز على استخدام الكائنات (Objects) والفئات (Classes) لتنظيم الكود وإدارته. توفر هذه البرمجة وسيلة قوية لإنشاء برامج قابلة لإعادة الاستخدام وسهلة الصيانة. فيما يلي نظرة على أهم مفاهيم البرمجة الكائنية في السي ++:
- الفئات (Classes)
- تعريف: الفئة هي نموذج أو قالب يُستخدم لإنشاء كائنات. تحتوي الفئة على البيانات (الخصائص) والوظائف (الطرق) التي تعمل على هذه البيانات.
- مثال:
cpp
Copy code
class Car {
public:
std::string make;
std::string model;
void start() {
std::cout << “Car is starting” << std::endl;
}
};
- الكائنات (Objects)
- تعريف: الكائن هو نسخة من فئة. يمكن أن يحتوي على بيانات فردية ويستطيع استخدام الوظائف المعرفة في الفئة.
- مثال:
cpp
Copy code
Car myCar;
myCar.make = “Toyota”;
myCar.model = “Corolla”;
myCar.start();
- الوراثة (Inheritance)
- تعريف: الوراثة هي ميزة تتيح لفئة أن ترث الخصائص والوظائف من فئة أخرى. تُستخدم لإعادة استخدام الكود وتنظيمه بطريقة هرمية.
- مثال:
cpp
Copy code
class ElectricCar : public Car {
public:
void charge() {
std::cout << “Charging the car” << std::endl;
}
};
- التعددية الشكلية (Polymorphism)
- تعريف: التعددية الشكلية تسمح لكائنات من أنواع مختلفة أن تستجيب لنفس النداء على طريقة بطريقة مختلفة. تشمل التعددية الشكلية في السي ++التعددية الشكلية المبنية على المؤشرات (Pointer-Based Polymorphism) والتعددية الشكلية المبنية على القوالب (Template-Based Polymorphism).
- مثال:
cpp
Copy code
class Animal {
public:
virtual void speak() {
std::cout << “Animal speaks” << std::endl;
}
};
class Dog : public Animal {
public:
void speak() override {
std::cout << “Dog barks” << std::endl;
}
};
Animal* myAnimal = new Dog();
myAnimal->speak(); // Output: Dog barks
- التغليف (Encapsulation)
- تعريف: التغليف هو مفهوم يتيح لك إخفاء التفاصيل الداخلية لتنفيذ الكائن وفتح واجهة عامة للتفاعل مع الكائن. يساعد في حماية البيانات والتأكد من الوصول إليها بشكل آمن.
- مثال:
cpp
Copy code
class BankAccount {
private:
double balance;
public:
void deposit(double amount) {
balance += amount;
}
double getBalance() {
return balance;
}
};
البرمجة الكائنية توفر إطار عمل قوي لتنظيم الكود، مما يجعل البرامج أكثر مرونة وقابلية للصيانة، وتعزز القدرة على إعادة استخدام الكود وتنظيم البيانات والوظائف بشكل منطقي.
القوالب (Templates)
القوالب (Templates) في السي ++هي ميزة تسمح بكتابة أكواد يمكن استخدامها مع أنواع بيانات متعددة دون الحاجة لتكرار الكود. هذه الميزة تعزز القابلية لإعادة الاستخدام وتوفر طريقة مرنة للتعامل مع الأنواع المختلفة. هناك نوعان رئيسيان من القوالب في السي ++: قوالب الدوال (Function Templates) وقوالب الفئات (Class Templates).
- قوالب الدوال (Function Templates)
قوالب الدوال تتيح لك تعريف دالة يمكن استخدامها مع أنواع بيانات مختلفة. بدلاً من كتابة دوال متعددة لكل نوع بيانات، يمكنك استخدام قالب دالة واحد.
مثال:
cpp
Copy code
template <typename T>
T max(T a, T b) {
return (a > b) ? a : b;
}
int main() {
std::cout << max(10, 20) << std::endl; // Output: 20
std::cout << max(15.5, 10.5) << std::endl; // Output: 15.5
}
في هذا المثال، max هي دالة قالب تقارن بين قيمتين من نفس النوع وتعيد القيمة الأكبر. يمكن استخدام الدالة مع أنواع بيانات مختلفة مثل int وdouble.
- قوالب الفئات (Class Templates)
قوالب الفئات تتيح لك تعريف فئة يمكن استخدامها مع أنواع بيانات مختلفة. هذا مفيد عند إنشاء هياكل بيانات عامة مثل القوائم والمصفوفات.
مثال:
cpp
Copy code
template <typename T>
class Stack {
private:
std::vector<T> elements;
public:
void push(const T& element) {
elements.push_back(element);
}
T pop() {
if (elements.empty()) {
throw std::out_of_range(“Stack<>::pop(): empty stack”);
}
T elem = elements.back();
elements.pop_back();
return elem;
}
bool isEmpty() const {
return elements.empty();
}
};
int main() {
Stack<int> intStack;
intStack.push(1);
intStack.push(2);
std::cout << intStack.pop() << std::endl; // Output: 2
Stack<std::string> stringStack;
stringStack.push(“Hello”);
stringStack.push(“World”);
std::cout << stringStack.pop() << std::endl; // Output: World
}
في هذا المثال، Stack هي فئة قالب تُستخدم لإنشاء كائنات من أنواع بيانات مختلفة، مثل int وstd::string.
ميزات القوالب:
- إعادة استخدام الكود: يمكنك استخدام القوالب لتجنب كتابة كود مكرر لأن القوالب يمكن أن تعمل مع أي نوع بيانات.
- مرونة: يمكنك تعريف دوال وفئات تعمل مع أنواع بيانات مختلفة بمرونة.
- تحسين الأداء: القوالب في السي ++ توفر تعبيرًا على مستوى الترجمة، مما يعني أنه يمكن تحسين الكود وتفادي التكاليف الزمنية لتفسير الأنواع في وقت التشغيل.
تخصيص القوالب (Template Specialization)
- تخصيص الكاملة (Full Specialization): يتيح لك تخصيص قالب معين لنوع بيانات محدد.
- تخصيص جزئي (Partial Specialization): يتيح تخصيص القوالب لأنواع بيانات معينة مع الاحتفاظ بالمرونة مع أنواع بيانات أخرى.
مثال لتخصيص القوالب:
cpp
Copy code
template <typename T>
class Printer {
public:
void print(const T& value) {
std::cout << value << std::endl;
}
};
// تخصيص للقوالب عند استخدام الأنواع الأساسية
template <>
class Printer<bool> {
public:
void print(const bool& value) {
std::cout << (value ? “True” : “False”) << std::endl;
}
};
int main() {
Printer<int> intPrinter;
intPrinter.print(123); // Output: 123
Printer<bool> boolPrinter;
boolPrinter.print(true); // Output: True
}
تخصيص القوالب يسمح بتحسين سلوك القوالب لأنواع بيانات معينة بما يتناسب مع احتياجاتك الخاصة.
إدارة الذاكرة والمؤشرات الذكية (Smart Pointers)Top of Form
إدارة الذاكرة هي جزء أساسي في البرمجة بلغة السي ++، ومؤشرات الذكية (Smart Pointers) تلعب دوراً مهماً في تسهيل هذه الإدارة وتقليل المخاطر المرتبطة بها مثل تسرب الذاكرة والأخطاء الناتجة عن الوصول إلى ذاكرة غير صالحة. مؤشرات الذكية توفر طريقة آمنة وفعالة للتعامل مع تخصيص وتحرير الذاكرة. في السي ++، توجد أنواع رئيسية من المؤشرات الذكية: std::unique_ptr، std::shared_ptr، و std::weak_ptr.
- std::unique_ptr
- الوصف: std::unique_ptr هو مؤشر ذكي يمتلك كائنًا واحدًا فقط، ولا يمكن أن يكون هناك أكثر من unique_ptr واحد يشير إلى نفس الكائن. هذا يضمن أنه لا يوجد تكرار للملكية، وبالتالي يزيل المخاطر المرتبطة بمشكلات التخصيص المزدوج.
- إدارة الذاكرة: يحرر الذاكرة تلقائيًا عندما يتم تدمير الكائن أو عندما يتم إعادة تعيين unique_ptr إلى كائن آخر.
- المثال:
cpp
Copy code
#include <iostream>
#include <memory>
int main() {
std::unique_ptr<int> ptr1 = std::make_unique<int>(10);
std::cout << *ptr1 << std::endl; // Output: 10
// لا يمكن نسخ unique_ptr، لكن يمكن نقله:
std::unique_ptr<int> ptr2 = std::move(ptr1);
std::cout << *ptr2 << std::endl; // Output: 10
// ptr1 الآن لا يمتلك الكائن، استخدامه سيكون خطأ.
}
- std::shared_ptr
- الوصف: std::shared_ptr هو مؤشر ذكي يسمح بالملكية المشتركة لكائن واحد. يمكن أن يكون هناك عدة shared_ptr يشيرون إلى نفس الكائن، ويكون الكائن مملوكًا حتى يتم تحرير آخر shared_ptr يشير إليه.
- إدارة الذاكرة: يستخدم عداد مرجعي (Reference Count) لتتبع عدد المؤشرات التي تشير إلى نفس الكائن. يتم تحرير الذاكرة تلقائيًا عندما ينخفض عداد المرجع إلى الصفر.
- المثال:
cpp
Copy code
#include <iostream>
#include <memory>
int main() {
std::shared_ptr<int> ptr1 = std::make_shared<int>(20);
std::cout << *ptr1 << std::endl; // Output: 20
// يمكن نسخ shared_ptr
std::shared_ptr<int> ptr2 = ptr1;
std::cout << *ptr2 << std::endl; // Output: 20
std::cout << ptr1.use_count() << std::endl; // Output: 2 (عدد المؤشرات المشتركة)
}
- std::weak_ptr
- الوصف: std::weak_ptr هو مؤشر ذكي يتيح الوصول إلى كائن يتم التحكم فيه بواسطة std::shared_ptr بدون التأثير على عداد المرجع. يستخدم weak_ptr بشكل رئيسي لتجنب المشاكل المرتبطة بالحلقات المرجعية (Circular References).
- إدارة الذاكرة: لا يؤثر weak_ptr على عدد المراجع للكائن. يستخدم للوصول إلى الكائن إذا كان لا يزال موجودًا، بدون ضمان وجوده.
- المثال:
cpp
Copy code
#include <iostream>
#include <memory>
int main() {
std::shared_ptr<int> ptr1 = std::make_shared<int>(30);
std::weak_ptr<int> weakPtr = ptr1;
if (auto sharedPtr = weakPtr.lock()) { // محاولة لتحويل weak_ptr إلى shared_ptr
std::cout << *sharedPtr << std::endl; // Output: 30
} else {
std::cout << “The object has been deleted” << std::endl;
}
}
فوائد استخدام المؤشرات الذكية:
- تقليل تسرب الذاكرة: يقوم المؤشر الذكي بإدارة الذاكرة تلقائيًا، مما يقلل من احتمال تسرب الذاكرة.
- إدارة الموارد بشكل أكثر أمانًا: يعزز الأمان عن طريق التأكد من تحرير الموارد بشكل صحيح حتى في حالة حدوث استثناءات.
- تقليل أخطاء الوصول إلى الذاكرة: يساعد في تجنب أخطاء الوصول إلى ذاكرة غير صالحة بفضل إدارة الملكية التلقائية.
مؤشرات الذكية تجعل الكود في السي ++ أكثر أمانًا وسهولة في الإدارة، وتعد جزءاً أساسياً من أفضل الممارسات في إدارة الذاكرة.
Bottom of Form
المكتبات القياسية (Standard Library)
المكتبة القياسية في السي ++ (Standard Library) هي مجموعة من الأدوات والوظائف التي توفرها لغة السي ++ لدعم البرمجة الفعّالة. هذه المكتبة تشمل مجموعة متنوعة من المكونات التي تسهل كتابة برامج قوية ومرنة. إليك نظرة على بعض العناصر الأساسية في المكتبة القياسية لـ السي ++:
- الحاويات (Containers)
تعتبر الحاويات جزءاً أساسياً من المكتبة القياسية، حيث توفر هياكل بيانات متنوعة لتخزين وتنظيم العناصر.
- std::vector: حاوية قائمة متجهية توفر تخزينًا ديناميكيًا للعناصر، مع القدرة على الوصول العشوائي.
cpp
Copy code
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec = {1, 2, 3, 4};
vec.push_back(5);
for (int n : vec) {
std::cout << n << ‘ ‘;
}
}
- std::list: حاوية قائمة مزدوجة الرابط، توفر إضافة وحذف العناصر في أي مكان بسرعة.
cpp
Copy code
#include <list>
#include <iostream>
int main() {
std::list<int> lst = {1, 2, 3, 4};
lst.push_back(5);
for (int n : lst) {
std::cout << n << ‘ ‘;
}
}
- std::map: حاوية خريطة توفر تخزين عناصر كأزواج مفتاح-قيمة، حيث يتم ترتيب العناصر حسب المفتاح.
cpp
Copy code
#include <map>
#include <iostream>
int main() {
std::map<std::string, int> age;
age[“Alice”] = 30;
age[“Bob”] = 25;
for (const auto& pair : age) {
std::cout << pair.first << “: ” << pair.second << std::endl;
}
}
- الخوارزميات (Algorithms)
توفر المكتبة القياسية مجموعة واسعة من الخوارزميات المفيدة التي يمكن استخدامها مع الحاويات.
- std::sort: خوارزمية لترتيب العناصر في الحاوية.
cpp
Copy code
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec = {4, 2, 5, 1, 3};
std::sort(vec.begin(), vec.end());
for (int n : vec) {
std::cout << n << ‘ ‘;
}
}
- std::find: خوارزمية للبحث عن عنصر في الحاوية.
cpp
Copy code
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
auto it = std::find(vec.begin(), vec.end(), 3);
if (it != vec.end()) {
std::cout << “Found: ” << *it << std::endl;
}
}
- المؤشرات الذكية (Smart Pointers)
كما ذكرت سابقاً، المؤشرات الذكية هي جزء من المكتبة القياسية وتوفر إدارة تلقائية للذاكرة.
- std::unique_ptr: لإدارة ملكية كائن واحد.
- std::shared_ptr: لإدارة ملكية كائن مشترك بين عدة مؤشرات.
- std::weak_ptr: لتجنب الحلقات المرجعية مع shared_ptr.
- التعامل مع النصوص (Strings)
تقدم المكتبة القياسية أنواعًا متعددة للتعامل مع النصوص، أهمها std::string.
- std::string: نوع بيانات لتمثيل النصوص مع وظائف متعددة لمعالجة النصوص.
cpp
Copy code
#include <string>
#include <iostream>
int main() {
std::string str = “Hello, World!”;
std::cout << str.substr(7, 5) << std::endl; // Output: World
}
- التعامل مع المدخلات والمخرجات (I/O)
تقدم المكتبة القياسية أدوات للتعامل مع المدخلات والمخرجات.
- std::cin: لإدخال البيانات من المستخدم.
- std::cout: لطباعة البيانات على الشاشة.
- std::ifstream و std::ofstream: لقراءة وكتابة الملفات.
cpp
Copy code
#include <iostream>
#include <fstream>
int main() {
std::ofstream outFile(“example.txt”);
outFile << “Hello, File!” << std::endl;
outFile.close();
std::ifstream inFile(“example.txt”);
std::string content;
std::getline(inFile, content);
std::cout << content << std::endl; // Output: Hello, File!
}
- التحكم بالاستثناءات (Exception Handling)
تتيح المكتبة القياسية التعامل مع الأخطاء باستخدام الاستثناءات.
- try, catch, throw: للتعامل مع الاستثناءات بشكل فعال.
cpp
Copy code
#include <iostream>
#include <stdexcept>
int main() {
try {
throw std::runtime_error(“An error occurred”);
} catch (const std::runtime_error& e) {
std::cout << “Caught exception: ” << e.what() << std::endl;
}
}
فوائد استخدام المكتبة القياسية:
- زيادة الإنتاجية: توفر المكتبة أدوات جاهزة، مما يقلل الحاجة لكتابة كود من الصفر.
- قابلية النقل: الكود الذي يستخدم المكتبة القياسية يتوافق مع معظم أنظمة التشغيل والمترجمات.
- تحسين الأمان: توفر ميزات آمنة وفعالة لإدارة الذاكرة والتعامل مع البيانات.
تعتبر المكتبة القياسية جزءاً أساسياً من السي ++ وتساهم بشكل كبير في تطوير برمجيات موثوقة وفعّالة.
خاتمة
في الختام، توفر لغة السي ++ مجموعة قوية ومرنة من الأدوات التي تسهم في تطوير برمجيات فعالة وقابلة للصيانة. من خلال استخدام مفاهيم البرمجة الكائنية (OOP)، مثل الفئات والوراثة والتعددية الشكلية، إلى الاستفادة من ميزات القوالب (Templates) لإعادة استخدام الكود بطريقة مرنة، تُظهر السي ++قدرتها على التعامل مع مشاريع البرمجة المعقدة.
إدارة الذاكرة من خلال المؤشرات الذكية (Smart Pointers) تُسهم بشكل كبير في تقليل مشاكل تسرب الذاكرة والأخطاء المتعلقة بالذاكرة، مما يعزز الأمان والكفاءة. في حين أن المكتبة القياسية (Standard Library) توفر مجموعة واسعة من الحاويات، والخوارزميات، وأدوات التعامل مع النصوص والمدخلات والمخرجات، مما يسهل على المبرمجين كتابة كود أكثر تنظيماً وأقل عرضة للأخطاء.
تجعل هذه الأدوات والمفاهيم السي++ لغة برمجة قوية ومفضلة في تطوير البرمجيات الكبيرة والمعقدة، حيث تجمع بين الأداء العالي والمرونة والقدرة على إدارة الموارد بشكل فعال. باستخدام هذه الميزات بفعالية، يمكن للمبرمجين الاستفادة من قوة السي++ لتطوير تطبيقات ذات جودة عالية وفعالية.