021-88881776

آموزش برنامه‌نویسی شیءگرا در C++

در این مقاله آموزشی جامع در مورد برنامه‌نویسی شیءگرا در C++ (Object-Oriented Programming in C++)، تمام جنبه‌های این موضوع از سطح مبتدی تا پیشرفته پوشش داده می‌شود. در آموزش C++، یکی از مهم‌ترین مفاهیم، شیءگرایی است که به ما این امکان را می‌دهد که کدهای خود را به شکلی ساختارمندتر و قابل نگهداری‌تر بنویسیم. این رویکرد به ما کمک می‌کند که به‌جای استفاده از توابع و داده‌ها به صورت جداگانه، آن‌ها را در قالب کلاس‌ها و اشیاء سازمان‌دهی کنیم. در ادامه، این مقاله تمام مفاهیم پایه‌ای و پیشرفته مرتبط با برنامه‌نویسی شیءگرا در C++ را با توضیحات ساده و مثال‌های عملی پوشش می‌دهد.

برنامه‌نویسی شیءگرا

برنامه‌نویسی شیءگرا (Object-Oriented Programming – OOP) یکی از روش‌های محبوب و قدرتمند برای طراحی نرم‌افزار است که هدف آن بهبود ساختار و قابلیت نگهداری کد است. این پارادایم به توسعه‌دهندگان این امکان را می‌دهد که نرم‌افزارهای خود را به شکلی منطقی‌تر و انعطاف‌پذیرتر توسعه دهند. در C++، برنامه‌نویسی شیءگرا به کمک ویژگی‌هایی مانند کلاس‌ها (Classes)، اشیاء (Objects)، وراثت (Inheritance)، چندریختی (Polymorphism) و کپسوله‌سازی (Encapsulation) به‌خوبی پیاده‌سازی می‌شود.

در برنامه‌نویسی شیءگرا، کد به واحدهایی تقسیم می‌شود که به آن‌ها شیء می‌گویند. هر شیء به‌طور معمول اطلاعات (داده‌ها) و توابع (متدها) را در خود جای می‌دهد. به‌عبارتی دیگر، یک شیء ترکیبی از داده‌ها و توابع است که می‌تواند به‌طور مستقل عمل کند. این روش به‌ویژه زمانی که با کدهای پیچیده یا پروژه‌های بزرگ سروکار داریم بسیار مفید است، زیرا باعث می‌شود کد ساده‌تر، تمیزتر و قابل مدیریت‌تر باشد.

ویژگی‌های اصلی برنامه‌نویسی شیءگرا

کلاس‌ها و اشیاء: در این مدل، شما ابتدا یک کلاس تعریف می‌کنید که مانند یک الگو برای ساخت اشیاء عمل می‌کند. کلاس‌ها ساختار داده‌ها و توابعی را مشخص می‌کنند که اشیاء آن کلاس خواهند داشت. هر شیء یک نمونه از کلاس است که می‌تواند مقادیر مختلفی از ویژگی‌ها (متغیرها) را در خود ذخیره کند.

کپسوله‌سازی: این ویژگی به این معنی است که داده‌ها و توابع مرتبط با داده‌ها در یک واحد (کلاس) قرار می‌گیرند و دسترسی به آن‌ها محدود می‌شود. این کار موجب می‌شود که دستکاری داده‌ها از بیرون کلاس فقط از طریق توابع (متدها) مجاز باشد و داده‌ها در برابر تغییرات ناخواسته محافظت شوند.

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

چندریختی: چندریختی به این معنی است که یک متد می‌تواند به شیوه‌های مختلف بسته به نوع شیء، رفتار متفاوتی داشته باشد. به‌عنوان‌مثال، یک متد در یک کلاس می‌تواند در کلاس‌های مشتق‌شده به‌طور متفاوت پیاده‌سازی شود. این ویژگی باعث می‌شود که کد انعطاف‌پذیرتر و قابل گسترش‌تر باشد.

انتزاع: انتزاع به شما اجازه می‌دهد تا پیاده‌سازی داخلی یک شیء را از دید کاربر پنهان کنید و تنها با یک رابط ساده و مشخص تعامل کنید. این ویژگی به ساده‌سازی کد و کاهش پیچیدگی‌ها کمک می‌کند.

مزایای برنامه‌نویسی شیءگرا

ساختار و نظم بهتر: با استفاده از کلاس‌ها و اشیاء، می‌توانید کدهای خود را به واحدهای منطقی تقسیم کنید و این باعث می‌شود که برنامه خواناتر و قابل فهم‌تر باشد.
قابلیت استفاده مجدد از کد: با استفاده از وراثت، می‌توانید کدهایی که قبلاً نوشته‌اید را در کلاس‌های جدید استفاده کنید، که باعث کاهش تکرار و افزایش بهره‌وری می‌شود.
گسترش و توسعه راحت‌تر: چون کد به‌صورت ماژولار و مستقل از یکدیگر نوشته می‌شود، افزودن ویژگی‌های جدید به برنامه و گسترش آن بسیار ساده‌تر می‌شود.
مدیریت آسان‌تر پروژه‌ها: در پروژه‌های بزرگ، با استفاده از OOP، توسعه‌دهندگان می‌توانند به راحتی کارهای خود را به بخش‌های کوچکتر تقسیم کنند و روی هر بخش به‌طور جداگانه کار کنند.
در نهایت، برنامه‌نویسی شیءگرا در C++ ابزارهای بسیار قوی‌ای را برای نوشتن برنامه‌های مقیاس‌پذیر، نگهداری‌پذیر و انعطاف‌پذیر فراهم می‌آورد که برای پروژه‌های پیچیده و بزرگ بسیار مفید است.

کلاس‌ها (C++ Classes)

در C++، کلاس‌ها (Classes) ساختارهای اصلی برای تعریف داده‌ها و توابع هستند. یک کلاس به‌عنوان یک الگو یا قالب برای ایجاد اشیاء (Objects) عمل می‌کند و می‌تواند ویژگی‌ها (متغیرها) و رفتارها (توابع) را که متعلق به اشیاء ایجادشده از آن کلاس هستند، در خود داشته باشد. به‌عبارت دیگر، کلاس‌ها نقش الگوهایی را ایفا می‌کنند که با استفاده از آن‌ها، می‌توانیم اشیاء با ویژگی‌ها و عملکردهای خاص ایجاد کنیم.

مفهوم کلاس‌ها

کلاس‌ها به‌طور کلی ترکیبی از داده‌ها و متدها هستند. داده‌ها، متغیرهایی هستند که اطلاعات یک شیء را ذخیره می‌کنند، در حالی که متدها توابعی هستند که برای انجام عملیات‌های مختلف روی داده‌های یک شیء یا برای تعامل با آن‌ها استفاده می‌شوند. یک کلاس به ما این امکان را می‌دهد که داده‌ها و توابع مرتبط با آن داده‌ها را در یک واحد نگهداری کنیم.

