loading...
دانلود سرای دانشجویی

سازنده ها و مخرب ها در وراثت

کلاس پايه و مشتق شده هر يک می تواند شامل توابع سازنده و مشتق شده باشند. وقتی شیئی ايجاد می شود کامپايلر تضمين می کند که کليه سازنده ها فراخوانی می شوند. در سلسله مراتب وراثت فراخوانی سازنده ها از ريشه شروع می شود. در هر سطح ابتدا سازنده کلاس پايه سپس سازنده کلاس مشتق شده فراخوانی می شود. مخرب ها برعکس ترتيب فراخوانی سازنده ها فراخوانی می شوند.

مثال. در برنامه زير کلاس Derived2 از کلاس Derived1 که خود از Base1 ارث بری دارد ارث می برد.

#include <iostream.h>
class Base1 {
   int x;
public:
   Base1 () {cout << "Base1 constructorn";}
   ~Base1() {cout << "Base1 destructorn";}
};
class Derived1 : public Base1 {
   int y;
public:
   Derived1() { cout << "Derived1 constructorn";}
   ~Derived1() { cout << "Derived1 destructorn";}
};
class Derived2 : public Derived1 {
   int z;
public:
   Derived2() { cout << "Derived2 constructorn";}
   ~Derived2() { cout << "Derived2 destructorn";}
};
int main() {
   Derived2 d2;
   return 0;
}

خروجی برنامه به صورت زير است:

Base1 constructor
Derived1 constructor
Derived2 constructor
Derived2 destructor
Derived1 destructor
Base1 destructor


نکته. ترتيب فراخوانی سازنده ها و مخرب ها در در توارث چندگانه هم صدق می کند. سازنده ها به ترتيبی که در ليست مشخص شده اند از چپ به راست فراخوانی می شوند. و مخرب ها برعکس.


ارسال پارامتر به سازنده کلاس پايه

زمانی که تنها سازنده کلاس مشتق شده دارای آرگومان است می توان به سادگی و به صورت متعارف آرگومان را به سازنده ارسال نمود. اما برای ارسال آرگومان به سازنده کلاس پايه دچار مشکل می شويد چون سازنده کلاس مشتق شده به داده خصوصی کلاس پايه دسترسی ندارد و نمی تواند آنها را مقداردهی کند. برای اين کار C++ گرامری را در اختيار می گذارد که ليست مقداردهی سازنده (constructor initializer list) نام دارد. ليست مقداردهی سازنده امکان فراخوانی صريح سازنده ها از اشيای عضو را می دهد. فرم کلی آن برای سازنده کلاس مشتق شده به صورت زير است:

