مبانی ++C برای یادگیری ساختمان داده — به زبان ساده

۲۰۰ بازدید
آخرین به‌روزرسانی: ۱۸ شهریور ۱۴۰۲
زمان مطالعه: ۷ دقیقه
مبانی ++C برای یادگیری ساختمان داده — به زبان ساده

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

997696

آشنایی با مبانی ++C

++C یکی از زبان‌های برنامه‌نویسی شیءگرا است. برنامه‌نویسی شیءگرا خصوصیاتی مانند «کپسوله‌سازی»، «وراثت»، «چندریختی» و «تجرید» دارد. کپسوله‌سازی در مورد دریافت داده‌ها و نگهداری امن و مطمئن آن‌ها در برابر دخالت بیرونی است. این کار از این طریق صورت می‌گیرد که تنها به تابع‌های درون کلاس اجازه می‌دهیم که متغیرها را تغییر دهند. یکپارچه‌سازی داده‌ها و متد (عملیات) در یک واحد منفرد (کلاس) و استفاده از Modifier دسترسی (یعنی public ،private یا protected) دو جنبه مهم کپسوله‌سازی هستند. درک STL ساخته شده در ++C و استفاده از آن نیز حائز اهمیت است.

اشاره‌گر شیء

برای توضیح این مفهوم از دو فایل نمونه استفاده می‌کنیم که کدهای آن را در ادامه می‌بینید. فایل CircleClass.cpp به صورت زیر است:

1#include <iostream>
2using namespace std;
3
4class Circle {
5  int radius;
6public:
7  Circle() { radius = 1; }
8  Circle(int i) { radius = 1; }
9  double getArea();
10};
11
12double Circle::getArea() {
13  return 3.14*radius*radius;
14}

فایل ObjectPointer.cpp به صورت زیر است:

1int main() {
2  Circle baseketball;
3  
4  //Access member variable by object name
5  cout<<baseketball.getArea()<<endl;
6  
7  //Access by object pointer
8  Circle *p;
9  p=&baseketball;
10  cout<<p->getArea()<<endl;
11  cout<<(*p).getArea()<<endl;
12}
1int a = 10;
2int *pa; // pointer variable *pa
3pa = &a; // address value &a

با به یاد آوردن مفهوم یک اشاره‌گر می‌دانیم که مقدار a و a* هر دو 10 هستند. اشاره‌گر شیء می‌تواند در مثال فوق به صورت p* که برای اشاره به شیء یک دونات استفاده می‌شود نیز مورد توجه قرار گیرد. برای تغییر دادن متغیر، عضو خصوصی دونات شیء باید به یکی از صورت‌های زیر باشد:

p->getArea()

یا

(*p).getArea

یا

donut.getArea()

اما نباید به صورت p->radius باشد.

آرایه شیء

به کدهای زیر توجه کنید.

فایل ObjectArray.cpp

1int main() {
2  Circle circleArray[3]; //creating Circle object class
3  
4  //access elements of object class
5  circleArray[0].setRadius(10);
6  circleArray[1].setRadius(20);
7  circleArray[2].setRadius(30);
8  
9  for(int i=0; i<3; i++) { //access each member variable
10    cout<<"Area of Circle"<<i<<" is "<<circleArray[i].getArea()<<endl;
11    
12  Circle *p;
13  p = CircleArray;
14  for(int i=0; i<3; i++) //accessing array by object pointer
15    cout<<"Area of Circle"<<i<<" is "<<p->getArea()<<endl;
16    p++;
17  }
18}

به طور مشابه در آرایه شیء می‌توان به وسیله

 circleArray[0].getArea()

یا

 p->getArea()

به مشخصه‌های خصوصی دسترسی داشت.

1#include <iostream>
2using namespace std;
3
4class Color {
5  int red, green, blue;
6public:
7  Color() { red = green = blue = 0; }
8  Color(int r, int g, int b) { red = r; green = g; blue = b; }
9  void setColor(int r, int g, int b) { red = r; green = g; blue = b; }
10  void show() { cout<<red<<' '<<green<<' '<<blue<<endl; }
11};

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

1int main() {
2  Color screenColor(255, 0, 0); //creating red color object
3  Color *p; //object pointer *p in Color type
4  
5  //(1)makep have screenColor address
6  p = &screenColor;
7  
8  //(2)use p and show() to print color of screenColor
9  p->show();
10  
11  //(3)declare one-dimensional array colors with 3 elements
12  Color colors[3];
13  
14  //(4)make p to point array colors
15  p = colors;
16  
17  //(5)use setColor() to change colors[0], colors[1], colors[2] to red, green, blue
18  p->setColor(255, 0, 0);
19  p->setColor(0, 255, 0);
20  p->setColor(0, 0, 255);
21  //or
22  p[0].setColor(255, 0, 0);
23  p[1].setColor(0, 255, 0);
24  p[2].setColor(0, 0, 255);
25    
26  //(6)use show() to print colors of array colors
27  for(int i=0; i<3; i++) {
28    p[i].show();
29  }
30  //or
31  for(int i=0; i<3; i++) {
32    p->show();
33    p++;
34  }
35}