کلاس‌ها می‌توانند ویژگی‌های خاص خود را داشته باشند که به آن‌ها خصوصیات (Attributes) یا متغیرهای اعضای کلاس گفته می‌شود. همچنین، آن‌ها می‌توانند شامل متدهایی (Methods) باشند که رفتارهای مختلف شیء را مشخص می‌کنند.

ساختار یک کلاس

یک کلاس معمولاً شامل سه بخش اصلی است:

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

اجزای یک کلاس

خصوصیات (Attributes): این‌ها داده‌هایی هستند که برای هر شیء از یک کلاس ذخیره می‌شوند. این ویژگی‌ها می‌توانند به‌صورت public (عمومی) یا private (خصوصی) باشند. ویژگی‌های private معمولاً در داخل کلاس دست‌نخورده باقی می‌مانند و تنها از طریق متدهای عمومی کلاس می‌توان به آن‌ها دسترسی داشت.

متدها (Methods): این‌ها توابعی هستند که رفتارهای خاص شیء را مشخص می‌کنند. متدها معمولاً برای انجام عملیات روی داده‌های شیء یا برای برقراری تعامل با سایر اشیاء طراحی می‌شوند. یک کلاس ممکن است متدهایی برای تنظیم یا دریافت ویژگی‌ها (توابع set و get) داشته باشد.

مثال بیشتر از یک کلاس

در مثال زیر، کلاس Car یک الگو برای ایجاد اشیاء از نوع خودرو فراهم می‌آورد. این کلاس سه ویژگی (brand, model, year) دارد که اطلاعات مربوط به خودرو را ذخیره می‌کند، و یک متد به نام displayInfo برای نمایش اطلاعات خودرو تعریف کرده است.

cpp
Copy
Edit
#include <iostream>
#include <string>
using namespace std;

class Car {
public:
string brand; // برند خودرو
string model; // مدل خودرو
int year; // سال ساخت خودرو

// متدی برای نمایش اطلاعات خودرو
void displayInfo() {
cout << "Brand: " << brand << ", Model: " << model << ", Year: " << year << endl;
}
};

int main() {
// ایجاد شیء جدید از کلاس Car
Car car1;
car1.brand = "Toyota"; // مقداردهی به ویژگی brand
car1.model = "Corolla"; // مقداردهی به ویژگی model
car1.year = 2022; // مقداردهی به ویژگی year

// نمایش اطلاعات خودرو
car1.displayInfo();

return 0;
}

در این مثال، کلاس Car دارای سه ویژگی (brand, model, year) است که اطلاعات مربوط به خودرو را ذخیره می‌کند. همچنین، یک متد به نام displayInfo تعریف شده است که این اطلاعات را چاپ می‌کند.

توضیحات بیشتر در مورد کد

کلاس Car: این کلاس سه ویژگی به نام‌های brand، model و year دارد. این ویژگی‌ها به‌طور عمومی (public) در دسترس قرار دارند، یعنی می‌توان از خارج از کلاس به آن‌ها دسترسی داشت.

متد displayInfo(): این متد که داخل کلاس تعریف شده است، اطلاعات مربوط به خودرو را با استفاده از متغیرهای اعضای کلاس نمایش می‌دهد. برای نمایش این اطلاعات، از دستور cout استفاده می‌شود.

ساخت شیء از کلاس: در تابع main، یک شیء به نام car1 از کلاس Car ایجاد شده است. سپس ویژگی‌های مختلف آن به مقادیر دلخواه اختصاص داده شده است.

دسترسی به داده‌ها: پس از ایجاد شیء، می‌توان از طریق نام شیء (car1) و نقطه (.) به ویژگی‌ها و متدهای آن دسترسی پیدا کرد. در اینجا، اطلاعات خودرو از طریق فراخوانی متد displayInfo() نمایش داده می‌شود.

کاربردهای کلاس‌ها

کلاس‌ها در C++ اساس طراحی برنامه‌های شیءگرا هستند. با استفاده از کلاس‌ها می‌توان:

مدل‌سازی داده‌ها: مانند مدل‌سازی اشیاء واقعی در دنیای بیرون (مثلاً یک خودرو، یک کتاب، یک حساب بانکی و غیره).
تعریف متدهای مرتبط با داده‌ها: به‌عنوان مثال، یک متد برای تغییر اطلاعات یک شیء یا برای نمایش اطلاعات آن.
پنهان‌سازی جزئیات داخلی: از طریق ویژگی‌های private و public می‌توان پیاده‌سازی داخلی کلاس را از بیرون کلاس مخفی کرد و تنها از طریق رابط‌های عمومی به آن دسترسی پیدا کرد.

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

برنامه‌نویسی شیءگرا (C++ OOP)

برنامه‌نویسی شیءگرا (Object-Oriented Programming – OOP) یکی از مهم‌ترین و قدرتمندترین پارادایم‌های برنامه‌نویسی است که در C++ نیز به‌طور کامل پیاده‌سازی شده است. در این روش، برنامه‌ها به واحدهایی به نام اشیاء (Objects) تقسیم می‌شوند که هر شیء می‌تواند داده‌ها و رفتارهای خاص خود را داشته باشد. این واحدهای مستقل از یکدیگر می‌توانند تعامل داشته باشند و به این ترتیب پیچیدگی‌های برنامه کاهش می‌یابد.

مفاهیم کلیدی در برنامه‌نویسی شیءگرا

در C++ OOP، مفاهیم اصلی عبارتند از:

کلاس‌ها (Classes)
اشیاء (Objects)
کپسوله‌سازی (Encapsulation)
وراثت (Inheritance)
چندریختی (Polymorphism)
انتزاع (Abstraction)
این مفاهیم به توسعه‌دهندگان این امکان را می‌دهند که برنامه‌ها را به شیوه‌ای سازمان‌یافته و ماژولار طراحی کنند.

اشیاء و کلاس‌ها

در C++ OOP، کلاس‌ها و اشیاء ابزارهای اصلی هستند:

یک کلاس (Class) یک الگو یا طرح است که نحوه ذخیره‌سازی داده‌ها و نحوه انجام عملیات بر روی آن‌ها را مشخص می‌کند.
یک شیء (Object) نمونه‌ای از یک کلاس است که می‌تواند مقادیر خاص خود را برای داده‌ها و ویژگی‌های کلاس داشته باشد.
به‌عبارت دیگر، یک کلاس نقشه‌ای برای اشیاء است. هر شیء یک نمونه از یک کلاس است و می‌تواند داده‌ها و توابع کلاس را داشته باشد. کلاس‌ها و اشیاء در برنامه‌نویسی شیءگرا این امکان را می‌دهند که برنامه‌نویس داده‌ها و توابع را به‌طور منطقی سازمان‌دهی کند.

ساختار برنامه‌نویسی شیءگرا در C++

در C++، برنامه‌نویسی شیءگرا با استفاده از کلاس‌ها و اشیاء پیاده‌سازی می‌شود. این به این معناست که شما ابتدا یک کلاس تعریف می‌کنید، سپس از آن کلاس اشیاء مختلفی می‌سازید و هر شیء ویژگی‌ها و رفتارهای خاص خود را دارد. ویژگی‌های کلاس‌ها معمولاً به‌صورت متغیرهای عضو (Member Variables) و رفتارهای آن‌ها به‌صورت متدها (Methods) تعریف می‌شود.

