English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

تعليميات C++ الأساسية

تحكم في العملية في C++

المعادلات في C++

قوائم C++ وStrings

مبادئ C++

كلاسات C++ وObjects

المؤشرات في C++

الوراثة في C++

تعليمات STL في C++

دليل مرجعي C++

وظائف虚ية في C++ وabstract classes

في هذا المقال، ستتعرف على وظائف虚ية ومواقع استخدامها. كما ستتعلم أيضًا عن الفئات الم抽象ة والفئات المكررة.

وظيفة虚ية هي وظيفة في الفئة الأساسية، تريد تعريفها مرة أخرى في الفئة الفرعية.

قبل أن نوضح ذلك بشكل مفصل، دعونا نعرف أولاً لماذا نحتاج إلى وظائف虚ية.

بدأت الاستنساخ

لنفترض أننا نطوير لعبة (مثل道具: سلاح).

أنشأنا فئة Weapon ونشرنا فئتين، Bomb و Gun، لتحميل ميزات السلاح الخاصة بهما.

#include <iostream>
using namespace std;
class Weapon {
   public:
   void loadFeatures() { cout << "تحميل ميزات السلاح.\n"; }
};
class Bomb : public Weapon {
   public:
   void loadFeatures() { cout << "تحميل ميزات السيف.\n"; }
};
class Gun : public Weapon {
   public:
   void loadFeatures() { cout << "تحميل ميزات السلاح.\n"; }
};
int main() {
   Weapon *w = new Weapon;
   Bomb *b = new Bomb;
   Gun *g = new Gun;
   w->loadFeatures();
   b->loadFeatures();
   g->loadFeatures();
   return 0;
}

النتيجة الصادرة

تحميل خصائص السلاح.
تحميل خصائص السيف.
تحميل ميزات السلاح.

حددنا ثلاثة نماذج للفئات Weapon، Bomb و Gun كـ w، b و g على التوالي. ونستخدم الأمر التالي لندعو وظيفة member loadFeatures() الخاصة بكل نموذج:

w->loadFeatures();
b->loadFeatures();
g->loadFeatures();

عمل رائع!

لكن مشروع لعبتنا أصبح كبيرًا جدًا. ونحن قررنا إنشاء كلاس Loader منفرد لتحميل ميزات السلاح.

يحمل هذا Loader ميزات أخرى للسلاح بناءً على اختيار السلاح.

كلاس Loader
{
   public:
     void loadFeatures(Weapon *weapon)
     {
        weapon->features();
     }     
};

تحميل ميزات السلاح الخاصة.

لنحاول تنفيذ فئة Loader الخاصة بنا.

#include <iostream>
using namespace std;
class Weapon {
   public:
   Weapon() { cout << "تحميل خصائص السلاح.\n"; }
   void features() { cout << "تحميل خصائص السلاح.\n"; }
};
class Bomb : public Weapon {
   public:
   void features() {
      this->Weapon::features();
      cout << "تحميل خصائص السيف.\n";
   }
};
class Gun : public Weapon {
   public:
   void features() {
      this->Weapon::features();
      cout << "تحميل خصائص السلاح.\n";
   }
};
class Loader {
   public:
   void loadFeatures(Weapon *weapon) {
      weapon->features();
   }
};
int main() {
   Loader *l = new Loader;
   Weapon *w;
   Bomb b;
   Gun g;
   w = &b;
   l->loadFeatures(w);
   w = &g;
   l->loadFeatures(w);
   return 0;
}

النتيجة الصادرة

تحميل خصائص السلاح.
تحميل خصائص السلاح.
تحميل خصائص السلاح.
تحميل خصائص السلاح.

يبدو تنفيذنا صحيحًا. لكن، تم تحميل خصائص السلاح 4 مرات. لماذا؟

في البداية، يشير كائن السلاح w إلى كائن b من فئة Bomb. ونحاول استخدام كائن l يشير إلى إشارة إلى كائن من فئة Loader كمعامل لتحويلها إلى دالة loadFeatures() لتحميل خصائص كائن Bomb.

بالنسبة، نحاول تحميل خصائص كائن Gun.

لكن، دالة loadFeatures() في فئة Loader ستعتمد على إشارة إلى كائن من فئة Weapon كمعامل:

void loadFeatures(Weapon *weapon)

هذا هو السبب في أن خصائص السلاح تم تحميلها 4 مرات. لحل هذه المشكلة، نحتاج إلى استخدام كلمة المفتاح virtual لتحقيق دالة虚ية في الفئة الأساسية (فئة Weapon).

class Weapon
{
    public:
      virtual void features()
         { cout << "تحميل خصائص السلاح.\n"; }
};