تخصیص استاتیک در برابر تخصیص دینامیک

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

زمانی که مقدار دقیق مورد نیاز برای تخصیص را ندانیم باید از تخصیص دینامیک استفاده کنیم.

1int a; int a[100]; //variables are allocated instantly when compile is done and saved in stack
2int *pInt = new int; //variables are allocated during the program execution
3Circle *pCircle = new Circle();
4delete pInt;
5delete pCircle;

در ++C از کلیدواژه new،delete برای تخصیص دینامیک استفاده می‌شود و همواره از اشاره‌گر برای تخصیص دینامیک بهره می‌گیریم. استفاده از آن نیز وضعیت مشابهی دارد. پس از استفاده از حافظه با تخصیص دینامیک باید حتماً آن را حذف کنید.

1#include <iostream>
2using namespace std;
3
4class Circle {
5	int radius;
6public:
7	Circle(); //constructor
8	Circle(int r); //constructor
9	~Circle(); //destructor
10
11	void setRadius(int r) { radius = r; }
12	double getArea() { return 3.14*radius*radius; }
13};
14
15Circle::Circle(){
16	radius = 1;
17	cout << "Constructor execute radius=" << radius << endl;
18}
19
20Circle::Circle(int r){
21	radius = r;
22	cout << "Constructor execute radius=" << radius << endl;
23}
24
25Circle::~Circle(){
26	cout << "Destructor execute radius=" << radius << endl;
27}

سازنده، تخصیص دینامیک و حذف

1Circle *q = new Circle(30);
2delete q;
3//dynamic array of objects
4Circle *p = new Circle[30];
5delete [] p;

در کدهای زیر نمونه‌هایی از این مفاهیم را مشاهده می‌کنید:

1class Circle {
2  int raidus;
3public:
4  void setRadius(int radius);
5  double getArea();
6};
7
8void Circle::setRadius(int radius) {
9  this->radius = radius;
10}
11
12void Circle::getArea() {
13  return 3.14*radius*radius;
14}

دینامیک آرایه کلاس

1int main() {
2  Circle *p;
3  int size;
4  cout<<"Number of Circle >> ";
5  cin>>size;
6  if(size < 1)
7    return 0;
8  p = new Circle[size]; //dynamic object array allocation
9  int radius;
10  for(int i=0; i<size; i++) {
11    cout<<"Radius of circle "<< i+1 <<">>";
12    cin>>radius;
13    p[i].setRadius(radius);
14  }
15  int count = 0;
16  for(int i=0; i<size; i++) {
17    if(p[i].getArea() > 100) { count++; }
18  }
19  cout<<"Number of circles bigger than size 100 are "<<count<<endl;
20  delete [] p; //object destruction
21}

اشاره‌گر this

1class Circle {
2  int radius;
3public:
4  Circle() {
5    this->radius = 1;
6  }
7  Circle(int radius) {
8    this->raduis = radius;
9  }
10  void setRadius(int radius) {
11    this->radius = radius;
12  }
13}
1int main() {
2  Circle c1;
3  Circle c2(2);
4  Circle c3(3);
5  
6  c1.setRadius(4);
7  c2.setRadius(5);
8  c3.setRadius(6);
9}

This در زبان ++C موارد زیر را شامل می‌شود:

  • شیء در حال اجرای کنونی
  • اشاره‌گر

در مثال فوق دایره‌های c1 ،c2 و c از 1، 2 و 3 به 4، 5 و 6 تغییر می‌یابند.

متغیر ارجاعی

1int n=2;
2int &refn = n; // reference variable refn is another name for n
3Circle circle;
4Circle &refc = circle;

متغیر ارجاعی refn و متغیر n فضای حافظه مشترکی دارند و هر دو به مقدار 2 اشاره‌ می‌کنند. بنابراین زمانی که یک متغیر ارجاعی اعلان می‌شود، در واقع هیچ فضای حافظه‌ای ایجاد نمی‌شود؛ بلکه یک نام جدید برای فراخوانی مقدار قبلی ایجاد می‌شود.