مثال عملی از برنامه‌نویسی شیءگرا در C++
در ادامه یک مثال ساده از C++ OOP آورده شده است:

#include <iostream>
#include <string>
using namespace std;

class Car {
public:
    string brand;
    string model;
    int year;
    
    void displayInfo() {
        cout << "Brand: " << brand << ", Model: " << model << ", Year: " << year << endl;
    }
};

int main() {
    // ساخت شیء از کلاس Car
    Car myCar;
    
    // مقداردهی ویژگی‌های شیء myCar
    myCar.brand = "Toyota";
    myCar.model = "Corolla";
    myCar.year = 2022;
    
    // فراخوانی متد برای نمایش اطلاعات
    myCar.displayInfo();
    
    return 0;
}

توضیحات کد:
تعریف کلاس Car: کلاس Car دارای سه ویژگی (متغیر عضو) است: brand, model و year که مربوط به اطلاعات خودرو هستند. همچنین یک متد به نام displayInfo داریم که این اطلاعات را نمایش می‌دهد.

ساخت شیء از کلاس Car: در داخل تابع main، شیء‌ای به نام myCar از کلاس Car ساخته می‌شود. هر شیء که از یک کلاس ساخته می‌شود، نمونه‌ای از آن کلاس است و ویژگی‌ها و متدهای کلاس را در اختیار دارد.

مقداردهی به ویژگی‌ها: پس از ساخت شیء، ویژگی‌های brand, model و year شیء myCar مقداردهی می‌شوند.

فراخوانی متد displayInfo: با استفاده از شیء myCar، متد displayInfo فراخوانی می‌شود که اطلاعات مربوط به خودرو را چاپ می‌کند.

ویژگی‌های مهم برنامه‌نویسی شیءگرا در C++

کپسوله‌سازی (Encapsulation): در C++ OOP، داده‌ها و توابع در داخل کلاس‌ها قرار دارند و این داده‌ها از بیرون کلاس به‌صورت مستقیم قابل دسترسی نیستند. این کار باعث محافظت از داده‌ها و کنترل بیشتر بر دسترسی به آن‌ها می‌شود. این ویژگی موجب می‌شود که تغییرات داخلی کلاس به‌راحتی بر سایر بخش‌های برنامه تأثیر نگذارد.

وراثت (Inheritance): یکی از ویژگی‌های قدرتمند C++ OOP این است که یک کلاس می‌تواند ویژگی‌ها و متدهای خود را از یک کلاس دیگر به ارث ببرد. این امکان باعث می‌شود که کدهای تکراری کاهش یابند و شما بتوانید کد جدید را بر اساس کدهای قدیمی بسازید.

چندریختی (Polymorphism): در C++ OOP، چندریختی به شما این امکان را می‌دهد که از یک متد با نام یکسان در کلاس‌های مختلف استفاده کنید، ولی هر کلاس پیاده‌سازی متفاوتی از آن متد داشته باشد. این ویژگی باعث افزایش انعطاف‌پذیری برنامه می‌شود.

انتزاع (Abstraction): در C++ OOP، شما می‌توانید پیاده‌سازی داخلی یک کلاس را از سایر بخش‌های برنامه پنهان کنید و فقط رابط‌های عمومی را در اختیار کاربران قرار دهید. این کار باعث می‌شود که پیچیدگی‌ها کاهش یابد و برنامه ساده‌تر شود.

مزایای برنامه‌نویسی شیءگرا در C++

کاهش پیچیدگی: با تقسیم برنامه به اشیاء و کلاس‌ها، پیچیدگی برنامه کاهش می‌یابد. هر کلاس مسئولیت خاص خود را دارد و این موجب می‌شود که مدیریت برنامه آسان‌تر شود.
مدیریت راحت‌تر پروژه‌های بزرگ: در پروژه‌های بزرگ، برنامه‌نویسی شیءگرا با استفاده از کلاس‌ها و اشیاء، امکان مدیریت بخش‌های مختلف پروژه را به‌طور جداگانه فراهم می‌کند.
انعطاف‌پذیری و توسعه آسان: با استفاده از ویژگی‌های OOP مانند وراثت و چندریختی، می‌توان برنامه‌های انعطاف‌پذیر نوشت که به راحتی قابلیت گسترش دارند.
استفاده مجدد از کد: با استفاده از وراثت، کدهای نوشته‌شده در کلاس‌های پایه را می‌توان در کلاس‌های مشتق‌شده استفاده کرد و به این ترتیب از تکرار کد جلوگیری می‌شود.

برنامه‌نویسی شیءگرا در C++ با استفاده از مفاهیم کلاس‌ها، اشیاء، کپسوله‌سازی، وراثت و چندریختی، ابزاری قدرتمند برای نوشتن برنامه‌های مقیاس‌پذیر، قابل مدیریت و انعطاف‌پذیر است. این ویژگی‌ها به توسعه‌دهندگان این امکان را می‌دهند که برنامه‌های پیچیده را به‌راحتی طراحی و پیاده‌سازی کنند و کدهایی تمیز، قابل نگهداری و مستند تولید کنند.

کلاس‌ها / اشیاء (C++ Classes/Objects)

در C++، کلاس‌ها و اشیاء ابزارهای اصلی و بنیادین برای پیاده‌سازی برنامه‌نویسی شیءگرا (Object-Oriented Programming – OOP) هستند. این دو مفهوم به‌طور مستقیم با هم مرتبط‌اند، به‌گونه‌ای که هر کلاس الگویی برای ایجاد اشیاء است و اشیاء نمونه‌هایی از کلاس‌ها به شمار می‌روند.

کلاس‌ها (Classes)

کلاس‌ها ساختارهایی هستند که به‌طور کلی داده‌ها و توابع را در یک جا گردآوری می‌کنند. کلاس‌ها می‌توانند ویژگی‌ها (متغیرهای عضو) و رفتارها (توابع یا متدها) را در خود داشته باشند. هر کلاس به‌عنوان یک الگو یا طراحی عمل می‌کند که بر اساس آن اشیاء ساخته می‌شوند.

یک کلاس می‌تواند حاوی:

ویژگی‌ها (Attributes): متغیرهایی که داده‌ها را ذخیره می‌کنند.
متدها (Methods): توابعی که رفتارهای کلاس را تعریف می‌کنند.
سازنده‌ها (Constructors): توابعی برای مقداردهی اولیه ویژگی‌های شیء.
تخریب‌کننده‌ها (Destructors): توابعی که هنگام حذف شیء فراخوانی می‌شوند.
مشخص‌کننده‌های دسترسی (Access Specifiers): که تعیین می‌کنند چه بخش‌هایی از کلاس قابل دسترسی هستند.

اشیاء (Objects)

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

هر شیء از یک کلاس می‌تواند ویژگی‌ها (داده‌ها) و متدهای آن کلاس را داشته باشد، اما مقادیر ویژگی‌ها می‌توانند در هر شیء متفاوت باشند. این باعث می‌شود که اشیاء انعطاف‌پذیر و مجزا از یکدیگر عمل کنند.