Derived(arg_list) : Base1(arg_list), Base2(arg_list), ...
{ //body of derived constructor}

نام کلاس های پايه توسط کاما از هم جدا می شوند. Base1 و Base2 و ... نام کلاس های پايه هستند که توسط کلاس مشتق شده Derived به ارث برده می شوند. سازنده ها همگی قبل از اينکه وارد بدنه سازنده کلاس مشتق شده شويد فراخوانی می شوند.


مثال. کلاس Circle از کلاس Point مشتق شده است. در سازنده کلاس Circle سازنده Coint فراخوانی می شود.

#include <iostream.h>
class Point {
   int x,y;
public:
   Point(int atx,int aty ) {x = atx; y = aty;}
   ~Point(){ cout << "Point Destructor calledn";}
   virtual void Draw() { cout << "Draw point at " << x << " " << y << endl;}
};
class Circle : public Point {
   int radius;
public:
   Circle(int atx, int aty, int theRadius) ;
   ~Circle() ;
   virtual void Draw() ;
};
Circle::Circle(int atx,int aty,int theRadius) : Point(atx,aty) {
   radius = theRadius;
}
inline Circle::~Circle() {
   cout << "Circle Destructor called" << endl;
}
void Circle::Draw( void ) {
   Point::Draw();
   cout << "circle::Draw point " << " Radius " << radius << endl;
}
int main() {
   Circle ACircle(10,10,5) ;
   ACircle.Draw();
   return 0;
}


برخلاف اينکه اغلب نياز است سازنده ها به صورت مستقيم در ليست مقداردهی فراخوانی شوند، مخرب ها نيازی به فراخوانی صريح ندارند زيرا هر کلاس تنها يک مخرب بدون هيچ آرگومانی دارد. کامپايلر کليه مخرب ها را از آخرين کلاس مشتق شده به سمت ريشه در کل سلسله مراتب وارثت اجرا می کند.

کنترل دسترسی به اعضای کلاس پايه

کلاس مشتق شده کليه اعضای کلاس پايه را به ارث می برند اما اجازه دسترسی مستقيم به اعضای خصوصی کلاس پايه را ندارند و تنها از طريق توابع عمومی و سازنده به آنها دسترسی دارند.

نحوه دسترسی به اعضای عمومی کلاس پايه در کلاس مشتق شده توسط يکی مجوزهای دسترسی زير که قبل از نام کلاس پايه ذکر می شود مشخص می شود:

• public
• private
• protected

توارث عمومی

با ذکر کلمه public قبل از نام کلاس پايه اعضای عمومی کلاس پايه به عنوان اعضای عمومی کلاس مشتق شده تلقی می شوند و در اختيار کاربر کلاس مشتق شده قرار می گيرد.


مثال. در مثال قبل تابع value از کلاس Base به اعضای عمومی Derived اضافه می شود بنابراين در برنامه قابل دسترسی است.


توارث خصوصی

با حذف کلمه public يا صريحا با ذکر کلمه private يک کلاس پايه می تواند به صورت خصوصی ارث گرفته شود. در توارث خصوصی کلاس مشتق شده کليه اعضای کلاس پايه را دارا خواهد بود اما به صورت مخفی و اعضای عمومی کلاس پايه اعضای خصوصی کلاس مشتق شده خواهند شد. بنابراين يک شی به عنوان يک نمونه از کلاس نمی تواند به اعضای کلاس پايه دسترسی پيدا کند.

نکته. توارث خصوصی برای پنهان کردن لايه زيرين پياده سازی کلاس پايه مفيد است.
نکته. در توارث خصوصی کليه اعضای عمومی کلاس پايه خصوصی می شوند. اگر می خواهيد عضوی قابل رويت شود کافی است نام آن را (بدون آرگومان و مقدار برگشتی) در بخش public کلاس مشتق شده ذکر کنيد.


مثال. چون وراثت خصوصی است تابع speak از کلاس پايه Pet در برنامه قابل دسترس نيست درحاليکه توابع eat و sleep از کلاس پايه به صورت قابل دسترس درآمده اند.

class Pet {
public:
   char eat() { return 'a'; }
   int speak() { return 2; }
   float sleep() { return 3.0; }
   float sleep(int) { return 4.0; }
};
class Goldfish : Pet {      // Private inheritance
public:
   Pet::eat;      // Name publicizes member
   Pet::sleep;      // Both overloaded members exposed
};
int main() {
   Goldfish bob;
   bob.eat();
   bob.sleep();
   bob.sleep(1);
//! bob.speak();      // Error: private member function
}


توارث محافظت شده

اعضای خصوصی هميشه خصوصی هستند اما گاهی می خواهيد اعضائی را از خارج مخفی کنيد ولی در کلاس مشتق شده قابل رويت باشند. کلمه protected می گويد که اعضای محافظت شده برای هر کسی که از اين کلاس ارث می برد قابل دسترس است و برای بقيه خصوصی است.

مثال. توابع set و read از کلاس Base درمثال قبل در کلاس مشتق شده Derived قابل رويت هستند ولی در برنامه مخفی هستند.

با قرار دادن کلمه protected قبل از نام کلاس مشتق شده اعضای محافظت شده و عمومی کلاس پايه به اعضای محافظت شده کلاس مشتق شده اضافه خواهند شد. بنابراين برای وارثين کلاس مشتق شده در دسترس است و برای بقيه پنهان باقی می ماند

نکته. در کليه حالات اعضای خصوصی کلاس پايه در وراثت شرکت نمی کنند و خصوصی باقی می مانند.
نکته. معمولا توارث عمومی است تا رابط کلاس پايه همچنان رابط کلاس مشتق شده باشد.
نکته. توارث محافظت شده خيلی استفاده نمی شود و فقط برای تکميل زبان برنامه نويسی است.
نکته. مناسب ترين روش اين است که اعضای داده ای کلاس را صورت خصوصی تعريف کنيد تا امکان تغيير پياده سازی زيرين حفظ شود. و به وارثين کلاس مجوز دسترسی کنترل شده ای به توابع عضو محافظت شده بدهيد.

تعريف کلاس مشتق شده

فرم کلی تعريف يک کلاس مشتق شده به صورت زير است:

class derived : access base
{
   //members of new class;
}

derived نام کلاس جديد است که از کلاس پايه base مشتق شده است. قسمت access اختياری است ولی می تواند public، private يا protected باشد و برای تعيين مجوز دسترسی اعضای کلاس پايه در کلاس جديد بکار می رود. اگر مجوز دسترسی ذکر نشود به اين معنی است که کليه اعضای عمومی کلاس پايه در کلاس مشتق شده به صورت خصوصی خواهند بود.


مثال. کلاس جديد Derived از کلاس Base مشتق شده است. در برنامه اصلی تابع change از کلاس Derived فراخوانی شده که خود دو تابع set و read از کلاس Base را صدا می زند.

#include <iostream.h>
class Base {
   int i;
protected:
   int read() { return i; }
   void set(int ii) { i = ii; }
public:
   Base() { i=0; }
   int value(int m) { return m*i; }
};
class Derived : public Base {
   int j;
public:
   Derived() { j=0; }
   void change(int x) { set(x); cout << read(); }
};
int main() {
   Derived d;
   d.change(10);
   return 0;
}

کلاس های پايه و مشتق شده

چند کلاس ممکن است خصوصيات و رفتارهای مشترکی داشته باشند اما هريک شامل خواص و توابع ديگری هم باشد. وراثت اجازه می دهد يک کلاس عمومی تعريف شود که اشيا درخصوصيات آن مشترک هستند و اين کلاس می تواند توسط ساير کلاس ها ارث برده شود و خواص جديدی به آن اضافه شود بدون اينکه تاثيری روی کلاس عمومی داشته باشد.

توارث شباهت بين دو کلاس را با استفاده از مفاهيم کلاس پايه (base) و کلاس مشتق شده (derived) بيان می کند. کلاسی که از آن ارث بری می شود کلاس پايه يا مبنا و کلاس وارث که خصوصيات کلاس پايه را به ارث می برد را کلاس مشتق شده می نامند. کلاس پايه شامل کليه خواص و رفتارهائی است که بين کلاس های مشتق شده مشترک است.


مثال. کلاس پايه shape را درنظر بگيريد که دارای خاصيت های اندازه، رنگ و موقعيت است. هر شکل می تواند رسم شود، پاک شود، حرکت کند و رنگ شود. هر کدام از اشکال دارای خواص و رفتارهای اضافه تری هستند. برای يک شکل معين بعضی رفتارها ممکن است متفاوت باشد مثلا محاسبه مساحت.


نکته. يک کلاس متشق شده به نوبه خود می تواند کلاس پايه برای ساير کلاس ها باشد.
نکته. اگر کلاس پايه تغيير کند کلاس مشتق شده نيز تحت تاثير اين تغييرات قرار می گيرد.

آرايه ای از اشيا

می توان به همان طريقی که آرايه ای از ساير انواع داده ايجاد می شود آرايه ای از اشيا تعريف کرد. اگر کلاس دارای تابع سازنده همراه با پارامتر باشد آرايه ای از اشيا را می توان مقداردهی کرد.


مثال. myarray آرايه ای از اشيا است که در برنامه اصلی با چهار عدد مقداردهی شده و نمايش داده می شود.

#include <iostream.h>
class display {
   int number;
public:
   display(int n) {this->number=n;}
   int show() { cout << this->number << endl; }
};
int main() {
   display myarray[4] = {1,2,3,4,};
   for (int i = 0; i < 4 ;i++ )
      myarray[i].show();
   return 0;
}


هر بار که تابع عضوی فراخوانی می شود به طور خودکار اشاره گری به نام this را به شیئی که آن را فراخوانی کرده است ارسال می کند. اشاره گر this يک پارامتر ضمنی برای تمام توابع عضو است و داخل تابع برای رجوع به شیء فراخواننده می تواند مورد استفاده قرار گيرد.

سازنده ها

معمولا بعضی از اعضای کلاس قبل از استفاده نیاز به مقداردهی دارند. اين عمل توسط سازنده (constractor) انجام می گیرد که به شیء اين امکان را می دهد که هنگام ايجاد مقداردهی شود. سازنده تابعی است هم اسم کلاس که وقتی یک نمونه از کلاس گرفته می شود اتوماتیک فراخوانی می شود.

تابع سازنده می تواند دارای پارامتر باشد بنابراين زمان ايجاد شیء می توان به متغيرهای عضو مقادير اوليه داد. برای ارسال آرگومان به تابع سازنده بايد هنگام تعريف شیء مقدار آرگومان بعد از نام شیء درون پرانتز قرار گيرد.

یک کلاس می تواند دارای چند سازنده با پارامترهای مختلف باشد. بهتر است همیشه حداقل یک سازنده حتی اگر خالی باشد ساخته شود.

برای تابع سازنده مقدار برگشتی ذکر نمی شود (حتی viod).


مخرب ها

تابع مخرب کلاس (destructor) کم و بیش عکس سازنده عمل می کند. یک مخرب وقتی فراخوانی می شود که یک شی از بین می رود. یک مخرب مشابه سازنده ساخته می شود فقط قبل از اسم آن علامت مد (~)قرار می گیرد. تابع مخرب اتوماتیک وقتی متغیر شیء از حوزه دسترسی خارج می شود (برای متغیرهای سراسری وقتی از تابع اصلی خارج می شود و برای متغیر محلی هنگام خروج از بلاک تابع) فراخوانی می شود.

مشابه سازنده ها تابع مخرب نيز نوع برگشتی ندارد.


مثال. توابع myclass در کلاس زير سازنده هستند. تابع ~myclass يک مخرب است که در انتهای تابع اصلی فراخوانی می شود و فايل متن را می بندد.

#include <fstream.h>
#include <iostream.h>
#include <string.h>
class myclass {
private:
   char msg[20];
   int loopcounter;
   fstream myfile;
public:
   void greeting();
   myclass();      // Constructor
   myclass(char greeting[20]); // Constructor
   ~myclass()    // Destructor
};
myclass::myclass(){
   myfile.open("input.txt",ios::in);
   myfile.getline(msg,20);
}
myclass::myclass(char greeting[20]) {
   strcpy(msg,greeting);
}
myclass::~myclass(){
   myfile.close();
}
void myclass::greeting(){
   cout << msg << "n";
}
int main (){
   myclass myobject;
   myobject.greeting();
   return 0;
}

در برنامه فوق هنگام ايجاد شیء myobject تابع سازنده فراخوانی شده خطی را از فايل متن خوانده و به متغير عضو تابع اختصاص می دهد. اگر در برنامه اصلی شیء به صورت زير ايجاد شود سازنده دوم فراخوانی می شود و مقدار آرگومان را به متغير msg اختصاص می دهد.

myclass myobject("Howdy from Texas!");


اغلب کلاس ها را در فایل های هدر تعریف می کنند. ترکیب کلاس و فایل هدر سطح بالاتری از قابلیت استفاده مجدد کد را فراهم می کند و می توان آن را در هر فایلی که به کلاس نیاز دارید ضمیمه کنید.

کلاس

کلاس

همانطور که قبلا دیدید ساختمان ها نوع داده جدیدی را ایجاد می کنند. کلاس ها به طور مشابه روش قدرتمند تری برای ایجاد يک نوع داده جدید هستند. وقتی یک کلاس تعریف می شود در اصل نوع داده جدیدی ساخته می شود که فيلدها و توابع خود را دارد. کلاس به عنوان قالبی برای تولید شی بکار می رود بنابراين از خود کلاس در برنامه استفاده نمی شود بلکه یک نمونه از آن که شیء ناميده می شود اعلان می شود. فرآیند تولید یک نمونه از کلاس یا ایجاد یک شی از کلاس به این معنا است که یک متغیر از نوع کلاس اعلان شود.

کلاس مشابه ساختمان تعریف می شود فقط کافی است ابتدای آن کلمه کلیدی class ذکر شود. دقت کنید در انتهای بلاک علامت سمیکولن را فراموش نکنید.

class classname
{
// members
};

وقتی یک کلاس ایجاد می کنید مانند هر متغیر دیگر می توانید یک نمونه از آن را بگیرید:

classname object_variable;


مثال.

class myclass {
   int number;
   void greeting();
};


حوزه اعضای کلاس

هر عضو ساختمان یا کلاس می تواند عمومی(public)، خصوصی (private) یا محافظت شده (protected) باشد. به طور پيش فرض تمام اعضای کلاس خصوصی هستند و امکان دسترسی به آنها خارج از کلاس ممکن نیست مگر اینکه توسط حوزه های دسترسی به عنوان عموی یا محافظت شده تعریف شوند.

حوزه های دسترسی (access modifiers) توسط کلمات زیر مشخص می شوند:

• private. اعضايی که به صورت خصوصی مشخص می شوند تنها درون کلاس توسط توابع عضو و توابع دوست قابل دسترسی هستند و نمی توانند خارج از کلاس دسترسی شود.
• public. اعضای عمومی از هر تابعی حتی خارج از کلاس قابل دستیابی هستند.
• protected. اعضای محافظت شده نمی توانند بیرون از کلاس دسترسی شوند اما توسط توابع عضو خودش و توابع دوست و از کلاسی که از آن مشتق شده قابل دسترسی هستند.

نکته. در یک ساختمان همه اعضا عمومی هستند مگر اینکه آنرا به عنوان خصوصی یا محافظت شده تعریف کنید.


مثال. متغير number عضو خصوصی و تابع greeting خضو عمومی کلاس زير هستند.

class myclass {
   int number;
public:    void greeting();
};


نکته. در یک ساختمان همه اعضا عمومی هستند مگر اینکه آنرا به عنوان خصوصی یا محافظت شده تعریف کنید.


مثال. در ساختمان A توابع عضو به صورت عمومی تعريف شده اند و فيلدها به صورت خصوصی هستند.

struct A {
private:
   int i, j, k;
public:
   int f() {return i + j + k;}
   void g() {i = j = k = 0;}
};


توابع عضو

توابع عضو (member functions) توابعی هستند که درون کلاس تعريف می شوند و متعلق به کلاس هستند. توابع عضو می توانند به کلیه اعضای کلاس (اعم از عمومی، خصوصی و محافظت شده) بدون هیچ محودیتی دسترسی پیدا کنند.


مثال. تابع greeting تابع عضو کلاس است که به متغير خصوصی عضو number دسترسی دارد.

class myclass {
   int number;
public:
   void greeting() {
      for(int i = 0; i<= number;i++) cout << "Hello World n";
   }
};


در مثال فوق کد تابع عضو به صورت درونی (inline) در کلاس قرار داده شده است. توابع درونی درنقطه فراخوانی به صورت خطی گسترش پيدا می کند به جای اينکه واقعا فراخوانی شود. توابع درونی درصورتی که بدنه تابع کوچک باشد روش کارآمدتری هستند. راه ديگر تعريف تابع عضو اين است که بدنه تابع بعد از بلاک کلاس قرار گيرد. سپس برای ارتباط تابع عضو با کلاس قبل از نام تابع نام کلاس بدنبال علامت (::) بايد ذکر شود. :: عملگر حوزه (scope operation) نام دارد و بيان کننده اين است که تابع متعلق به کلاس است.


مثال. کلاس فوق را به صورت زير نيز می توان نوشت.

class myclass {
   int number;
public:
   void greeting();
};
void myclass::greeting(){
   for(int i = 0; i<= number;i++)
      cout << "Hello World n";
}


توابع دوست

توابع دوست (friend function) توابعی هستند که عضو کلاس نيستند اما به اعضای خصوصی کلاس دسترسی دارند. برای ايجاد يک تابع دوست در کلاس پروتوتايپ تابع را در بخش عمومی کلاس قرار داده و قبل از آن کلمه friend استفاده کنيد.


مثال. دربرنامه زير پيغام سه بار نمايش داده می شود. تابع set يک تابع دوست است که برای مقداردهی متغير خصوصی عضو کلاس استفاده شده است.

#include <iostream>
class myclass {
   int number;
public:
   void greeting();
   friend void set(myclass, int);
};
void myclass::greeting(){
      for(int i = 0; i<= number;i++)
         cout << "Hello World n";
}
void set(myclass n, int value){
   n.number=value;
}
int main () {
   myclass myobject;
   set(myobject, 3);
   myobject.greeting();
   return 0;
}


نکته. يک تابع ممکن است دوست بيش از يک کلاس باشد.

مفاهيم شی گرائی

برنامه نویسی شیءگرائی (object oreinted programming) وسیله ای برای مدل کردن صحیح دنیای واقعی با استفاده از اشیا (objects) در برنامه و استفاده مجدد از کد است. یک شی در برنامه دقیقا همان طور تعريف می شود که در دنيای واقعی است؛ خواص معینی دارد که آن را توصیف می کند و متدهایی که می توانید برای انجام کار معینی روی شیء استفاده کنید.

هدف کلی C++ اضافه کردن شیءگرائی به زبان برنامه نویسی C است. یک شیء برای نگهداری داده استفاده می شود. داده و توابعی که روی داده کار می کنند به هم مربوط هستند بنابراين داده و توابع هردو با هم دریک بسته قرار می گیرند. شیءگرائی بيشتر روی داده تاکيد دارد تا عمليات و توابعی که روی داده کار می کنند.

مثال. ماشین یک شی است دارای خواصی مثل رنگ، تعداد درها و غیره است متدهای معینی دارد مانند سرعت گرفتن، ترمز کردن و غیره. می توان این شی را با استفاده از متدهایش استفاده کرد.

شرحی از داده ها و توابعی که می توانند روی داده کار کنند را کلاس (class) می نامند. کلاس را به عنوان الگوئی برای توليد شیء می توان تصور کرد. کلاس در واقع يک نوع داده user-defined است . اشياء نمونه هائی از کلاس ها هستند که در زمان اجرا ايجاد می شوند.

چهار مفهوم اصلی وجود دارند که اساس برنامه نویسی شیءگرائی را می سازند و توسط کلاس ها ارائه می شوند. این مفاهیم انتزاع (abstraction)، کپسوله کردن (encapsulation)، توارث (inheritance) و چندریختی (polymorphism) هستند.

انتزاع

شیء گرائی ابزاری را برای برنامه نویس فراهم می کند که اجزای فضای مسئله را توسط اشيا نمایش دهد. مسئله به بخش های تشکيل دهنده تجزيه می شود. هر مولفه يک شیء می شود که شامل داده های مرتبط و دستورالعمل های خود است. به اين ترتيب مسئله به همان صورتی که در دنيای واقعی هست توصیف می شود نه به روشی کامپیوتری که مسئله را حل می کند. یعنی می توانید با همه چيز در یک ترتیب کلی سروکار داشته باشید. پيچيدگی عمليات کاهش يافته و جزييات پياده سازی مخفی می ماند.


مثال. درباره خصوصیات کلی وسيله نقليه بدون سروکارداشتن با یک وسيله و مدل خاص می توان بحث کرد. يک نمونه شیء MyVehicle از کلاس Vehicle که خواص کلی و توابع وسايل نقليه را در بر دارد می توان ايجاد کرد. تابع Print مشخصات کلی وسيله نقليه را نمايش می دهد.

Vehicle MyVehicle;
MyVehicle.Print();


کپسوله کردن

قرار دادن داده و توابعی که روی داده کار می کنند را در یک بسته کپسوله کردن می گویند. در برنامه نویسی رویه گرا (مشابه آنچه تا کنون انجام می داديد) معلوم نیست چه تابعی روی چه متغیری کار می کند. در برنامه های پیچیده تر این روابط تیره تر می شوند. در برنامه نویسی شیءگرائی داده و توابع مربوط به آن- که اغلب متد (method) ناميده می شوند- با در يک بسته به نام کلاس قرار می گیرند بنابراین کاملا مشخص است چه تابعی روی چه داده ای کار می کند.

کپسول کردن امکان پنهان کردن اطلاعات را نيز فراهم می کند. هر عضو کلاس را می توان به صورت عمومی، خصوصی یا محافظت شده مشخص کرد. شی ايجاد شده از کلاس به داده از طريق يک سری توابع عمومی دسترسی دارد و اجازه دسترسی مستقيم به اعضای خصوصی کلاس و خراب کردن آنها داده نمی شود. به اين صورت جزئيات پياده سازی هم مخفی می ماند و به طراح اجازه می دهد پياده سازی را اساسی بدون تغيير در واسطه ها عوض کند.

وراثت

یکی ديگر از جنبه های مفید برنامه نویسی شیءگرائی قابلیت استفاده مجدد از کد است. یک کلاس می تواند اعضای عمومی را از کلاس دیگر را به ارث ببرد. توارث اجازه می دهد کلاس جديدی شامل کليه داده ها و توابع کلاس (های) پياده سازی شود. کلاس موجود را کلاس پايه (base) و کلاس جديد که اعضای کلاس پايه را به ارث می گيرد را کلاس مشتق شده (derived) می نامند.


مثال. فرض کنيد يک کلاس پايه به نام Vehicle برای وسايل نقليه داريم. وسيله نقليه می تواند ماشين، تراکتور، قايق و هواپيما را شامل شود که ممکن است هر يک از آنها احتياج به اطلاعات يا توابع اضافی داشته باشند. بنابراين می توان برای هر کدام کلاس های فرعی را تعريف کرد که خواص کلاس Vehicle را به ارث می برند علاوه براين که دارای فيلدهای جديد ديگری هم هستند.


اگر کلاس ويژگی های تنها يک کلاس را به ارث ببرد وارثت منفرد(single inheritance) و اگر از چند کلاس به ارث گرفته شود وارثت چندگانه (multiple inheritance) ناميده می شود.

ارث از کلاس پایه ممکن است به صورت عمومی، خصوصی یا محافظت شده باشد. این مشخصه های دسترسی تعیین می کنند کلاس های مشتق شده می توانند به اعضای عمومی و محافظت شده کلاس پایه دسترسی پیدا کنند یا خیر. تنها وراثت عمومی است که با مفهوم توارث تطبیق دارد. دو فرم دیگر کمتر استفاده می شوند.

چندریختی

يک تابع در سلسله مراتب کلاس ها و زير کلاس ها می تواند به طرق مختلف پياده سازی شود و شکل های متعددی بگیرد. چندریختی یک رابط مشترک را برای پیاده سازی های مختلف از يک تابع در اختيار می گذارد که برای اشیا تحت شرایط مختلف متفاوت عمل کند. به عبارت ديگر فراخوانی تابعی که متعلق به کلاس است هميشه به شکل زير خواهد بود.

object.function(parameter-list)


مثال. در مثال قبل تابع نمايش برای قايق ممکن است متفاوت از نمايش يک وسيله نقليه باشد. دو تابع می توانند هم نام باشند ولی با کدهای متفاوت بسته به کلاس شیئی که تابع را فراخوانی می کند.

Vehicle MyVehicle;
Boat YourBoat;
MyVehicle.Print();
YourBoat.Print();


در مثال قبل کامپايلر نوع تابع print را برای دو نوع فراخوانی شده بر اساس نوع شیء می تواند پيدا کند. اما گاهی پيدا کردن آن تا زمان اجرای واقعی برنامه ممکن نيست. مشکل زمانی بروز می کند که به شیء از طريق اشاره گر دسترسی می شود و چون اشاره گرها می توانند بطور پويا به انواع مختلفی از اشيا اشاره کنند کلاس شیء تا زمان اجرا مشخص نمی شود. برای حل اين موضوع توابع عضو مجازی بکار می روند. توابع مجازی عضو (Virtual member functions) اجازه پياده سازی خاص تری از تابعی که فراخوانی می شود را مطابق با نوع شیء زمان اجرا می دهند.

دسترسی تصادفی فايل

هر فايل بازی يک انديکاتور موقعيت دارد که تعيين می کند عمل خواندن/نوشتن در کدام محل فايل انجام می شود. موقعيت هميشه برمبنای تعداد بايت ها از ابتدای فايل داده می شود. اگر فايل موجودی در مد اضافه کردن باز شود انديکاتور در انتهای فايل است در بقيه مدها انديکاتور در ابتدای فايل است و برابر صفر است.

توابع خواندن/نوشتن روی فايل که در محل انديکاتور انجام می شود باعث تغيير موقعيت آن می شود. مثلا اگر فايلی باز شود و 10 بايت از آن خوانده شود انديکاتور روی موقعيت 10 فايل قرار می گيرد. عمل بعدی روی موقعيت 10 انجام می گيرد.

C++ توابعی را در اختيار می گذارد (seekp و seekg) که امکان کنترل انديکاتور و دسترسی تصادفی به فايل را می دهند. يعنی می توانيد به هر نقطه ای درون فايل مراجعه کنيد بدون اينکه مجبور باشيد فايل را از ابتدا بخوانيد يا بنويسيد.


مثال. نمايش اندازه يک فايل.

#include <fstream.h>
#include <iostream.h>
int main () {
   long start,end;
   ifstream myfile (“test.txt”, ios::in|ios::binary);
   start = myfile.tellg();
   myfile.seekg (0, ios::end);
   end = myfile.tellg();
   myfile.close();
   cout << "size of " << “test.txt”;
   cout << " is " << (end-start) << " bytes.n";
   return 0;
}

فایل های متنی

فايل های متنی مورد استفاده بسياری دارند. يک فايل متنی (text file) جريانی از کاراکترهاست که دارای کاراکتر(های) خاصی برای نشانه گذاری انتهای هر خط است. فايل های متنی را با هر اديتورمتنی می توان توليد کرد يا محتويات آن را مشاهده کرد.


مثال. ايجاد يک فايل متنی با نام test.txt.

#include <fstream.h>
int main() {
   ofstream myfile ("test.txt");
   if (myfile.is_open()){
      myfile << "This outputting a line.n";
      myfile << "Guess what, this is another line.n";
      myfile.close();
      }
   return 0;
}

مثال. خواندن فايل متنی test.txt و نمايش آن روی صفحه.

#include <fstream.h>
#include <iostream.h>
int main (){
   char buffer[256];
   ifstream myfile ("test.txt");
   while (! myfile.eof() ) {
      myfile.getline (buffer,100);
      cout << buffer << endl;
   }
   return 0;
}


در فايل های متنی می توانيم اعداد را هم ذخيره کنيم. اعداد به صورت متن ذخيره می شوند. برای مثال عدد 236 به صورت کاراکتر'2' ، کاراکتر '3' و کاراکتر '6' ذخيره می شود. اين تبديل زمان اضافه می برد اما فايل حاصل قابل خواندن است.


فایل های باینری

فایل های باینری هم نوعی فايل مسطح هستند که در حالت دودوئی ذخیره می شوند. در حالت باینری هر فایل یک فرمت بایت به بایت دارد که باعث می شود فايل در ادیتور اسکی خوانا نباشد و کاراکترهای عجیبی نشان داده شود.

تابع write برای نوشتن داده در فايل باينری استفاده می شود. تابع دارای دو پارامتر است. اولی آدرس جائی که داده بايد نوشته شود و دومی تعداد بايت های داده است که نوشته می شود. تابع read برای خواندن از فايل باينری است.

تعداد صفحات : 425

اطلاعات کاربری
آمار سایت
  • کل مطالب : 4247
  • کل نظرات : 0
  • افراد آنلاین : 8
  • تعداد اعضا : 2926
  • آی پی امروز : 69
  • آی پی دیروز : 161
  • بازدید امروز : 493
  • باردید دیروز : 830
  • گوگل امروز : 8
  • گوگل دیروز : 51
  • بازدید هفته : 493
  • بازدید ماه : 35,434
  • بازدید سال : 110,543
  • بازدید کلی : 8,289,237
  • کدهای اختصاصی