1#include <iostream>
2using namespace std;
3class Circle {
4  int radius;
5public:
6  Circle() { radius = 1; }
7  Circle(int radius) { this->radius = radius; }
8  void setRadius(int radius) { this-> radius = radius; }
9  double getArea() { return 3.14*radius*radius; }
10};
11int main() {
12  Circle circle;
13  Circle &refc = circle;
14  refc.setRadius(10); //not refc->setRadius(10);
15  cout<<ref.getArea()<<" "<<circle.getArea();

(refc.setRadius(10 روش صحیح برای تغییر دادن مقدار شعاع refc است که شبیه به (circle.setRadius(10 است.

1/* difference in usage*/
2circle *c;
3c=&circle;
4c->setRadius(10); //pointer variable
5int n=3;
6int &refn=n;
7refn.setRadius(10); //reference varibale

فراخوانی با ارجاع

1#include <iostream>
2using namespace std;
3void swap(int &a, int &b) {
4  int tmp;
5  
6  tmp = a;
7  a = b;
8  b = tmp;
9}
10int main() {
11  int m=2, n=9;
12  swap(m,n);
13  cout<<m<<' '<<n;
14}

مثال فوق نشان می‌دهد که متغیر ارجاعی در زمان فراخوانی کردن پارامترها و استفاده از آدرس دقیق داده‌هایی که باید تغییر یابند بسیار آسان‌تر است. اگر بخواهیم با استفاده از اشاره‌گر مقدار دو متغیر a و b را با هم عوض کنیم، به صورت زیر عمل می‌کنیم:

1void swap(int *a, int *b) {
2  int tmp;
3  
4  tmp=*a;
5  *a=*b;
6  *b=tmp;
7}

اما در زمان استفاده از متغیر ارجاعی، a و b می‌توانند به صورتی که هستند نیز استفاده شوند. دلیل آن این است که متغیر ارجاعی در واقع نوعی قالب اشاره‌گر است و به آدرس مقداری که قرار است تغییر یابد اشاره می‌کند:

1#include <iostream>
2using namespace std;
3class MyIntStack {
4  int p[10];
5  int tos; //index pointing out top of stack
6public:
7  MyIntStack();
8  bool push(int n);
9  bool pop(int &a);
10};
1int main() {
2  MyIntStack a;
3  for(int i=0; i<11; i++) {
4    if(a.push(i))
5      cout<<i<<' ';
6    else
7      cout<<endl<<"the "<<i+1<<"th stack is full"<<endl;
8  }
9  int n;
10  for(int i=0; i<11; i++) {
11    if(a.pop(n))
12      cout<<n<<' ';
13    else
14      cout<<endl<<"the "<<i+1<<"th stack is empty"<<endl;
15  }
16  cout<<endl;
17}
18
19/*0 1 2 3 4 5 6 7 8 9
20the 11th stack is full
219 8 7 6 5 4 3 2 1 0
22the 11th stack is full
23*/
1MyIntStack::MyIntStack() {
2  tos = 0;
3}
4bool MyIntStack::push(int n) {
5  if(tos == 10)
6    return false; //stack full
7  p[tos] = n;
8  tos++;
9  return true;
10}
11bool MyIntStack::pop(int &refn) {
12  if(tos == 0)
13    return false; //stack empty
14  tos--;
15  refn = p[tos]; //refn and n are sharing same value
16  return true;
17}

Overloading

یکی از خصوصیات مهم برنامه‌نویسی شیءگرا چندریختی است. نمونه گویایی از چندریختی در مباحث Overloading ،Overriding و پارامتر پیش‌فرض (Default Parameter) است.

Overloading چیست؟

Overloading یعنی با استفاده از نام تابع یکسان، تعداد و نوع پارامترهای متفاوتی را مورد استفاده قرار دهیم.

1int add(int a, int b) { .. }
2double add(double a, double b) { .. }
3int add(int a, int b, int c) { ...}

تابع‌های ++C می‌توانند با نام یکسان دارای تعداد و نوع پارامترهای مختلفی باشند و این وضعیت در مورد آرایه‌ها و اشیا نیز صدق می‌کند.

مبانی ++C
مفهوم overload

بدین ترتیب می‌توان از نام تابع add بارها و بارها استفاده کرد و لازم نیست هر بار نام‌های جدیدی مانند intAdd ،doubleAdd ،intAddWithThreeParameter و غیره نوشت.

1#include <iostream>
2using namespace std;
3
4int big(int a, int b) { //return bigger number among a and b
5  if(a > b) return a;
6  else return b;
7}
8
9int big(int a[], int size) { //return bigger number among array a[]
10  int res = a[0];
11  for(int i=1; i<size; i++)
12    if(res < a[i]) res = a[i];
13  return res;
14}
15
16int main() {
17  int array[5] = {1, 9, -2, 8, 6};
18  cout<<big(2,3)<<endl;
19  cout<<big(array,5)<<endl;
20}

تابع سازنده تکراری

هدف از تابع سازنده تکراری تعیین مقدار آغازین در زمان ایجاد یک شیء است.

1class string {
2 ...
3public:
4  string(); //create string object with empty string
5  string(string& str); //create string object with copying str
6  string(char* s); 
7 ...
8};
9string str;
10string copyAddress(address);
11string address("Seoul");

پارامتر پیش‌فرض

اگر پارامتری دارای مقدار نباشد، این پارامتر با مقدار پیش‌فرض اعلان می‌شود. قالب پارامتر پیش‌فرض به صورت ‘parameter = default value’ است.

1void star(int a=5); // default value of a is 5
2star(); //value of a is 5
3star(10); //value of a is 10

شیوه استفاده از پارامتر پیش‌فرض

  • پارامتر عمومی در ابتدا می‌آید و پارامتر پیش‌فرض بعد آن قرار می‌گیرد.
  • پارامتر عمومی نمی‌تواند حذف شود.
1void calc(int a, int b=5, int c, int d=0) //compile error
2void sum(int a=0, int b, int c) //compile error
3void calc(int a, int b=5, int c=0, int d=0) //correct!

برای جمع‌بندی باید اشاره کنیم که overloading تابع و پارامتر پیش‌فرض به ساده‌سازی تابع‌ها کمک می‌کنند.

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

==

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

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