مثال کلاس‌ها و اشیاء در C++

در این مثال، یک کلاس به نام Car تعریف می‌شود که ویژگی‌ها و متدی برای نمایش اطلاعات خودرو دارد. سپس یک شیء از این کلاس ساخته می‌شود.

#include <iostream>
#include <string>
using namespace std;

class Car {
public:
    // ویژگی‌ها (Attributes)
    string brand;
    string model;
    int year;

    // متد (Method)
    void displayInfo() {
        cout << "Brand: " << brand << ", Model: " << model << ", Year: " << year << endl;
    }
};

int main() {
    // ساخت شیء از کلاس Car
    Car myCar;
    
    // مقداردهی ویژگی‌های شیء myCar
    myCar.brand = "Toyota";
    myCar.model = "Corolla";
    myCar.year = 2022;

    // فراخوانی متد برای نمایش اطلاعات خودرو
    myCar.displayInfo();
    
    return 0;
}

توضیحات کد:
کلاس Car:
این کلاس شامل سه ویژگی است: brand, model و year که اطلاعات مربوط به خودرو را ذخیره می‌کنند.
یک متد به نام displayInfo برای نمایش این اطلاعات به کاربر تعریف شده است.
ساخت شیء myCar:
در داخل تابع main، یک شیء به نام myCar از کلاس Car ساخته می‌شود. در اینجا، myCar یک نمونه از کلاس Car است.
پس از ساخت شیء، ویژگی‌های brand, model و year برای شیء myCar مقداردهی می‌شوند.
فراخوانی متد displayInfo:
با استفاده از شیء myCar، متد displayInfo فراخوانی می‌شود تا اطلاعات مربوط به خودرو نمایش داده شود.

تفاوت کلاس و شیء

کلاس: یک کلاس تنها یک الگو یا طرح است و به تنهایی هیچ داده‌ای ندارد. کلاس‌ها ویژگی‌ها و متدها را به‌عنوان قالب برای اشیاء مشخص می‌کنند.
شیء: هر شیء نمونه‌ای از یک کلاس است و داده‌ها و رفتارهای خاص خود را دارد. به عبارت دیگر، یک کلاس می‌تواند چندین شیء مختلف بسازد، و هر شیء می‌تواند ویژگی‌های متفاوتی داشته باشد.

استفاده از اشیاء در C++

هر شیء از کلاس می‌تواند ویژگی‌ها و رفتارهای خود را داشته باشد، اما آن‌ها از کلاس اصلی وراثت می‌کنند. برای نمونه، می‌توانیم چندین شیء از کلاس Car بسازیم که هرکدام دارای ویژگی‌های متفاوتی باشند:

int main() {
    // ساخت چندین شیء از کلاس Car
    Car car1;
    car1.brand = "Toyota";
    car1.model = "Camry";
    car1.year = 2023;

    Car car2;
    car2.brand = "Honda";
    car2.model = "Civic";
    car2.year = 2022;

    // فراخوانی متد برای نمایش اطلاعات
    car1.displayInfo();  // اطلاعات خودرو اول
    car2.displayInfo();  // اطلاعات خودرو دوم

    return 0;
}

در اینجا، دو شیء car1 و car2 از کلاس Car ساخته می‌شوند. هر کدام ویژگی‌های خاص خود را دارند، اما متد displayInfo برای هر دو یکسان است. این نشان‌دهنده این است که همه اشیاء از یک کلاس می‌توانند رفتار مشترک داشته باشند، اما ویژگی‌های آن‌ها متفاوت خواهد بود.

مزایای استفاده از کلاس‌ها و اشیاء

سازمان‌دهی داده‌ها: استفاده از کلاس‌ها و اشیاء کمک می‌کند تا داده‌ها و رفتارها به‌طور منطقی و منظم در کنار هم قرار گیرند.
استفاده مجدد از کد: می‌توان از کلاس‌ها برای ایجاد اشیاء متعدد استفاده کرد که کد تکراری کاهش یابد و استفاده از کدهای موجود آسان‌تر شود.
مدیریت آسان‌تر برنامه‌های بزرگ: در برنامه‌های پیچیده، استفاده از کلاس‌ها و اشیاء باعث می‌شود که برنامه به بخش‌های کوچک‌تر و قابل مدیریت تقسیم شود.
گسترش و تغییر آسان: با استفاده از کلاس‌ها، تغییرات در برنامه راحت‌تر اعمال می‌شود. به‌عنوان مثال، اگر بخواهیم ویژگی‌های یک کلاس را تغییر دهیم، تنها باید کد مربوط به آن کلاس را ویرایش کنیم، بدون اینکه به بخش‌های دیگر برنامه آسیب وارد کنیم.

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

متدهای کلاس (C++ Class Methods)

در C++، متدهای کلاس توابعی هستند که داخل یک کلاس تعریف می‌شوند و معمولاً به‌منظور تعامل با داده‌های درون شیء یا انجام عملیات خاص بر روی ویژگی‌های آن شیء نوشته می‌شوند. متدهای کلاس می‌توانند داده‌های عضو کلاس را تغییر دهند، محاسباتی انجام دهند، یا اطلاعات را نمایش دهند. آن‌ها به‌عنوان رفتارهایی برای کلاس عمل می‌کنند و می‌توانند به‌طور مستقیم با داده‌های شیء تعامل داشته باشند.

مفهوم متد در کلاس‌ها

یک متد در C++ یک تابع است که در داخل یک کلاس تعریف می‌شود و معمولاً برای انجام عملیات خاص بر روی ویژگی‌های شیء و بازگرداندن نتایج یا تغییرات مرتبط به‌کار می‌رود. متدها می‌توانند مانند توابع معمولی پارامتر بگیرند و مقداری را بازگردانند، اما تفاوت اصلی آن‌ها در این است که به داده‌های عضو کلاس (ویژگی‌ها) دسترسی دارند و معمولاً برای عمل بر روی داده‌های داخلی شیء طراحی می‌شوند.

انواع متدهای کلاس

متدهای کلاس‌ها در C++ به طور کلی به دو دسته تقسیم می‌شوند:

متدهای عضو (Member Methods): این‌ها متدهایی هستند که داخل کلاس تعریف شده و می‌توانند به ویژگی‌های داخلی شیء دسترسی داشته باشند.
متدهای ثابت (Const Methods): این متدها قادر به تغییر ویژگی‌های شیء نیستند و صرفاً برای خواندن داده‌ها طراحی شده‌اند. این نوع متدها معمولاً برای اعمالی که نیازی به تغییر وضعیت شیء ندارند، استفاده می‌شوند.

مثال ساده از متدهای کلاس

در اینجا یک مثال ساده از کلاس Circle آورده شده است که متدی به نام area دارد که مساحت دایره را محاسبه می‌کند:

#include <iostream>
using namespace std;

class Circle {
public:
    double radius;

    // متد محاسبه مساحت دایره
    double area() {
        return 3.14 * radius * radius;
    }
};

