Codeblocks/Codelite/Eclipse
বা সমমানের IDE বা C++ কম্পাইলার, Text Editor – Syntax Highlighter
সহ
আজকে Arduino
নিয়ে তেমন কথা হবে না। শুধু OOP
বা Object Oriented Programming
নিয়েই আলোচনা করা হবে। OOP
মূলত আলোচনা করা হবে C++
ল্যাঙ্গুয়েজে। C++
জানেন না, কোন সমস্যা নেই, যেকোন একটা ল্যাঙ্গুয়েজে OOP
আয়ত্ব করলেই হয়, তবে ল্যাঙ্গুয়েজভেদে এর ইম্প্লিমেন্টেশন আলাদা হয়। অবশ্যই OOP
একটি বিশাল জিনিস কিন্তু এখানে মোটমাট ২ ভাগে OOP
আলোচনা করা হবে কারণ ইচ্ছা করলেই কম কথায় OOP
এর বেসিক জিনিসগুলো তুলে ধরা যাবে কিন্তু সেটা পরবর্তীতে সমস্যা তৈরি করতে পারে তাই সবদিক বিবেচনা করে OOP
এর পোস্টটা যতটা পারা যায় Informative ও Implementation বেজড রাখার চেষ্টা করা হবে।
আমরা যখনই কোন প্রোগ্রাম লিখি তখন নিচের মডেলগুলোর মধ্যে যেকোন একটি মডেলকে অনুসরণ করে প্রোগ্রাম লিখে থাকি। অনেক মডেলই আছে এবং কিছু কিছু প্রোগ্রামিং ল্যাঙ্গুয়েজ নির্দিষ্ট কিছু মডেল মেনে চলে। Java
কে একটি পিওর OOP
ল্যাঙ্গুয়েজ বলা চলে। কারণ Java
কোড চালাতে গেলে আপনাকে কমপক্ষে একটি ক্লাস ও একটি মেইন ফাংশন ব্যবহার করতেই হবে। আবার C++
এ আমরা Procedural/Functional/OOP
ইত্যাদি যেকোন মডেল অ্যাপ্লাই করতে পারি। আমি এখানে দুইটি মডেলের কথা বলছি।
একে Imperative Programming
বলা হয়ে থাকে। C
তে আমরা যেসব কোড লিখি তা প্রায় সবই Procedural
। কারণ কোডটি শুরু থেকে শেষ পর্যন্ত চলে এবং লাইন বাই লাইন (পড়ুন স্টেটমেন্ট বাই স্টেটমেন্ট) এক্সিকিউট হয়। অন্য কথায় Top To Bottom Approach
। যখন একটা নির্দিষ্ট কাজ আমাদের করতে হয় এবং তার জন্য এমন একটি প্রোগ্রাম লিখলেই হয় যেটা টপ টু বটম রান করবে এবং সমস্যাটি সমাধান করবে তখন আমরা Procedural প্রোগ্রামিং মডেল ব্যবহার করে থাকি। এই মডেলে একাধিক ফাংশন ও একটি মেইন ফাংশন ব্যবহার করা হয়। BASIC, Pascal ও C তে Procedural Programming
মডেল অনুসরণ করা হয়। সফটওয়্যার ডেভেলপিংয়ে এর প্রয়োগ নেই বললেই চলে। C তে একটি Procedural Programming এর উদাহরণ:
int add(int a, int b);int main(){int firstNum = 6;int secondNum = 15;int sum;sum = add(firstNum,secondNum);printf("sum= ",sum);return 0;}int add(int a,int b){int result;result = a + b;return result;}
একই প্রোগ্রাম যদি আমরা C++
এ অবজেক্ট ওরিয়েন্টেড স্টাইলে লিখি তাহলে হবে এইরকম:
#include <iostream>class addNumbers{public:int sum;addNumbers(int, int); // এটা হল Constructor, Constructor কিছু রিটার্ন করে না, চিন্তা করার কিছু নেই পরে আলোচনা করা হবে};addNumbers::addNumbers(int num1, int num2){sum = num1 + num2;}int main(){addNumbers object(1,2);std::cout << "Sum: " << object.sum;}
Object Oriented Programming
এর অ্যাপ্রোচ বটম টু টপ। অবজেক্ট ওরিয়েন্টেড ডিজাইনে যেটা থাকতেই হবে তা হল ক্লাস ও অবজেক্ট। এটা ছাড়া OOP
চিন্তাই করা যায় না। বেশ কয়েকটি কারণে সফটওয়্যার ডেভেলপিং থেকে হার্ডওয়্যার প্রোগ্রামিংয়ে এর জনপ্রিয়তা চরম পর্যায়ের। OOP
এর এই কারণ বা ফিচারগুলো হল:
Class, Object
Encapsulation
Inheritance
Polymorphism
এগুলোর পাশাপাশি যেটা আলোচনা করা হবে: Constructor, Destructor
আমাদের আশেপাশে যা আছে তাই Object
এবং কতগুলো Object
এর বৈশিষ্ট্য অনুযায়ী তাদেরকে একটা নির্দিষ্ট দলে ফেলা যায়। এই কনসেপ্টের উপর ভিত্তি করে Object
গুলোকে একটি নির্দিষ্ট Class
দ্বারা ডিফাইন করা হয়ে থাকে। আমরা গৃহপালিত পশুদেরকে একটি ক্লাস এর আওতায় আনি, নাম দিলাম Pet
। C++
এ Pet
কে ক্লাস হিসেবে ডিফাইন করতে হলে আমাদের লিখতে হবে class* Pet
। আচ্ছা, এবার Pet
দের আমরা কি কি করি? তাদের নাম দিই, খাবার খেতে দিই এবং তাদের ধরণ অনুযায়ী আমাদের তারা Feedback দেয়। এই Feedback, Pet
এর Object
ভেদে বিভিন্ন ধরণের হতে পারে। কিন্তু ভালভাবে লক্ষ্য করলে দেখা যাবে তাদের কিছু সাধারণ বা Common
বৈশিষ্ট্য ('Properties')
আছে। যেমন তারা খাবার খায়, ডাক দেয়, নাম ধরে ডাকলে সাড়া দেয়, এবং ভাল ট্রেনিং পেলে অনেক কিছু করে দেখাতে পারে। তাহলে Pet
ক্লাসের Object
গুলোর Name, age
ইত্যাদি হল তার Attributes
, আর খাবার খাওয়া, ডাক দেওয়া ইত্যাদি কাজগুলো তার Method
বা প্রোগ্রামিংয়ে আমরা Function
আকারে লিখে থাকি। Method গুলোকে আবার Member Function
হিসেবেও ডাকা হয়।
class Pet{public:string name;void eat();void utter();};
আপাতত public:
** নিয়ে চিন্তা করার দরকার নাই। পরের লাইনগুলো দেখা যাক।
আমি name
ভ্যারিয়েবলকে string
টাইপ হিসেবে ডিফাইন করলাম, তার Method
গুলোকে ফাংশন হিসেবে ডিফাইন করলাম। যেটা মনে রাখতে হবে সেটা হল class Pet { // blablabla };
<- এই সেমিকোলনটার কথা।
আমি এখানে মেথডগুলোর একটা লিস্ট দেখিয়েছি। কিন্তু Method
গুলো কীভাবে কাজ করবে সেটা লিখিনি। Method
গুলো কীভাবে কাজ করবে সেটা দুইভাবে দেখানো যায়।
ক্লাসের ভিতরে [Inside of Class]
ক্লাসের বাইরে [Outside of Class]
উপরের প্রোগ্রামটি যদি আমি ক্লাসের ভিতরে লিখে দেখাই তাহলে এমন হবে:
class Pet{public:string name;void eat(){cout << "Gulp gulp gulp..... ... .." << endl;}void utter(){cout << "meaw .... meaw ..." << endl;}};
ঠিক যেমন আমরা ফাংশন ডিফাইন করি ওইভাবেই। এবার ক্লাসের বাইরে লিখলে দেখাবে:
class Pet{public:string name;void eat();void utter();};void Pet::eat(){cout << "Gulp ... gulp... gulp.." << endl;}void Pet::utter(){cout << "Meaw..... meaw.... " << endl;}
প্রথমে আমরা একটা লিস্ট দিলাম কি কি থাকবে, তারপর Method গুলো কীভাবে কাজ করবে সেটা লিখলাম। তাহলে, C++
এ ক্লাসের বাইরে Method
ডিফাইন করার নিয়ম হল:
//[returnType] [ClassName] :: [methodName(argument)]//Here-> '::' is called Scope Resolution Operatorvoid Pet :: eat(){// Code goes Here}
‘::’
কে স্কোপ রেজোল্যুশন অপারেটর বলা হয়। নামটা অনেক ভারী হলেও কাজটা সহজ। খালি বলে দেওয়া কোন ফাংশন কোন ক্লাসে থাকে :)
ক্লাস তৈরি করা
ক্লাসের জন্য Attribute
ও Method
তৈরি করা
Method
কে ক্লাসের ভিতরে ও বাইরে কীভাবে ডিফাইন করা যায়
Object
তৈরি করা
Object
এর Variable
বা Attribute এ Value
বসানো
Object
এর Method Call
করা
object
কে Argument
হিসেবে Pass
করা
Class, object
ব্যবহার করে একটি পূর্ণাঙ্গ প্রোগ্রাম তৈরি করা
এই পর্যন্ত যেসব কিছু শেখা হয়ে গেল তা কি আসলেই শিখেছেন? না শিখলে কষ্ট করে আরেকটিবার পড়ুন, বুঝতে সমস্যা হলে Comment করুন। সামনে আরেকটু জটিল হতে পারে।
class Pet {}; // Assume it is the classint main(){Pet dog; // Object Created!}// className objectName /* To create an object */
#include <iostream>using namespace std;class Pet{public:string name;};int main(){Pet dog, cat;dog.name = "Tommy";cat.name = "Tom";cout << "Name of the cat is: " << cat.name << endl;cout << "Name of the dog is: " << dog.name << endl;}
প্রোগ্রামে দেখা যাচ্ছে আমরা Pet
ক্লাস দিয়ে দুইটি অবজেক্ট তৈরি করেছি। ধরলাম, একটা হল Dog
আরেকটা হল Cat
।পোষাপ্রাণীর নাম রাখা বাঞ্ছনীয় তাই dog
এর নাম দিলাম Tommy
এবং cat
এর নাম দিলাম Tom
। এখানে আরেকটি ব্যাপার লক্ষ্যণীয়, আমরা নাম দেওয়ার সময় dot operator
বা objectName.variable = “Value”
। Scope Resolution Operatorএর কাজ হল কোন
Member Functionকোন
Classএর অন্তর্ভুক্ত। আর
Dot operatorএর কাজ হল
Objectএর নির্দিষ্ট কোন
Member Functionবা
Variable এ Accessদেওয়া।
nameএকটি
stringটাইপ ভ্যারিয়েবল
Petক্লাসের জন্য। কিন্তু মজার বিষয় হল
Petক্লাসে আমি দুইটি
Object` তৈরি করে তাদের ভিন্ন ভিন্ন নাম দিয়েছি যদিও তারা একই ক্লাসের অন্তর্ভুক্ত।
ধরি, variable = cat.name
, তাহলে cat.name = “Tom”
হবে, variable = “Tom”
, মানে “Tom”
স্ট্রিংকে আমরা স্ট্রিংটাইপ ভ্যারিয়েবলে বসালাম (অবশ্যই cat অবজেক্টের variable এ)।
উপরের প্রোগ্রামের আউটপুট:
Name of the cat is: TomName of the dog is: Tommy
আর এই ছবিটি হল অবজেক্ট তৈরি করার পরে:
আগের মতই, object.functionName(argument)
এভাবে অবজেক্টের Method
কে Call
করা যায়।
#include <iostream>using namespace std;class Pet{public:string name;void sayName(){cout << "My name is " << name << endl;}};int main(){Pet cat;cat.name = "Thomas";cat.sayName();}
প্রোগ্রামে প্রথমে cat Object
এর নাম অ্যাসাইন করলাম। এবং অ্যাসাইন করার পর sayName()
ফাংশনটি Call
করলাম।
আউটপুট:
My name is Thomas
#include <iostream>using namespace std;class Pet{public:string name;};void sayName(Pet petObject, string petName) // This is NOT A MEMBER FUNCTION, it is just a function in the program!{petObject.name = petName; // Name has been assigned by taking the name from the argumentcout << "Name of the pet is: " << petObject.name << endl;}int main(){Pet cat;sayName(cat, "Thomas"); // This will print "Name of the pet is: Thomas"cout << cat.name << endl; // This will print nothing!!!}
আমরা জানি, ফাংশনে আর্গুমেন্ট পাস করা যায় দুইভাবে, Pass by reference
এবং Pass by value
হিসেবে। উপরেরটা হল Pass by Value
। প্রোগ্রামে void sayName
ফাংশনটি কোন ক্লাসের অন্তর্ভুক্ত নয়, এটি একটি অবজেক্ট ও একটি স্ট্রিংকে আর্গুমেন্ট হিসেবে নিয়ে, অবজেক্টের Attribute name
এ শুধু string
টা বসিয়ে দিয়েছে, এবং পরের স্টেটমেন্টে প্রিন্ট করে দেখিয়েছে।
আউটপুট:
Name of the pet is: Thomas
আমরা যদি মূল প্রোগ্রাম [int main() অংশ]
লক্ষ্য করি তাহলে দেখতে পাব, sayName
এ আমরা cat
অবজেক্ট পাস করে ফাংশনের মাধ্যমে cat
এর নাম আউটপুটে দেখতে পাচ্ছি। যদি আমি cat.name
কে cout
করি তাহলে কিছুই দেখা যাচ্ছে না। কারণ কি? কারণ হল Pass by value
।
ধরুন, আমি আপনাকে একটি ওয়েবপেইজের লিঙ্ক দিলাম (URL)
। এখন যদি ওই লিঙ্কে কোন পরিবর্তন হয়, তাহলে পরিবর্তন যেমন আপনিও দেখতে পারবেন আমিও পারব। যদি আপনি আপনার পিসি থেকে লিঙ্কটি ডিলেট করে দেন তাহলে ওয়েবপেজের কিছুই হবে না। এটাই হল Pass by reference
।
যদি আমি আপনাকে ওই URL
এর একটি পেজ প্রিন্ট করে দেই তাহলে সেটি হবে Pass by value
, যদি ওই URL
এর ওয়েবপেজে কোন পরিবর্তন আসে তাহলে নিশ্চয়ই আপনি আপনার প্রিন্টকৃত পেজটিতে দেখতে পাবেন না। এবং যদি ওটা আপনি নষ্ট করে দেন তাহলে আপনি নিজের কপিটি ধ্বংস করলেন। অর্জিনাল কপি ঠিকি তাদের ওয়েবসাইটে থাকবে।
উপরের প্রোগ্রামটি Pass by value
হওয়ার কারণে মূল কপির কোন পরিবর্তন হয় নি।
একই প্রোগ্রাম আমি যদি Pass by reference
দিয়ে লিখি তাহলে:
......void sayName(Pet &petObject, string petName) // I just put an & before the object!{petObject.name = petName;cout << "Name of the pet is: " << petObject.name << endl;}int main(){Pet cat;sayName(cat, "Thomas"); // This will print "Name of the pet is: Thomas"cout << cat.name << endl; // This will print "Thomas"}
এটার আউটপুট:
Name of the pet is: ThomasThomas
Pass by reference
এ আমি cat
এর লোকেশন পাঠাই &
চিহ্নটির মাধ্যমে। আমি cat
অবজেক্টটি তৈরি করে তার লোকেশন ফাংশনে পাঠালাম এবং ফাংশনটি নতুন অবজেক্ট তৈরি না করে (আসলে নতুন অবজেক্ট তৈরি করলেও লোকেশন একই নির্দেশ করছে) cat
অবজেক্টের লোকেশনের name
টা পরিবর্তন করে দিল। Pass by Value
তে যে অবজেক্টটি তৈরি করে অর্থাৎ, petObject != cat [Not equal]
কিন্তু Pass by reference
এ petObject == cat
কারণ দুটি অবজেক্ট মূলত একটাই লোকেশন নির্দেশ করে আর সেটা হল cat
এর লোকেশন। তাই petObject
এর name
পরিবর্তিত হওয়া মানে কিছুই না cat
এর name
পরিবর্তিত হওয়া যেহেতু তাদের লোকেশন একই!
নিচের কোডটি রান করলে Led blinking
দেখতে পাবেন কনসোলে, মানে কিছু বোরিং টেক্সট আপনাকে দেখাবে কত নাম্বার পিনে led জ্বলছে, কত টাইম নিয়ে ব্লিংকিং করছে এই আরকি।
#include <iostream>#include <Windows.h>using namespace std;class Led{public:int ledPin;Led(int pinNumber);void pinMode(int);void blinkLed(int delay);};Led::Led(int pinNumber){ledPin = pinNumber;pinMode(pinNumber);}void Led::pinMode(int pin){cout << pin << " is set as output" << endl;}void Led::blinkLed(int delay){cout << "Led at " << ledPin << " is on" << endl;Sleep(delay);cout << "Led at " << ledPin << " is off" << endl;Sleep(delay);}int main(){int usDelay, pinNumber, turn;cout << "Enter Delay, Pin number and Turns [sequentially, example: 1000 13 2]: ";cin >> usDelay, cin >> pinNumber, cin >> turn;Led led(pinNumber);while (turn > 0){led.blinkLed(usDelay);turn--;}}
Enter Delay, Pin number and Turns [sequentially, example: 1000 13 2]: 1000 13 213 is set as outputLed at 13 is onLed at 13 is offLed at 13 is onLed at 13 is off
Access Modifiers:
C++
এ তিন ধরণের Access Modifiers
আছে, public, private ও protected
। এটা Encapsulation
বা Data Hiding
এর অন্তর্গত। তাই এখানে আলোচনা না করে পরবর্তী মূল পোস্টে আলোচনা করা হবে।
এখানে UML Diagram
বলতে আমরা Class
কে চিত্র দ্বারা প্রকাশ বুঝাব [Class Diagram]
। এটি বিশাল জিনিস এবং এই সিরিজের আলোচ্য বিষয়বস্তু না। নিচে একটি ক্লাস ডায়াগ্রাম (উইকিপিডিয়া থেকে সংগৃহীত):
সবার উপরের অংশ হল Class Name
। এটা বোল্ড হয় ও মাঝখানে থাকে, প্রথম বর্ণটি Capitalized
থাকে
মাঝের অংশে Attributes
বা Variable
থাকে। Left aligned
ও প্রথম বর্ণ Lowercase
শেষের অংশে Method
থাকে। Left aligned
ও প্রথম বর্ণ
Attributes ও Method
এর আগে নিচের টেবিলের চিহ্ন থাকতে পারে [Access Modifier -> +, -, #; Package -> ~, Derived-> / ]
আজকে এই পর্যন্তই, পরবর্তী পরিচ্ছদে OOP এর বাকি বেসিক টপিকগুলো নিয়ে আলোচনা করা হবে।