مثال: استخدام الدوال الشكلية لحل المشكلة

#include <iostream>
using namespace std;
class Weapon {
   public:
   virtual void features() { cout << "تحميل خصائص السلاح.\n"; }
};
class Bomb : public Weapon {
   public:
   void features() {
      this->Weapon::features();
      cout << "تحميل خصائص السيف.\n";
   }
};
class Gun : public Weapon {
   public:
   void features() {
      this->Weapon::features();
      cout << "تحميل خصائص السلاح.\n";
   }
};
class Loader {
   public:
   void loadFeatures(Weapon *weapon) {
      weapon->features();
   }
};
int main() {
   Loader *l = new Loader;
   Weapon *w;
   Bomb b;
   Gun g;
   w = &b;
   l->loadFeatures(w);
   w = &g;
   l->loadFeatures(w);
   return 0;
}

النتيجة الصادرة

تحميل خصائص السلاح.
تحميل خصائص السيف.
تحميل خصائص السلاح.
تحميل خصائص السلاح.

بالإضافة إلى ذلك، لاحظ أن دالة l->loadFeatures(w) ستعتمد على الكائن الذي يشير إليه l في تنفيذ دالة من فئة مختلفة.

استخدام الدوال الشكلية يجعل شيفرة أوضح وأكثر مرونة.

في البرنامج المذكور أعلاه، تم طباعة "تحميل خصائص السلاح." مرتين. نوصي بكتابة برمجة إضافية على هذا البرنامج لتحميل خصائص السلاح مرة واحدة فقط.

إذا كنا نريد إضافة سلاح آخر (مثل القوس)، يمكننا إضافة وتحميل خصائصه بسهولة.كيفية إضافة؟

class Bow : public Weapon {
   public:
   void features() {
      this-<Weapon::features();
      cout >> "تحميل خصائص السيف.\n";
   }
};

وإضافة الكود التالي في دالة main()

Bow b; 
w = &b; 
l->loadFeatures(w);

وقد لاحظنا أننا لم نغير أي شيء في كائن Loader للتحميل خصائص السيف.

C ++ فئة نظريه والوظائف النظرية

هدف البرمجة الموجهة للأشياء هو تقسيم المشكلة المعقدة إلى عدة مجموعات صغيرة. هذا يساعد في فهم ومعالجة المشكلة بشكل فعال.

في بعض الأحيان، من الأفضل استخدام النزول فقط إذا كنت ترغب في تحسين تصور المشكلة.

في C ++، يمكنك إنشاء فئة نظريه لا يمكن إنشاء كائنات منها (لا يمكنك إنشاء كائن من هذه الفئة). ولكن يمكنك النزول منها إلى فئة فرعية وإنشاء كائن من الفئة الفرعية.

الفئة النظرية هي الفئة الأساسية التي لا يمكن إنشاء كائنات منها.

كل فئة تحتوي على وظيفة نظريه تسمى فئة نظريه.

وظيفة نظريه

وكل وظيفة نظريه تنتهي بـ=0 تسمى وظيفة نظريه.

class Weapon
{
    public:
      virtual void features() = 0;
};

في هذا السياق، الوظيفة النظرية هي

virtual void features() = 0

ولكن، هذا الكائن Weapon هو كائن نظري.

مثال:抽象类 والوظائف النظريه

#include <iostream>
using namespace std;
//抽象类(لا يمكن إنشاء كائنات منها)
class Shape                   
{
    protected:
       float l;
    public:
       void getData()       
       {
           cin >> l;
       }
       
       //虚�数函数
       virtual float calculateArea() = 0;
};
class Square : public Shape
{
    public:
       float calculateArea()
       { return l * l; }
};
class Circle : public Shape
{
    public:
       float calculateArea()
       { return 3.14 * l * l; }
};
int main()
{
    Square s;
    Circle c;
    cout << (
    s.getData();
    cout << (
    cout << (
    c.getData();
    cout << "مساحة الدائرة: " << c.calculateArea();
    return 0;
}

النتيجة الصادرة

أدخل الطول لتحديد مساحة المربع: 4
مساحة المربع: 16
أدخل نصف القطر لتحديد مساحة الدائرة: 5
مساحة الدائرة: 78.5

في هذا البرنامج، تم تعريف الوظيفة المجردة virtual float area() = 0; في الفئة Shape.

شيء يجب مراعاته هو أنك يجب أن تعيد كتابة الوظائف المجردة في الفئة المشتقة. إذا فشلت في إعادة الكتابة، فإن الفئة المشتقة也将 تصبح فئة مجردة.