int main() {
    // ساخت شیء از کلاس Circle
    Circle myCircle;
    myCircle.radius = 5.0; // مقداردهی به شعاع

    // فراخوانی متد برای محاسبه مساحت
    cout << "Area of the circle: " << myCircle.area() << endl;

    return 0;
}

توضیحات کد:
کلاس Circle:
کلاس Circle یک ویژگی به نام radius دارد که شعاع دایره را ذخیره می‌کند.
متد area نیز در کلاس تعریف شده است که مساحت دایره را محاسبه می‌کند. این متد از فرمول π * radius^2 برای محاسبه مساحت استفاده می‌کند.
شیء myCircle:
در داخل تابع main، یک شیء از کلاس Circle به نام myCircle ساخته می‌شود.
سپس ویژگی radius به مقدار 5.0 مقداردهی می‌شود.
فراخوانی متد area:
متد area فراخوانی می‌شود و مساحت دایره را محاسبه می‌کند. نتیجه این محاسبه در کنسول چاپ می‌شود.

اهمیت متدهای کلاس

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

متدهای با پارامتر و بدون پارامتر

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

مثال متد با پارامتر:

#include <iostream>
using namespace std;

class Rectangle {
public:
    double length;
    double width;

    // متد برای محاسبه مساحت مستطیل
    double area(double l, double w) {
        length = l;
        width = w;
        return length * width;
    }
};

int main() {
    Rectangle rect;
    // فراخوانی متد با پارامتر برای محاسبه مساحت مستطیل
    cout << "Area of rectangle: " << rect.area(10.0, 5.0) << endl;
    return 0;
}

در این مثال، متد area با دو پارامتر l و w تعریف شده است که به آن داده می‌دهند تا مساحت مستطیل را محاسبه کند. این متد مقادیر را به ویژگی‌های length و width اختصاص می‌دهد و سپس مساحت را باز می‌گرداند.

متدهای ثابت (Const Methods)

متدهای ثابت (Const Methods) به‌طور خاص برای اطمینان از این که هیچ تغییری در وضعیت شیء ایجاد نمی‌شود طراحی شده‌اند. این متدها نمی‌توانند ویژگی‌های عضو کلاس را تغییر دهند. برای اعلام یک متد به‌عنوان متد ثابت، از کلمه‌کلیدی const بعد از تعریف متد استفاده می‌شود.

مثال متد ثابت:

#include <iostream>
using namespace std;

class Book {
public:
    string title;
    string author;

    // متد ثابت برای نمایش عنوان کتاب
    void displayInfo() const {
        cout << "Title: " << title << ", Author: " << author << endl;
    }
};

int main() {
    Book myBook;
    myBook.title = "C++ Programming";
    myBook.author = "Bjarne Stroustrup";

    // فراخوانی متد ثابت
    myBook.displayInfo();

    return 0;
}

در این مثال، متد displayInfo به‌عنوان یک متد ثابت تعریف شده است. این متد فقط اطلاعات را نمایش می‌دهد و هیچ تغییری در ویژگی‌های شیء ایجاد نمی‌کند.
متدهای کلاس در C++ ابزارهای کلیدی برای پیاده‌سازی رفتارهای کلاس و تعامل با داده‌های موجود در اشیاء هستند. این متدها می‌توانند ویژگی‌ها را تغییر دهند، عملیات‌های مختلفی انجام دهند، یا اطلاعات را نمایش دهند. استفاده از متدها در کلاس‌ها باعث می‌شود که برنامه‌نویسی شیءگرا به‌صورت منظم، ساختاریافته و مقیاس‌پذیر انجام شود.

سازنده‌ها (C++ Constructors)

سازنده‌ها (Constructors) توابع ویژه‌ای در کلاس‌ها هستند که به‌طور خودکار زمانی که یک شیء جدید از کلاس ساخته می‌شود، فراخوانی می‌شوند. وظیفه اصلی سازنده‌ها مقداردهی اولیه به ویژگی‌ها (متغیرهای عضو) شیء است. در واقع، سازنده‌ها این امکان را فراهم می‌کنند که شیء جدید به‌طور صحیح و با مقادیر اولیه مناسب ساخته شود.

مفهوم سازنده در C++

سازنده‌ها در C++ توابعی هستند که نامشان دقیقا با نام کلاس یکسان است و هیچ نوع مقدار بازگشتی ندارند (حتی void هم نمی‌توانند داشته باشند). این توابع می‌توانند پارامترهایی بپذیرند یا فاقد پارامتر باشند. هدف اصلی سازنده‌ها، مقداردهی اولیه به داده‌های عضو شیء است.

ویژگی‌های سازنده‌ها

نام همانند کلاس: سازنده همیشه نامش باید همانند نام کلاس باشد.
عدم بازگشت مقدار: سازنده هیچ مقداری باز نمی‌گرداند، حتی void هم ندارد.
فراخوانی خودکار: وقتی شیء جدیدی از کلاس ساخته می‌شود، سازنده به‌طور خودکار فراخوانی می‌شود.
مقداردهی اولیه: سازنده‌ها معمولاً برای مقداردهی اولیه به ویژگی‌های شیء استفاده می‌شوند.

انواع سازنده‌ها

در C++، سازنده‌ها به دو نوع اصلی تقسیم می‌شوند:

سازنده پیش‌فرض (Default Constructor): این سازنده بدون هیچ پارامتری است و به‌طور خودکار توسط کامپایلر ایجاد می‌شود اگر هیچ سازنده‌ای در کلاس تعریف نشده باشد.
سازنده پارامتردار (Parameterized Constructor): این سازنده یک یا چند پارامتر دارد که به‌طور معمول برای مقداردهی اولیه به ویژگی‌های شیء استفاده می‌شود.

سازنده پیش‌فرض (Default Constructor)

اگر شما سازنده‌ای برای یک کلاس تعریف نکنید، C++ به‌طور خودکار یک سازنده پیش‌فرض ایجاد می‌کند که ویژگی‌های شیء را به مقادیر پیش‌فرض (مانند ۰ برای عددها یا NULL برای اشاره‌گرها) مقداردهی می‌کند.

مثال سازنده پیش‌فرض:

#include <iostream>
using namespace std;

class Book {
public:
    string title;
    string author;

    // سازنده پیش‌فرض
    Book() {
        title = "Unknown";
        author = "Unknown";
    }
};

int main() {
    // ساخت شیء از کلاس Book
    Book myBook;

    // نمایش ویژگی‌های شیء
    cout << "Title: " << myBook.title << ", Author: " << myBook.author << endl;

    return 0;
}

در اینجا، یک سازنده پیش‌فرض برای کلاس Book تعریف شده است که به‌طور خودکار ویژگی‌های title و author را به مقادیر “Unknown” مقداردهی می‌کند.

سازنده پارامتردار (Parameterized Constructor)

سازنده‌های پارامتردار این امکان را به شما می‌دهند که هنگام ساخت شیء جدید، مقادیر خاصی به آن پاس دهید و ویژگی‌های آن را مقداردهی کنید. این نوع سازنده‌ها بسیار مفید هستند وقتی که می‌خواهید به‌طور داینامیک مقادیر اولیه را به شیء ارسال کنید.

مثال سازنده پارامتردار:

#include <iostream>
using namespace std;

class Book {
public:
    string title;
    string author;

    // سازنده پارامتردار
    Book(string t, string a) {
        title = t;
        author = a;
    }
};

int main() {
    // ساخت شیء از کلاس Book و ارسال مقادیر به سازنده
    Book myBook("C++ Programming", "Bjarne Stroustrup");

    // نمایش ویژگی‌های شیء
    cout << "Title: " << myBook.title << ", Author: " << myBook.author << endl;

    return 0;
}

در اینجا، سازنده Book دارای دو پارامتر t و a است که به آن مقادیر “C++ Programming” و “Bjarne Stroustrup” ارسال شده است. سپس، این مقادیر به ویژگی‌های title و author نسبت داده می‌شوند.

سازنده کپی (Copy Constructor)

سازنده کپی یک نوع خاص از سازنده است که برای ایجاد یک شیء جدید به‌وسیله کپی کردن داده‌های یک شیء دیگر از همان نوع استفاده می‌شود. این نوع سازنده زمانی مفید است که بخواهید از یک شیء دیگر یک کپی دقیق بسازید.

مثال سازنده کپی:

#include <iostream>
using namespace std;

class Book {
public:
    string title;
    string author;

    // سازنده پارامتردار
    Book(string t, string a) {
        title = t;
        author = a;
    }

    // سازنده کپی
    Book(const Book &b) {
        title = b.title;
        author = b.author;
    }
};

int main() {
    Book originalBook("C++ Programming", "Bjarne Stroustrup");
    
    // ساخت شیء جدید با استفاده از سازنده کپی
    Book copiedBook = originalBook;

    // نمایش ویژگی‌های شیء کپی شده
    cout << "Copied Book - Title: " << copiedBook.title << ", Author: " << copiedBook.author << endl;

    return 0;
}

در اینجا، وقتی شیء originalBook ساخته می‌شود، سازنده کپی برای ایجاد یک شیء جدید copiedBook از داده‌های originalBook استفاده می‌شود.

تخریب‌کننده‌ها (Destructors)

در کنار سازنده‌ها، C++ از تخریب‌کننده‌ها (Destructors) نیز پشتیبانی می‌کند. این توابع به‌طور خودکار زمانی که شیء از حافظه حذف می‌شود، فراخوانی می‌شوند. وظیفه اصلی تخریب‌کننده‌ها آزادسازی منابعی است که در طول عمر شیء گرفته شده‌اند (مثلاً حافظه‌های دینامیکی که توسط new تخصیص داده شده‌اند).
سازنده‌ها در C++ توابع ویژه‌ای هستند که به هنگام ساخت یک شیء جدید به‌طور خودکار فراخوانی می‌شوند. آن‌ها وظیفه دارند که ویژگی‌های شیء را مقداردهی اولیه کنند و در برخی موارد، از سازنده‌های پارامتردار برای دریافت مقادیر اولیه از کاربر استفاده می‌شود. علاوه بر سازنده‌های معمولی، سازنده‌های کپی نیز می‌توانند برای کپی کردن داده‌های یک شیء به شیء دیگر استفاده شوند.

مشخص‌کننده‌های دسترسی (C++ Access Specifiers)

در C++، مشخص‌کننده‌های دسترسی (Access Specifiers) ابزارهایی هستند که به برنامه‌نویس این امکان را می‌دهند که دسترسی به ویژگی‌ها (Attributes) و متدهای (Methods) یک کلاس را کنترل کند. این ابزارها به‌ویژه در برنامه‌نویسی شیءگرا مهم هستند زیرا از کپسوله‌سازی (Encapsulation) پشتیبانی می‌کنند، که به‌نوبه خود باعث افزایش امنیت داده‌ها و محافظت از اطلاعات داخلی شیء می‌شود.

انواع مشخص‌کننده‌های دسترسی در C++

در C++ سه نوع اصلی مشخص‌کننده دسترسی وجود دارد که عبارتند از:

public: این مشخص‌کننده اجازه می‌دهد که اعضای کلاس از هر نقطه‌ای در برنامه قابل دسترسی باشند. در واقع، هر چیزی که در بخش public کلاس قرار داشته باشد، بدون هیچ محدودیتی از هر کجا در برنامه قابل استفاده است.

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

protected: این مشخص‌کننده، دسترسی به اعضای کلاس را محدود به خود کلاس و کلاس‌های مشتق‌شده (در صورت استفاده از وراثت) می‌کند. اعضای protected از داخل کلاس قابل دسترسی هستند، همچنین کلاس‌های فرزند (کلاس‌های مشتق‌شده) نیز می‌توانند به این اعضا دسترسی داشته باشند.

توضیحات بیشتر و جزئیات

1. public

اعضای public آزادانه از خارج از کلاس در دسترس هستند.
این اعضا از محدودیت‌های کپسوله‌سازی مستثنی هستند.
در برنامه‌نویسی شیءگرا، برای توابع یا ویژگی‌هایی که قرار است توسط دیگر قسمت‌های برنامه فراخوانی شوند، معمولاً از این مشخص‌کننده استفاده می‌شود.
مثال:

class Car {
public:
    string brand;
    string model;

    void displayInfo() {
        cout << "Brand: " << brand << ", Model: " << model << endl;
    }
};

در این مثال، ویژگی‌ها و متدهای کلاس Car که با public تعریف شده‌اند، می‌توانند از خارج از کلاس فراخوانی شوند.

2. private

اعضای private تنها در داخل همان کلاس قابل دسترسی هستند.
این اعضا نمی‌توانند از خارج از کلاس تغییر یا مشاهده شوند. این نوع دسترسی برای داده‌های داخلی و حساس به‌کار می‌رود.
این ویژگی به امنیت داده‌ها کمک می‌کند و از تغییرات غیرمجاز جلوگیری می‌کند.
مثال:

class Person {
private:
    int age;  // ویژگی private

public:
    void setAge(int a) {
        age = a;  // متد public برای تغییر داده private
    }

    int getAge() {
        return age;  // متد public برای دسترسی به داده private
    }
};

در اینجا، ویژگی age به‌صورت private تعریف شده است و نمی‌توان مستقیماً از خارج از کلاس به آن دسترسی پیدا کرد. برای دسترسی به آن، باید از متدهای setAge و getAge استفاده کرد.

3. protected

اعضای protected از داخل کلاس قابل دسترسی هستند و همچنین کلاس‌های مشتق‌شده (کلاس‌هایی که از این کلاس به ارث برده‌اند) نیز می‌توانند به آن‌ها دسترسی پیدا کنند.
این نوع دسترسی در زمانی که نیاز به استفاده از وراثت باشد، کاربرد دارد. به این ترتیب اعضای protected نه به طور کامل عمومی هستند و نه به طور کامل خصوصی. آن‌ها فقط به کلاس‌های فرزند (کلاس‌های مشتق‌شده) دسترسی دارند.
مثال:

class Animal {
protected:
    string species;  // ویژگی protected

public:
    void setSpecies(string sp) {
        species = sp;  // متد public برای تغییر داده protected
    }

    void displaySpecies() {
        cout << "Species: " << species << endl;
    }
};

class Dog : public Animal {  // کلاس Dog از Animal ارث‌بری می‌کند
public:
    void setDogSpecies(string sp) {
        species = sp;  // دسترسی به ویژگی protected از کلاس پایه (Animal)
    }
};

در این مثال، ویژگی species به‌صورت protected در کلاس Animal تعریف شده است. از آنجا که کلاس Dog از Animal ارث‌بری کرده است، می‌تواند به این ویژگی دسترسی پیدا کند.

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

کپسوله‌سازی داده‌ها: استفاده از private و protected برای پنهان کردن داده‌ها و توابع داخلی از دسترسی‌های خارجی می‌تواند به حفاظت از اطلاعات کمک کند. این به‌ویژه در پروژه‌هایی که نیاز به ایمنی بالایی دارند، اهمیت دارد.

مدیریت دسترسی به متدها: گاهی اوقات ممکن است برخی از متدها یا ویژگی‌ها تنها باید در کلاس خود قابل دسترسی باشند و از این رو، از private برای این نوع ویژگی‌ها استفاده می‌شود.

کنترل دسترسی در وراثت: protected این امکان را به کلاسی که از یک کلاس دیگر ارث‌بری می‌کند می‌دهد تا به برخی از داده‌ها یا متدهای کلاس پایه دسترسی داشته باشد، اما همچنان از دسترسی آزاد آن‌ها جلوگیری می‌کند.
مشخص‌کننده‌های دسترسی در C++ ابزارهای قدرتمندی برای کنترل دسترسی به اعضای کلاس‌ها هستند. با استفاده از public، private و protected، می‌توانیم از امنیت داده‌ها محافظت کنیم، دسترسی‌ها را مدیریت کنیم و انعطاف‌پذیری بیشتری در طراحی نرم‌افزار به‌دست آوریم. این اصول کمک می‌کنند تا از کپسوله‌سازی و سایر اصول شیءگرا به‌درستی استفاده کنیم و برنامه‌های امن‌تر و مقیاس‌پذیرتری ایجاد نماییم.

کپسوله‌سازی (C++ Encapsulation)

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

هدف کپسوله‌سازی

هدف اصلی کپسوله‌سازی جلوگیری از دسترسی مستقیم به داده‌های حساس شیء است. این مفهوم به این صورت است که داده‌ها (ویژگی‌ها) باید خصوصی (private) باقی بمانند و فقط از طریق متدها (که می‌توانند عمومی یا protected باشند) به آن‌ها دسترسی پیدا شود. این متدها می‌توانند رفتارهایی برای تغییر یا مشاهده داده‌ها فراهم کنند، اما خود داده‌ها از دیدگاه خارجی پنهان می‌مانند.

مزایای کپسوله‌سازی

امنیت داده‌ها: با محدود کردن دسترسی مستقیم به داده‌ها، می‌توان از تغییرات غیرمجاز یا ناخواسته جلوگیری کرد. این به خصوص برای داده‌های حساس یا حیاتی در سیستم‌های نرم‌افزاری مهم است.
کاهش وابستگی‌ها: برنامه‌نویسان می‌توانند تغییرات لازم را در پیاده‌سازی کلاس انجام دهند بدون اینکه لازم باشد کدهای خارج از کلاس تحت تاثیر قرار گیرند. این باعث افزایش انعطاف‌پذیری و کاهش خطاهای ناشی از تغییرات می‌شود.
بهبود نگهداری کد: با پنهان کردن جزئیات داخلی کلاس و فراهم کردن تنها یک رابط عمومی برای تعامل با داده‌ها، نگهداری کد ساده‌تر می‌شود. تغییرات داخلی کد نیازی به تغییر در کدهای استفاده‌کننده از آن ندارد.
افزایش خوانایی و ساختار کد: کپسوله‌سازی می‌تواند به ساختار و سازماندهی بهتر کد کمک کند، چرا که تنها متدهای عمومی (public methods) برای تعامل با داده‌ها در دسترس هستند.

اجزای کپسوله‌سازی

داده‌ها (Data): این‌ها ویژگی‌های شیء هستند که اطلاعات مختلف شیء را ذخیره می‌کنند. معمولاً این داده‌ها به‌صورت خصوصی (private) تعریف می‌شوند.
متدها (Methods): این‌ها توابعی هستند که روی داده‌ها عمل می‌کنند و معمولاً به‌صورت عمومی (public) تعریف می‌شوند تا برنامه‌نویسان بتوانند از آن‌ها برای تعامل با داده‌ها استفاده کنند.
محدودیت‌های دسترسی (Access Modifiers): این‌ها تعیین می‌کنند که کدام بخش‌های یک کلاس در دسترس هستند و کدام بخش‌ها محدود شده‌اند. در C++ سه نوع اصلی محدودیت دسترسی وجود دارد:
private: ویژگی‌ها و متدهای خصوصی فقط در داخل کلاس قابل دسترسی هستند.
public: ویژگی‌ها و متدهای عمومی از خارج از کلاس قابل دسترسی هستند.
protected: ویژگی‌ها و متدهای محافظت‌شده فقط در کلاس‌ها و کلاس‌های ارثی قابل دسترسی هستند.

مثال کپسوله‌سازی

در مثال زیر، یک کلاس Account طراحی شده است که ویژگی balance به‌عنوان داده‌ای خصوصی (private) تعریف شده است و از دسترسی مستقیم به آن جلوگیری می‌شود. برای دسترسی به آن، از متدهای عمومی (public) به نام deposit و getBalance استفاده می‌شود:

#include <iostream>
using namespace std;

class Account {
private:
    double balance;  // ویژگی private که از بیرون قابل دسترسی نیست

public:
    // سازنده برای مقداردهی اولیه به موجودی
    Account(double initialBalance) {
        if (initialBalance >= 0) {
            balance = initialBalance;
        } else {
            balance = 0;
        }
    }

    // متد برای واریز پول به حساب
    void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
        }
    }

    // متد برای دریافت موجودی
    double getBalance() {
        return balance;
    }
};

int main() {
    // ایجاد یک شیء از کلاس Account
    Account myAccount(1000);

    // واریز پول به حساب
    myAccount.deposit(500);

    // نمایش موجودی حساب
    cout << "Current balance: " << myAccount.getBalance() << endl;

    return 0;
}

توضیحات کد:
ویژگی balance: در کلاس Account، ویژگی balance به‌صورت private تعریف شده است، به این معنی که هیچ کدی از خارج از کلاس نمی‌تواند به‌طور مستقیم به آن دسترسی داشته باشد.
سازنده Account: سازنده‌ای برای این کلاس تعریف شده است که مقدار اولیه برای balance تعیین می‌کند. اگر مقدار منفی به سازنده داده شود، آن را به صفر تغییر می‌دهد.
متد deposit: این متد برای واریز پول به حساب طراحی شده است. اگر مقدار واریز شده بیشتر از صفر باشد، موجودی به‌روزرسانی می‌شود.
متد getBalance: این متد برای دریافت موجودی حساب از شیء استفاده می‌شود. به دلیل کپسوله‌سازی، فقط از طریق این متد می‌توان موجودی را مشاهده کرد.

دسترسی به داده‌ها از خارج کلاس

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

کپسوله‌سازی و امنیت داده‌ها

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

وراثت (C++ Inheritance)

وراثت یکی از ویژگی‌های اصلی برنامه‌نویسی شیءگرا است که به ما این امکان را می‌دهد که یک کلاس جدید ایجاد کنیم که ویژگی‌ها و رفتارهای یک کلاس موجود را به ارث می‌برد. این ویژگی به‌ویژه در زمانی که نیاز به استفاده مجدد از کد و توسعه کدهای قبلی داریم بسیار مفید است.

در C++، وراثت با استفاده از عملگر : public، protected یا private پیاده‌سازی می‌شود. با استفاده از وراثت، می‌توانیم کلاسی جدید بسازیم که تمامی ویژگی‌ها و متدهای کلاس پایه را داشته باشد و در صورت نیاز، ویژگی‌ها و رفتارهای جدیدی به آن اضافه کنیم.

انواع وراثت:

وراثت عمومی (Public Inheritance): اعضای public و protected کلاس پایه به ترتیب به اعضای public و protected در کلاس فرزند تبدیل می‌شوند.
وراثت محافظت‌شده (Protected Inheritance): اعضای public و protected کلاس پایه به اعضای protected در کلاس فرزند تبدیل می‌شوند.
وراثت خصوصی (Private Inheritance): تمام اعضای public و protected کلاس پایه به اعضای private در کلاس فرزند تبدیل می‌شوند.
مثال:

class Animal {
public:
    void eat() {
        cout << "Animal is eating" << endl;
    }
};

class Dog : public Animal {
public:
    void bark() {
        cout << "Dog is barking" << endl;
    }
};

int main() {
    Dog dog;
    dog.eat();  // از کلاس Animal ارث‌بری شده
    dog.bark(); // از کلاس Dog تعریف شده
    return 0;
}

در این مثال:

کلاس Dog از کلاس Animal ارث‌بری کرده است.
متد eat() که در کلاس Animal تعریف شده، در کلاس Dog به ارث می‌رسد و می‌تواند مورد استفاده قرار گیرد.
علاوه بر آن، کلاس Dog متد خاص خود به نام bark() را دارد.

کاربردهای وراثت:

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

چندریختی (C++ Polymorphism)

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

در C++، این ویژگی معمولاً با استفاده از توابع مجازی (virtual functions) و بازنویسی (overriding) متدها پیاده‌سازی می‌شود.

توابع مجازی (Virtual Functions):

توابع مجازی این امکان را فراهم می‌کنند که در کلاس پایه، متدی به‌طور عمومی تعریف شود و در کلاس‌های مشتق‌شده، این متد بازنویسی (override) شود تا رفتار متفاوتی داشته باشد. برای ایجاد یک تابع مجازی، باید آن را با کلمه‌کلیدی virtual در کلاس پایه علامت‌گذاری کنیم.

بازنویسی (Overriding):

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

مثال:

class Animal {
public:
    virtual void sound() {
        cout << "Animal sound" << endl;
    }
};

class Dog : public Animal {
public:
    void sound() override {
        cout << "Bark" << endl;
    }
};

class Cat : public Animal {
public:
    void sound() override {
        cout << "Meow" << endl;
    }
};

int main() {
    Animal* animal1 = new Dog();
    Animal* animal2 = new Cat();

    animal1->sound(); // "Bark"
    animal2->sound(); // "Meow"

    delete animal1;
    delete animal2;
    return 0;
}

در این مثال:

کلاس Animal یک تابع مجازی به نام sound() دارد که در ابتدا یک پیغام کلی “Animal sound” چاپ می‌کند.
کلاس‌های Dog و Cat این تابع را بازنویسی کرده‌اند تا صداهای مخصوص خود را چاپ کنند.
در متد main، از اشاره‌گرهای نوع Animal استفاده شده تا نشان‌دهنده اشیاء از نوع Dog و Cat باشد. زمانی که تابع sound() فراخوانی می‌شود، به جای اینکه متد عمومی کلاس پایه فراخوانی شود، متدهای بازنویسی شده در کلاس‌های مشتق‌شده فراخوانی می‌شود. این رفتار، ویژگی چندریختی را نشان می‌دهد.

انواع چندریختی:

چندریختی زمانی که از اشاره‌گر به شیء استفاده می‌شود: این زمانی است که یک اشاره‌گر به کلاس پایه به شیء از کلاس مشتق‌شده اشاره دارد. در اینجا، متدهای بازنویسی شده کلاس‌های مشتق‌شده به‌درستی فراخوانی می‌شوند.
چندریختی زمانی که از ارجاع به شیء استفاده می‌شود: مشابه حالت اشاره‌گر، اما با ارجاع به شیء، به‌گونه‌ای که بدون استفاده از اشاره‌گر یا اشاره‌گر به شیء، بازنویسی متدها فعال می‌شود.

مزایای چندریختی:

انعطاف‌پذیری بالا: این ویژگی اجازه می‌دهد تا با استفاده از یک رابط عمومی، عملکردهای متفاوتی از کلاس‌های مختلف دریافت کنیم.
کاهش پیچیدگی کد: با استفاده از چندریختی، می‌توان کدهای ساده‌تر و قابل نگهداری‌تری نوشت، زیرا نیازی به نوشتن کدهای تکراری برای هر نوع شیء نیست.
گسترش پذیری: این امکان وجود دارد که کد موجود را بدون تغییر در آن گسترش دهیم و ویژگی‌های جدیدی اضافه کنیم.

نتیجه‌گیری

برنامه‌نویسی شیءگرا در C++ یک روش قدرتمند و موثر برای توسعه نرم‌افزارهای پیچیده و مقیاس‌پذیر است. با استفاده از مفاهیمی مانند کلاس‌ها، اشیاء، وراثت، چندریختی و کپسوله‌سازی، می‌توانیم ساختارهایی منظم و انعطاف‌پذیر برای برنامه‌ها ایجاد کنیم که نگهداری و توسعه آن‌ها را ساده‌تر می‌کند.

کلاس‌ها و اشیاء اساس برنامه‌نویسی شیءگرا در C++ را تشکیل می‌دهند و امکان استفاده مجدد از کد و گسترش آن را فراهم می‌آورند. وراثت به ما اجازه می‌دهد که کدهای موجود را گسترش دهیم و رفتارهای جدیدی را اضافه کنیم، در حالی که چندریختی این امکان را می‌دهد که متدهای یکسان را برای اشیاء مختلف با رفتارهای متفاوت پیاده‌سازی کنیم.

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

آموزش برنامه‌نویسی شیءگرا در C++

دیدگاه های شما

دیدگاهتان را بنویسید

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