Object-Oriented ProgrammingObject-Oriented Programming

Classes, objects, inheritance, polymorphism — the C++ ideas BUET loves to test. Class, object, inheritance, polymorphism — C++ এর যেসব idea BUET পরীক্ষায় বারবার আসে।

1. Classes and Objects1. Classes and Objects

A class is a blueprint. It describes what data a thing has, and what actions it can do. An object is a real thing made from that blueprint.

Think of it like this: "Student" is a class. It says every student has a name and a roll. "Rahim, roll 101" is an object. You can make many objects from one class.

  • Class = idea / design / template. Takes no memory by itself.
  • Object = real instance. Each object gets its own memory for the data members.
  • The data inside a class are called data members. The functions inside are called member functions (or methods).

Class হলো একটা blueprint বা নকশা। এটা বলে দেয় কোনো জিনিসের কী কী data থাকবে আর সে কী কী কাজ করতে পারবে। Object হলো সেই নকশা থেকে বানানো আসল জিনিস।

এভাবে ভাবুন: "Student" একটা class। এটা বলে প্রতিটা student-এর একটা name আর roll থাকবে। "Rahim, roll 101" হলো একটা object। একটা class থেকে অনেকগুলো object বানানো যায়।

  • Class = idea / design / template। এটা নিজে কোনো memory নেয় না।
  • Object = আসল instance। প্রতিটা object-এর data member-দের জন্য আলাদা memory থাকে।
  • Class-এর ভেতরের data-কে বলে data member। ভেতরের function-কে বলে member function (বা method)।
A class with attributes and methods, and objects created from it
One class (blueprint) with attributes and methods — many objects made from it. একটা class (blueprint), তার attribute আর method — সেখান থেকে অনেক object তৈরি হয়।
Example: A simple class with objects. একটা simple class আর তার object।
#include <iostream>
using namespace std;

class Student {
public:
    string name;      // data member
    int roll;         // data member

    void show() {     // member function
        cout << name << " " << roll << endl;
    }
};

int main() {
    Student a, b;           // two objects
    a.name = "Rahim"; a.roll = 101;
    b.name = "Karim"; b.roll = 102;
    a.show();
    b.show();
    return 0;
}
// Output:
// Rahim 101
// Karim 102

Here a and b each have their own name and roll. Changing a.roll does not touch b.roll. এখানে a আর b — দুজনের নিজের নিজের name আর roll আছে। a.roll বদলালে b.roll বদলায় না।

Access specifiers: public, private, protectedAccess specifiers: public, private, protected

Access specifiers control who can touch a member from outside the class.

Access specifier ঠিক করে দেয় class-এর বাইরে থেকে কে কোন member ধরতে পারবে

SpecifierSpecifier Inside the classClass-এর ভেতরে In derived classDerived class-এ Outside (main etc.)বাইরে (main ইত্যাদি)
public Yesহ্যাঁ Yesহ্যাঁ Yesহ্যাঁ
protected Yesহ্যাঁ Yesহ্যাঁ Noনা
private Yesহ্যাঁ Noনা Noনা
Example: private members give a compile error outside the class. private member বাইরে থেকে ধরলে compile error হয়।
class Account {
private:
    double balance;      // hidden
public:
    void setBalance(double b) { balance = b; }
    double getBalance()       { return balance; }
};

int main() {
    Account acc;
    acc.balance = 5000;        // ERROR! balance is private
    acc.setBalance(5000);      // OK
    cout << acc.getBalance();  // OK, prints 5000
}

struct vs class in C++C++ এ struct vs class

In C++, a struct can also have member functions, constructors, even inheritance. The only real difference is the default access.

C++ এ struct-এও member function, constructor, এমনকি inheritance থাকতে পারে। আসল পার্থক্য একটাই — default access।

struct class
Default member accessDefault member access public private
Default inheritance modeDefault inheritance mode public private
Common useসাধারণ ব্যবহার Simple data bundlesSimple data একসাথে রাখা Full OOP with hidden dataData লুকিয়ে full OOP

The this pointerthis pointer

Inside a member function, this is a pointer to the object that called the function. It is passed automatically. Two common uses:

  • Separate a data member from a parameter with the same name: this->x = x;
  • Return the current object for chaining: return *this;

Member function-এর ভেতরে this হলো একটা pointer, যেটা সেই object-কে point করে যে function-টা call করেছে। এটা automatic pass হয়। দুইটা common ব্যবহার:

  • Data member আর same নামের parameter আলাদা করা: this->x = x;
  • Chaining-এর জন্য current object return করা: return *this;
Example: this pointer solving a name clash, and chaining. this pointer দিয়ে name clash সমাধান, আর chaining।
class Box {
    int w;
public:
    Box& setW(int w) {
        this->w = w;     // left w = member, right w = parameter
        return *this;    // return the object itself
    }
    void show() { cout << "w = " << w << endl; }
};

int main() {
    Box b;
    b.setW(10).show();   // chaining works because setW returns *this
}
// Output:
// w = 10
Note: Exam favorites: (1) default access of class is private, of struct is public. (2) A class takes no memory; sizeof an empty class object is 1 byte (so each object has a unique address). (3) this is not available inside static member functions — they belong to the class, not to any object. পরীক্ষায় প্রিয় প্রশ্ন: (১) class-এর default access private, struct-এর public। (২) Class নিজে memory নেয় না; empty class-এর object-এর sizeof হয় 1 byte (যাতে প্রতিটা object-এর আলাদা address থাকে)। (৩) static member function-এর ভেতরে this পাওয়া যায় না — কারণ ওগুলো object-এর না, class-এর।

Class design: many-to-many (Employee — Project)Class design: many-to-many (Employee — Project)

BUET sometimes gives a real-life situation and asks you to design the classes. A classic one: one Employee can work on many Projects, and one Project can have many Employees. This is a many-to-many relationship. The clean trick: put a third class in the middle — an association class, here called Assignment. One Assignment object means "this employee works on this project". It is also the natural home for extra data that belongs to the pair, like hours per week or role.

BUET মাঝে মাঝে একটা real-life situation দিয়ে বলে class design করতে। Classic উদাহরণ: একজন Employee অনেকগুলো Project-এ কাজ করতে পারে, আবার একটা Project-এ অনেকজন Employee থাকতে পারে। এটাই many-to-many relationship। সহজ সমাধান: মাঝখানে তৃতীয় একটা class বসান — একটা association class, এখানে নাম Assignment। একটা Assignment object মানে "এই employee এই project-এ কাজ করে"। যে data জোড়াটার নিজের (যেমন hours per week বা role), তার জায়গাও এই class-এই।

RelationshipRelationship Meaningমানে
Employee 1 — * Assignment One employee has many assignmentsএকজন employee-র অনেকগুলো assignment থাকে
Project 1 — * Assignment One project has many assignmentsএকটা project-এর অনেকগুলো assignment থাকে
Employee * — * Project The two 1-to-many links together give the many-to-manyদুইটা 1-to-many link মিলে many-to-many তৈরি হয়
Example: A small code sketch of the design (only fields and links matter here, not full methods). Design-এর ছোট একটা code sketch (এখানে field আর link-ই আসল, full method না)।
class Employee;              // forward declarations
class Project;

class Assignment {           // association class: one (employee, project) pair
public:
    Employee* employee;      // who
    Project*  project;       // on what
    int    hoursPerWeek;     // extra data about the PAIR lives here
    string role;             // e.g., "tester", "lead"
};

class Employee {
public:
    int id;
    string name;
    vector<Assignment*> assignments;   // one employee → many assignments
};

class Project {
public:
    int code;
    string title;
    vector<Assignment*> assignments;   // one project → many assignments
};
To list all projects of an employee: walk her assignments and follow each project pointer. To list all employees of a project: same idea from the other side. একজন employee-র সব project বের করতে: তার assignments ঘুরে প্রতিটার project pointer follow করুন। একটা project-এর সব employee বের করতে: উল্টো দিক থেকে একই idea।
Note: This exact design (Employees and Projects, many-to-many) was asked in the BUET October 2018 exam. Remember the pattern: many-to-many = two classes + one association class in the middle, each side holding a collection (like a vector) of the middle class. It is the same idea as a junction table in databases. ঠিক এই design-টাই (Employees আর Projects, many-to-many) BUET October 2018 পরীক্ষায় এসেছিল। Pattern-টা মনে রাখুন: many-to-many = দুইটা class + মাঝখানে একটা association class, আর দুই পাশের class-ই মাঝের class-টার একটা collection (যেমন vector) রাখে। Database-এর junction table-এর idea-টাই এখানে।

2. Encapsulation and Abstraction2. Encapsulation and Abstraction

EncapsulationEncapsulation

Encapsulation means wrapping data and the functions that work on that data into one unit (a class), and hiding the data from outside. Outsiders talk to the object only through public functions.

Why hide data?

  • Safety: no one can set an invalid value directly (like a negative balance).
  • Control: you can add checks inside setters.
  • Freedom to change: you can change the inside of the class later without breaking outside code.

Encapsulation মানে data আর সেই data নিয়ে কাজ করা function-গুলোকে এক unit-এ (class-এ) বেঁধে ফেলা, আর data-কে বাইরের থেকে লুকিয়ে রাখা। বাইরের কেউ object-এর সাথে কথা বলবে শুধু public function দিয়ে।

Data লুকাই কেন?

  • Safety: কেউ সরাসরি ভুল value বসাতে পারবে না (যেমন negative balance)।
  • Control: setter-এর ভেতরে check বসানো যায়।
  • বদলানোর স্বাধীনতা: পরে class-এর ভেতরটা বদলালেও বাইরের code ভাঙে না।
Example: Getters and setters with validation. Validation সহ getter আর setter।
class BankAccount {
private:
    double balance;   // hidden data
public:
    BankAccount() { balance = 0; }

    void deposit(double amount) {          // setter-style
        if (amount > 0) balance += amount; // validation!
    }
    bool withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
            return true;
        }
        return false;
    }
    double getBalance() { return balance; } // getter
};

int main() {
    BankAccount acc;
    acc.deposit(1000);
    acc.deposit(-500);              // ignored: validation blocks it
    acc.withdraw(300);
    cout << acc.getBalance();       // 700
}
// Output: 700

Nobody can write acc.balance = -999;. The data is safe behind the public functions. কেউ acc.balance = -999; লিখতে পারবে না। Public function-এর পেছনে data নিরাপদ।

AbstractionAbstraction

Abstraction means showing only the essential things and hiding the details of how it works. When you press a car's brake, you do not think about the brake wires. Same idea: the user of a class sees what it does, not how.

In C++, abstraction is done by:

  • Public interface + private implementation (access specifiers).
  • Abstract classes — classes with at least one pure virtual function. They give only the "what", and derived classes fill in the "how". You cannot create an object of an abstract class.

Abstraction মানে শুধু দরকারি জিনিসটা দেখানো, আর কীভাবে কাজটা হয় সেই details লুকানো। গাড়ির brake চাপলে আপনি brake-এর ভেতরের তার নিয়ে ভাবেন না। একই idea: class-এর user দেখে কী হয়, কীভাবে হয় তা না।

C++ এ abstraction করা হয়:

  • Public interface + private implementation দিয়ে (access specifier)।
  • Abstract class দিয়ে — যে class-এ অন্তত একটা pure virtual function আছে। এরা শুধু "কী করতে হবে" বলে, derived class "কীভাবে" সেটা লেখে। Abstract class-এর object বানানো যায় না।
Example: A tiny abstract class (details come in Section 5). ছোট্ট একটা abstract class (details Section 5-এ আসবে)।
class Shape {                    // abstract class
public:
    virtual double area() = 0;   // pure virtual: only "what"
};

class Circle : public Shape {
    double r;
public:
    Circle(double r) { this->r = r; }
    double area() { return 3.1416 * r * r; }   // the "how"
};

int main() {
    // Shape s;        // ERROR: cannot create object of abstract class
    Circle c(2);
    cout << c.area();  // 12.5664
}
Encapsulation Abstraction
Main ideaমূল idea Hide the data, bundle data + functionsData লুকানো, data + function একসাথে বাঁধা Hide the implementation details, show only interfaceImplementation details লুকানো, শুধু interface দেখানো
FocusFocus "How data is protected""Data কীভাবে protect হয়" "What the object can do""Object কী করতে পারে"
C++ toolsC++ tools private, protected, getters/setters abstract class, pure virtual function, interfaceabstract class, pure virtual function, interface
LevelLevel Implementation levelImplementation level Design levelDesign level
Note: A classic exam question: "Difference between encapsulation and abstraction?" Short answer: encapsulation hides data (information hiding), abstraction hides complexity/implementation. Encapsulation is one way to achieve abstraction. Also remember the 4 pillars of OOP: Encapsulation, Abstraction, Inheritance, Polymorphism. Classic পরীক্ষার প্রশ্ন: "Encapsulation আর abstraction-এর পার্থক্য?" ছোট উত্তর: encapsulation লুকায় data (information hiding), abstraction লুকায় complexity/implementation। Encapsulation আসলে abstraction পাওয়ার একটা উপায়। OOP-এর ৪টা pillar মনে রাখুন: Encapsulation, Abstraction, Inheritance, Polymorphism

3. Constructors and Destructors3. Constructors and Destructors

A constructor is a special member function that runs automatically when an object is created. Rules:

  • Same name as the class.
  • No return type (not even void).
  • Can be overloaded (many constructors with different parameters).

A destructor (~ClassName()) runs automatically when an object is destroyed. It takes no parameters, has no return type, and there can be only one — so it cannot be overloaded.

Constructor হলো special member function, যেটা object তৈরি হওয়ার সময় automatic চলে। নিয়ম:

  • Class-এর নামের সাথে same নাম।
  • কোনো return type নেই (void-ও না)।
  • Overload করা যায় (আলাদা parameter দিয়ে অনেকগুলো constructor)।

Destructor (~ClassName()) object destroy হওয়ার সময় automatic চলে। এটা কোনো parameter নেয় না, return type নেই, আর একটাই থাকতে পারে — তাই overload করা যায় না।

Types of constructorsConstructor-এর ধরন

Example: Default, parameterized, and copy constructor together (constructor overloading). Default, parameterized আর copy constructor একসাথে (constructor overloading)।
#include <iostream>
using namespace std;

class Point {
    int x, y;
public:
    Point() {                    // 1. default constructor
        x = 0; y = 0;
        cout << "Default\n";
    }
    Point(int a, int b) {        // 2. parameterized constructor
        x = a; y = b;
        cout << "Parameterized\n";
    }
    Point(const Point &p) {      // 3. copy constructor
        x = p.x; y = p.y;
        cout << "Copy\n";
    }
    void show() { cout << "(" << x << "," << y << ")\n"; }
};

int main() {
    Point a;          // Default
    Point b(3, 4);    // Parameterized
    Point c = b;      // Copy  (same as Point c(b);)
    c.show();         // (3,4)
}
// Output:
// Default
// Parameterized
// Copy
// (3,4)
Note: When is the copy constructor called? Memorize these 3 cases: (1) an object is created from another object: Point c = b;, (2) an object is passed to a function by value, (3) an object is returned by value from a function. The copy constructor parameter must be a reference (const Point &p) — if it took the object by value, that pass-by-value would itself need a copy, causing infinite recursion. Copy constructor কখন call হয়? এই ৩টা case মুখস্থ রাখুন: (১) এক object থেকে আরেক object তৈরি: Point c = b;, (২) object কোনো function-এ by value pass করলে, (৩) function থেকে object by value return করলে। Copy constructor-এর parameter অবশ্যই reference হতে হবে (const Point &p) — value নিলে সেই pass-by-value-র জন্যই আবার copy লাগত, ফলে infinite recursion হতো।

Constructor and destructor orderConstructor আর destructor-এর order

Objects are destroyed in the reverse order of creation (like a stack). Also, in inheritance: base constructor runs first, derived constructor next; destructors run in reverse (derived first, then base).

Object যেভাবে তৈরি হয়, destroy হয় তার উল্টা order-এ (stack-এর মতো)। আর inheritance-এ: আগে base constructor, তারপর derived constructor; destructor চলে উল্টা করে (আগে derived, পরে base)।

Example: What is the output? (classic trace question) Output কী হবে? (classic trace প্রশ্ন)
class A {
    int id;
public:
    A(int i) { id = i; cout << "C" << id << " "; }
    ~A()     { cout << "D" << id << " "; }
};

int main() {
    A a1(1);
    A a2(2);
    A a3(3);
    return 0;
}
// Output:
// C1 C2 C3 D3 D2 D1

Creation order: 1, 2, 3. Destruction order: 3, 2, 1 — last created, first destroyed. তৈরির order: 1, 2, 3। Destroy-এর order: 3, 2, 1 — যে শেষে তৈরি, সে আগে destroy।

Shallow copy vs deep copyShallow copy vs deep copy

The compiler's free (default) copy constructor copies members one by one. If a member is a pointer, only the address is copied — both objects then point to the same memory. That is a shallow copy. Dangerous: when one object's destructor frees that memory, the other object holds a dangling pointer, and freeing again causes a double-free crash.

A deep copy allocates new memory and copies the actual data. You must write the copy constructor yourself for this.

Compiler-এর free (default) copy constructor member-গুলো একটা একটা করে copy করে। কোনো member যদি pointer হয়, শুধু address-টা copy হয় — তখন দুই object একই memory-কে point করে। এটাই shallow copy। বিপদ: এক object-এর destructor ওই memory free করলে অন্য object-এর কাছে dangling pointer থেকে যায়, আবার free করলে double-free crash।

Deep copy নতুন memory নিয়ে আসল data copy করে। এর জন্য copy constructor নিজে লিখতে হয়।

Shallow copy obj1.ptr obj2.ptr same data Both pointers → one memory block. Delete twice = crash! Deep copy obj1.ptr obj2.ptr data (own) data (own) Each object has its own memory. Safe to delete both.
Example: Writing a deep copy constructor. Deep copy constructor লেখা।
class MyArray {
    int *data;
    int n;
public:
    MyArray(int n) {
        this->n = n;
        data = new int[n];
    }
    // DEEP copy constructor
    MyArray(const MyArray &other) {
        n = other.n;
        data = new int[n];              // new memory!
        for (int i = 0; i < n; i++)
            data[i] = other.data[i];    // copy real values
    }
    ~MyArray() { delete[] data; }
};

int main() {
    MyArray a(5);
    MyArray b = a;   // deep copy: b gets its own memory
}   // both destructors run safely — no double free
Shallow copyShallow copy Deep copyDeep copy
What is copiedকী copy হয় Member values only (pointer = address)শুধু member value (pointer = address) Actual data, in new memoryআসল data, নতুন memory-তে
Who provides itকে দেয় Compiler defaultCompiler-এর default You write it yourselfনিজে লিখতে হয়
Riskঝুঁকি Dangling pointer, double freeDangling pointer, double free Safe (a bit slower)নিরাপদ (একটু slow)
Note: Rule of Three: if a class needs a custom destructor, copy constructor, or copy assignment operator, it almost always needs all three (this happens when the class manages a resource like new memory). BUET-style questions often show a class with new in the constructor and no copy constructor, then ask what goes wrong when you copy the object. Rule of Three: কোনো class-এর যদি custom destructor, copy constructor বা copy assignment operator-এর একটা লাগে, তাহলে প্রায় সবসময় তিনটাই লাগে (যখন class কোনো resource manage করে, যেমন new দিয়ে নেওয়া memory)। BUET-style প্রশ্নে প্রায়ই constructor-এ new আছে কিন্তু copy constructor নেই — এমন class দেখিয়ে জিজ্ঞেস করে object copy করলে কী সমস্যা হবে।

4. Inheritance4. Inheritance

Inheritance lets a new class (derived / child class) reuse the members of an existing class (base / parent class). The child gets everything the parent has (except private access), and can add its own members or change behavior.

Syntax: class Derived : public Base { ... };

Main benefit: code reuse, plus it enables runtime polymorphism (next section).

Inheritance দিয়ে একটা নতুন class (derived / child class) আগের একটা class-এর (base / parent class) member-গুলো reuse করতে পারে। Child তার parent-এর সবকিছু পায় (private access ছাড়া), আর চাইলে নিজের member যোগ করতে বা behavior বদলাতে পারে।

Syntax: class Derived : public Base { ... };

মূল লাভ: code reuse, আর এটাই runtime polymorphism-এর দরজা খোলে (পরের section)।

Five types of inheritanceInheritance-এর পাঁচ ধরন

Single A B Multiple A B C Multilevel A B C Hierarchical A B C Hybrid (diamond) A B C D
TypeType Meaningমানে ExampleExample
SingleSingle One base → one derivedএকটা base → একটা derived B : public A
MultipleMultiple One derived from two or more basesদুই বা বেশি base থেকে একটা derived C : public A, public B
MultilevelMultilevel Chain: grandparent → parent → childChain: grandparent → parent → child B : A, thenতারপর C : B
HierarchicalHierarchical Many derived from one baseএক base থেকে অনেক derived B : A, C : A
HybridHybrid Mix of two or more types (often makes a diamond)দুই বা বেশি ধরনের মিশ্রণ (প্রায়ই diamond তৈরি হয়) Multiple + hierarchicalMultiple + hierarchical
Example: Single inheritance and constructor order. Single inheritance আর constructor-এর order।
class Animal {
public:
    Animal()  { cout << "Animal made\n"; }
    ~Animal() { cout << "Animal gone\n"; }
    void eat() { cout << "eating\n"; }
};

class Dog : public Animal {
public:
    Dog()  { cout << "Dog made\n"; }
    ~Dog() { cout << "Dog gone\n"; }
    void bark() { cout << "woof\n"; }
};

int main() {
    Dog d;
    d.eat();    // inherited from Animal
    d.bark();   // Dog's own
}
// Output:
// Animal made      <- base constructor FIRST
// Dog made
// eating
// woof
// Dog gone         <- derived destructor FIRST
// Animal gone

Access modes of inheritanceInheritance-এর access mode

The word after the colon (: public / : protected / : private) sets how the base members appear inside the derived class. Rule of thumb: the base member's access becomes the more restrictive of its own access and the inheritance mode. Private members of the base are never directly accessible in the derived class.

Colon-এর পরের word-টা (: public / : protected / : private) ঠিক করে base-এর member-গুলো derived class-এ কেমন হয়ে ঢুকবে। সহজ নিয়ম: base member-এর access আর inheritance mode — দুটোর মধ্যে যেটা বেশি কড়া, সেটাই হয়। Base-এর private member derived class থেকে কখনোই সরাসরি ধরা যায় না।

Base member ↓ / Mode →Base member ↓ / Mode → public inheritanceinheritance protected inheritanceinheritance private inheritanceinheritance
public public protected private
protected protected protected private
private not accessibleধরা যায় না not accessibleধরা যায় না not accessibleধরা যায় না

The diamond problem and virtual base classDiamond problem আর virtual base class

In hybrid inheritance, a diamond shape can appear: B and C both inherit from A, and D inherits from both B and C. Now D contains two copies of A's members. Calling an A member through D becomes ambiguous — the compiler does not know which copy you mean.

Fix: make A a virtual base class: class B : virtual public A and class C : virtual public A. Then D keeps only one shared copy of A.

Hybrid inheritance-এ একটা diamond shape তৈরি হতে পারে: B আর C দুজনেই A থেকে inherit করে, আর D inherit করে B আর C দুজন থেকে। তখন D-এর ভেতরে A-এর member-দের দুইটা copy থাকে। D দিয়ে A-এর member call করলে ambiguous হয় — compiler বোঝে না কোন copy-টা চাইছেন।

সমাধান: A-কে virtual base class বানান: class B : virtual public A আর class C : virtual public A। তখন D-তে A-এর একটাই shared copy থাকে।

Diamond inheritance: D inherits from B and C, both of which inherit from A
The diamond problem: D reaches A through two paths (B and C). Diamond problem: D দুইটা path (B আর C) দিয়ে A-তে পৌঁছায়।
Example: Diamond problem and the virtual fix. Diamond problem আর virtual দিয়ে সমাধান।
class A { public: int x; };

// WITHOUT virtual: D gets TWO x's
class B : public A {};
class C : public A {};
class D : public B, public C {};

int main() {
    D d;
    // d.x = 5;      // ERROR: ambiguous (B::x or C::x?)
    d.B::x = 5;      // must pick a path — ugly
}

// WITH virtual: D gets ONE shared x
class B2 : virtual public A {};
class C2 : virtual public A {};
class D2 : public B2, public C2 {};

int main2() {
    D2 d;
    d.x = 5;         // OK now — only one copy of A
    return 0;
}
Note: Exam points: (1) Constructors run base → derived; destructors run derived → base. (2) Constructors and destructors are not inherited; friends are not inherited either. (3) With a virtual base class, the most derived class (here D2) calls the virtual base's constructor directly. (4) Java avoids the diamond problem by not allowing multiple inheritance of classes. পরীক্ষার point: (১) Constructor চলে base → derived; destructor চলে derived → base। (২) Constructor আর destructor inherit হয় না; friend-ও inherit হয় না। (৩) Virtual base class থাকলে most derived class (এখানে D2) সরাসরি virtual base-এর constructor call করে। (৪) Java class-এর multiple inheritance allow করে না বলে diamond problem এড়ায়।

5. Polymorphism5. Polymorphism

Polymorphism means "many forms" — the same name or the same call behaves differently in different situations. C++ has two kinds:

  • Compile-time (static): the compiler decides which function runs. Done by function overloading and operator overloading. Also called early binding.
  • Runtime (dynamic): the decision happens while the program runs. Done by virtual functions through base-class pointers or references. Also called late binding.

Polymorphism মানে "many forms" — একই নাম বা একই call ভিন্ন পরিস্থিতিতে ভিন্নভাবে কাজ করে। C++ এ দুই ধরন:

  • Compile-time (static): কোন function চলবে তা compiler ঠিক করে। হয় function overloading আর operator overloading দিয়ে। এটাকে early binding-ও বলে।
  • Runtime (dynamic): সিদ্ধান্তটা program চলার সময় হয়। হয় base-class pointer বা reference দিয়ে virtual function call করলে। এটাকে late binding বলে।

Function overloading (compile-time)Function overloading (compile-time)

Same function name, different parameter list (different number or types). Return type alone is not enough to overload.

একই function name, কিন্তু আলাদা parameter list (সংখ্যা বা type আলাদা)। শুধু return type আলাদা হলে overload হয় না

Example:
int    add(int a, int b)       { return a + b; }
double add(double a, double b) { return a + b; }
int    add(int a, int b, int c){ return a + b + c; }

int main() {
    cout << add(2, 3)       << endl;  // 5      (int version)
    cout << add(2.5, 3.5)   << endl;  // 6      (double version)
    cout << add(1, 2, 3)    << endl;  // 6      (3-arg version)
}

Operator overloading (compile-time)Operator overloading (compile-time)

You can teach operators like +, ==, << to work on your own classes. Some operators can never be overloaded: ::, ., .*, ?:, sizeof.

+, ==, << — এই operator-গুলোকে নিজের class-এর জন্য কাজ করানো যায়। কিছু operator কখনো overload করা যায় না: ::, ., .*, ?:, sizeof

Example: Overloading + for complex numbers. Complex number-এর জন্য + overload।
class Complex {
public:
    double re, im;
    Complex(double r, double i) : re(r), im(i) {}

    Complex operator+(const Complex &o) {
        return Complex(re + o.re, im + o.im);
    }
};

int main() {
    Complex a(1, 2), b(3, 4);
    Complex c = a + b;               // calls a.operator+(b)
    cout << c.re << "+" << c.im << "i";
}
// Output: 4+6i

Virtual functions (runtime)Virtual functions (runtime)

Situation: a base-class pointer holds a derived object. Which function runs — base's or derived's?

  • Non-virtual: the pointer type decides → base version runs (early binding).
  • virtual: the actual object decides → derived version runs (late binding).

Redefining a virtual function in a derived class with the same signature is called overriding.

পরিস্থিতি: একটা base-class pointer একটা derived object ধরে আছে। কোন function চলবে — base-এরটা নাকি derived-এরটা?

  • Non-virtual: pointer-এর type ঠিক করে → base-এর version চলে (early binding)।
  • virtual: আসল object ঠিক করে → derived-এর version চলে (late binding)।

Derived class-এ একই signature দিয়ে virtual function আবার লেখাকে বলে overriding

Example: What is the output? — the most common BUET-style trace. Watch the virtual vs non-virtual difference. Output কী হবে? — সবচেয়ে common BUET-style trace। Virtual vs non-virtual পার্থক্যটা খেয়াল করুন।
class Base {
public:
    void hello()          { cout << "Base hello\n"; }   // non-virtual
    virtual void greet()  { cout << "Base greet\n"; }   // virtual
};

class Derived : public Base {
public:
    void hello()          { cout << "Derived hello\n"; } // hides Base::hello
    void greet() override { cout << "Derived greet\n"; } // overrides
};

int main() {
    Derived d;
    Base *p = &d;      // base pointer → derived object

    p->hello();        // Base hello     (non-virtual: pointer type wins)
    p->greet();        // Derived greet  (virtual: object type wins)

    d.hello();         // Derived hello  (direct call, no pointer)
    d.greet();         // Derived greet
}
// Output:
// Base hello
// Derived greet
// Derived hello
// Derived greet

Memory trick: virtual → look at the object; non-virtual → look at the pointer type. মনে রাখার কৌশল: virtual → object দেখুন; non-virtual → pointer-এর type দেখুন।

How it works: the vtable ideaকীভাবে কাজ করে: vtable-এর idea

When a class has at least one virtual function, the compiler builds a hidden table of function pointers for it — the vtable. Every object of that class carries a hidden pointer — the vptr — pointing to its class's vtable. A virtual call goes: object → vptr → vtable → correct function. That lookup happens at runtime, so the actual object type always wins. Cost: one extra pointer per object and one indirection per call.

কোনো class-এ অন্তত একটা virtual function থাকলে compiler তার জন্য function pointer-দের একটা লুকানো table বানায় — এটাই vtable। ওই class-এর প্রতিটা object-এর ভেতরে একটা লুকানো pointer থাকে — vptr — যেটা তার class-এর vtable-কে point করে। Virtual call যায় এভাবে: object → vptr → vtable → সঠিক function। এই lookup runtime-এ হয়, তাই আসল object-এর type-ই জেতে। খরচ: object প্রতি একটা extra pointer আর call প্রতি একটা indirection।

Derived object d vptr ● data members Derived vtable greet → ● ~Derived → ● Code Derived::greet Derived::~Derived p->greet() ⇒ follow p → vptr → vtable → Derived::greet() Runtime lookup: the real object type decides, not the pointer type.

Pure virtual functions and abstract classesPure virtual function আর abstract class

  • A pure virtual function has no body in the base: virtual double area() = 0;
  • A class with at least one pure virtual function is an abstract class. You cannot create its object, but you can have pointers/references to it.
  • A derived class must override all pure virtual functions, or it stays abstract too.
  • Pure virtual function-এর base-এ কোনো body থাকে না: virtual double area() = 0;
  • যে class-এ অন্তত একটা pure virtual function আছে, সেটা abstract class। এর object বানানো যায় না, কিন্তু pointer/reference রাখা যায়
  • Derived class-কে সবগুলো pure virtual function override করতে হয়, নাহলে সেও abstract থেকে যায়।
Example: Runtime polymorphism in action — one loop, many shapes. Runtime polymorphism হাতে-কলমে — এক loop, অনেক shape।
class Shape {
public:
    virtual double area() = 0;         // pure virtual
    virtual ~Shape() {}                // virtual destructor!
};

class Circle : public Shape {
    double r;
public:
    Circle(double r) : r(r) {}
    double area() override { return 3.1416 * r * r; }
};

class Rect : public Shape {
    double w, h;
public:
    Rect(double w, double h) : w(w), h(h) {}
    double area() override { return w * h; }
};

int main() {
    Shape *shapes[2] = { new Circle(1), new Rect(2, 3) };
    for (int i = 0; i < 2; i++)
        cout << shapes[i]->area() << endl;  // right area() picked at runtime
    for (int i = 0; i < 2; i++)
        delete shapes[i];   // safe: destructor is virtual
}
// Output:
// 3.1416
// 6
Note: Virtual destructor — a top exam favorite. If you delete a derived object through a base pointer and the base destructor is not virtual, only the base destructor runs — the derived part is never cleaned up (memory leak / undefined behavior). Rule: any class meant to be a polymorphic base must have a virtual destructor. Also: constructors can never be virtual. Virtual destructor — পরীক্ষার top favorite। Base pointer দিয়ে derived object delete করলে, base destructor virtual না হলে শুধু base-এর destructor চলে — derived অংশটা কখনো cleanup হয় না (memory leak / undefined behavior)। নিয়ম: যে class polymorphic base হবে, তার destructor অবশ্যই virtual হতে হবে। আরও মনে রাখুন: constructor কখনো virtual হতে পারে না।

Overloading vs overriding vs hidingOverloading vs overriding vs hiding

OverloadingOverloading OverridingOverriding HidingHiding
Whereকোথায় Same class (same scope)একই class-এ (একই scope) Base + derived classBase + derived class-এ Base + derived classBase + derived class-এ
SignatureSignature Same name, different parametersএকই নাম, আলাদা parameter Same name, same parameters, base is virtualএকই নাম, একই parameter, base-এ virtual Same name, base not virtual (or different parameters)একই নাম, base-এ virtual নেই (বা parameter আলাদা)
Decidedকখন ঠিক হয় Compile timeCompile time-এ Runtime (via vtable)Runtime-এ (vtable দিয়ে) Compile timeCompile time-এ
Through base pointerBase pointer দিয়ে Derived version runsDerived version চলে Base version runsBase version চলে
Compile-time polymorphismCompile-time polymorphism Runtime polymorphismRuntime polymorphism
Other namesঅন্য নাম Static / early bindingStatic / early binding Dynamic / late bindingDynamic / late binding
Achieved byকী দিয়ে হয় Function + operator overloading, templatesFunction + operator overloading, templates Virtual functions + base pointer/referenceVirtual function + base pointer/reference
Speedগতি Faster (direct call)দ্রুত (direct call) Slightly slower (vtable lookup)একটু slow (vtable lookup)
FlexibilityFlexibility Fixed at compile timeCompile time-এই fixed Decided by actual object at runtimeRuntime-এ আসল object ঠিক করে

6. Other C++ Concepts6. Other C++ Concepts

Static membersStatic members

A static data member is shared by all objects — there is only one copy for the whole class. It must be defined once outside the class. A static member function can be called without any object (ClassName::func()) and can only touch static members — it has no this.

static data member সব object মিলে share করে — পুরো class-এর জন্য একটাই copy থাকে। Class-এর বাইরে একবার define করতে হয়। static member function কোনো object ছাড়াই call করা যায় (ClassName::func()), আর সে শুধু static member ধরতে পারে — তার কোনো this নেই।

Example: Counting objects with a static member. Static member দিয়ে object গোনা।
class Counter {
public:
    static int count;              // declaration (shared)
    Counter() { count++; }
    static int get() { return count; }   // no object needed
};
int Counter::count = 0;            // definition (required, outside)

int main() {
    Counter a, b, c;
    cout << Counter::get();        // 3 — one shared count
}
// Output: 3

Friend function and friend classFriend function আর friend class

A friend function is not a member, but the class gives it permission to access its private and protected members. A friend class gets the same permission for all its functions. Important facts: friendship is not mutual (A friending B does not make B friend A), not inherited, and not transitive.

Friend function class-এর member না, কিন্তু class তাকে নিজের private আর protected member ধরার অনুমতি দেয়। Friend class হলে তার সব function সেই অনুমতি পায়। জরুরি কথা: friendship mutual না (A যদি B-কে friend বানায়, B automatic A-এর friend হয় না), inherit হয় না, আর transitive-ও না

Example:
class Box {
private:
    int secret = 42;
    friend void peek(Box &b);      // friend declaration
};

void peek(Box &b) {                // normal function, not a member
    cout << b.secret;              // allowed! it is a friend
}

int main() {
    Box b;
    peek(b);                       // 42
}

Templates (generic programming)Templates (generic programming)

A template lets you write one function or class that works for any type. The compiler generates a separate version for each type you use — that is why templates are compile-time polymorphism.

Template দিয়ে এমন একটা function বা class লেখা যায় যেটা যেকোনো type-এর জন্য কাজ করে। আপনি যে যে type ব্যবহার করেন, compiler প্রতিটার জন্য আলাদা version বানিয়ে নেয় — এজন্যই template compile-time polymorphism।

Example: Function template and class template. Function template আর class template।
template <typename T>
T maxOf(T a, T b) { return (a > b) ? a : b; }

template <typename T>
class Pair {
public:
    T first, second;
    Pair(T a, T b) : first(a), second(b) {}
};

int main() {
    cout << maxOf(3, 7) << endl;        // 7    (T = int)
    cout << maxOf(2.5, 1.5) << endl;    // 2.5  (T = double)
    Pair<int> p(1, 2);
    cout << p.first + p.second;         // 3
}

Exception handlingException handling

Exceptions separate error handling from normal code. throw raises an error, try marks the risky block, catch handles it. catch (...) catches anything. When an exception is thrown, the stack "unwinds": local objects are destroyed properly on the way to the matching catch.

Exception দিয়ে error handle করার code-কে normal code থেকে আলাদা রাখা যায়। throw error ছোড়ে, try ঝুঁকির block-টা ঘিরে রাখে, catch সেটা ধরে। catch (...) সবকিছু ধরে। Exception throw হলে stack "unwind" হয়: matching catch-এ পৌঁছানোর পথে local object-গুলো ঠিকভাবে destroy হয়।

Example:
double divide(double a, double b) {
    if (b == 0) throw string("Divide by zero!");
    return a / b;
}

int main() {
    try {
        cout << divide(10, 2) << endl;   // 5
        cout << divide(7, 0)  << endl;   // throws — skips the cout
        cout << "never printed\n";
    }
    catch (string &msg) {
        cout << "Error: " << msg << endl;
    }
    cout << "Program continues\n";
}
// Output:
// 5
// Error: Divide by zero!
// Program continues

STL quick overview: vector, map, setSTL quick overview: vector, map, set

The STL (Standard Template Library) gives ready-made containers and algorithms, all built with templates. Three you must know:

STL (Standard Template Library) ready-made container আর algorithm দেয়, সবই template দিয়ে বানানো। এই তিনটা জানতেই হবে:

ContainerContainer What it isএটা কী Order / duplicatesOrder / duplicate Key operationsKey operations
vector Dynamic (growable) arrayDynamic (বাড়ানো যায় এমন) array Insertion order; duplicates OKInsertion order; duplicate চলে push_back O(1) amortized, index access O(1)push_back O(1) amortized, index access O(1)
map Key → value pairs (balanced BST inside)Key → value pair (ভেতরে balanced BST) Sorted by key; keys uniqueKey অনুযায়ী sorted; key unique insert / find / erase — O(log n)insert / find / erase — O(log n)
set Collection of unique valuesUnique value-দের collection Sorted; no duplicatesSorted; duplicate নেই insert / find / erase — O(log n)insert / find / erase — O(log n)
Example:
#include <vector>
#include <map>
#include <set>

int main() {
    vector<int> v = {3, 1, 3};
    v.push_back(5);                 // v = 3 1 3 5 (duplicates kept)

    set<int> s(v.begin(), v.end()); // s = 1 3 5 (sorted, unique)

    map<string, int> marks;
    marks["math"] = 80;
    marks["cse"]  = 95;
    cout << marks["cse"] << endl;   // 95

    for (int x : s) cout << x << " ";  // 1 3 5
}
// Output:
// 95
// 1 3 5
Note: Quick exam facts: (1) static member functions have no this pointer. (2) friend functions are declared inside the class but are not members and are not affected by access specifiers. (3) map/set are usually implemented as red-black trees → O(log n); unordered_map uses hashing → average O(1). (4) Throwing an exception from a destructor is dangerous — avoid it. Quick পরীক্ষা-fact: (১) static member function-এর this pointer নেই। (২) friend function class-এর ভেতরে declare হয় কিন্তু member না, access specifier-ও তার ওপর কাজ করে না। (৩) map/set সাধারণত red-black tree দিয়ে বানানো → O(log n); unordered_map hashing ব্যবহার করে → average O(1)। (৪) Destructor থেকে exception throw করা বিপজ্জনক — এড়িয়ে চলুন।

Standard C++ threads: std::threadStandard C++ threads: std::thread

Since C++11, threads are part of the language's standard library: std::thread (header <thread>). You give the constructor a function (plus its arguments), and that function runs in a new worker thread. The main thread must call join() to wait for the worker to finish before using its result.

C++11 থেকে thread language-এর standard library-র অংশ: std::thread (header <thread>)। Constructor-এ একটা function (আর তার argument) দিলে সেই function নতুন একটা worker thread-এ চলে। Worker-এর result ব্যবহারের আগে main thread-কে join() call করে তার শেষ হওয়া পর্যন্ত অপেক্ষা করতে হয়।

Example: Factorial computed in a worker thread — the exact task BUET asked. Worker thread-এ factorial হিসাব — BUET ঠিক এই কাজটাই করতে বলেছিল।
#include <iostream>
#include <thread>
using namespace std;

unsigned long long fact = 1;

void factorial(int n) {              // this runs in the worker thread
    for (int i = 2; i <= n; i++)
        fact *= i;
}

int main() {
    thread t(factorial, 5);          // start worker thread, argument 5
    t.join();                        // wait for the worker to finish
    cout << "5! = " << fact << endl;
}
// compile: g++ -std=c++11 fact.cpp -pthread
// Output:
// 5! = 120
Without join(), main could end (or print) before the worker finishes — that is a bug. join() is the "wait here" line. যদি join() না দেন, worker শেষ হওয়ার আগেই main শেষ হয়ে (বা print করে) যেতে পারে — সেটা bug। join() মানেই "এখানে দাঁড়িয়ে অপেক্ষা করো"।
Note: Asked October 2017 — and the question said to use standard C++ threads, NOT pthread. One-line contrast: pthread is an old C library (pthread_create with void* casts, Unix-only style), while std::thread is standard C++11 — an object, type-safe, takes any function with normal arguments, and is portable. October 2017-এ এসেছিল — আর প্রশ্নে স্পষ্ট বলা ছিল standard C++ threads ব্যবহার করতে, pthread না। এক লাইনে পার্থক্য: pthread পুরনো C library (pthread_create, void* cast, Unix-ঘেঁষা), আর std::thread হলো standard C++11 — একটা object, type-safe, normal argument-সহ যেকোনো function নেয়, আর portable।

Java Corner (Real Exam Questions!)Java Corner (Real Exam Questions!)

The official syllabus says OOP with C++. But in real BUET exams, Java questions appear too! So learn these few Java things well. They are short, and they were actually asked. Official syllabus-এ লেখা OOP with C++। কিন্তু আসল BUET পরীক্ষায় Java-র প্রশ্নও আসে! তাই এই কয়েকটা Java বিষয় ভালো করে শিখে রাখুন। এগুলো ছোট, আর সত্যিই পরীক্ষায় এসেছে।

Java vs C++ — quick differencesJava vs C++ — দ্রুত পার্থক্য

Thingবিষয় C++ Java
PointersPointer Yes, full pointer arithmeticআছে, full pointer arithmetic No pointers — only referencesPointer নেই — শুধু reference
Memory cleanupMemory cleanup Manual: new / deleteManual: new / delete Automatic garbage collection (GC)Automatic garbage collection (GC)
Where code livesCode কোথায় থাকে Free functions allowed (like main)Class-এর বাইরে free function লেখা যায় (যেমন main) Everything must be inside a classসবকিছু class-এর ভেতরে থাকতেই হবে
Multiple inheritanceMultiple inheritance Yes, of classes (diamond problem!)Class-এর multiple inheritance আছে (diamond problem!) Not for classes — use interfaces instead (a class can implement many)Class-এ নেই — বদলে interface ব্যবহার হয় (একটা class অনেকগুলো implement করতে পারে)
Runs onচলে কীসে Compiled to native machine codeসরাসরি native machine code-এ compile হয় Bytecode on the JVM ("write once, run anywhere")JVM-এ bytecode হিসেবে ("write once, run anywhere")
Operator overloadingOperator overloading Yesআছে No (only + for String is built in)নেই (শুধু String-এর + built-in)

String pool: == vs .equals()String pool: == vs .equals()

In Java, == on objects compares references (same object in memory?). .equals() compares the content. String literals go into a shared "string pool", so equal literals point to the same object. But new String("...") always makes a brand new object outside the pool. Java-তে object-এর ওপর == তুলনা করে reference (memory-তে একই object কি না?)। .equals() তুলনা করে content। String literal-গুলো একটা shared "string pool"-এ থাকে, তাই সমান literal একই object-কে point করে। কিন্তু new String("...") সবসময় pool-এর বাইরে একদম নতুন object বানায়।

Example: The exact style of code BUET asked. Predict the output first! BUET ঠিক এই ধরনের code-ই জিজ্ঞেস করেছিল। আগে নিজে output ভাবুন!
String a = "buet";
String b = "buet";                 // same pool object as a
String c = new String("buet");     // NEW object, outside the pool

System.out.println(a == b);        // true  (same pool reference)
System.out.println(a == c);        // false (different objects)
System.out.println(a.equals(c));   // true  (same content "buet")
Output: true, false, true. Rule of thumb: always compare Strings with .equals(), never with ==. Output: true, false, true। মনে রাখার নিয়ম: String তুলনা সবসময় .equals() দিয়ে, কখনোই == দিয়ে না।

String is immutableString হলো immutable

A Java String can never change after it is made. Methods like concat, toUpperCase, replace do NOT change the old String — they return a new String object. If you ignore the returned value, nothing seems to happen. Java String একবার বানানোর পর কখনো বদলায় না। concat, toUpperCase, replace — এই method-গুলো পুরনো String বদলায় না — একটা নতুন String object return করে। Return value না ধরলে মনে হবে কিছুই হয়নি।

Example: Immutability in action. Immutability কাজে দেখুন।
String s = "BUET";
s.concat(" CSE");                  // makes a new String, but we threw it away!
System.out.println(s);             // BUET   (s did not change)

s = s.concat(" CSE");              // now we keep the new object
System.out.println(s);             // BUET CSE
Output: BUET then BUET CSE. For heavy string building, use StringBuilder — it IS mutable. Output: BUET তারপর BUET CSE। অনেক string জোড়া দিতে হলে StringBuilder ব্যবহার করুন — সেটা mutable।

Nested classes: static vs non-static (inner)Nested class: static vs non-static (inner)

A class written inside another class is a nested class. A static nested class does not need an outer object — create it directly. A non-static nested class (called an inner class) belongs to an outer object, so you must have an outer object first, and use the special syntax outer.new Inner(). এক class-এর ভেতরে লেখা class-কে nested class বলে। static nested class-এর জন্য outer object লাগে না — সরাসরি বানানো যায়। non-static nested class (যাকে inner class বলে) একটা outer object-এর সাথে যুক্ত, তাই আগে outer object লাগবেই, আর বিশেষ syntax outer.new Inner() ব্যবহার করতে হয়।

Example: The instantiation syntax BUET asked for. BUET ঠিক এই instantiation syntax-টাই জিজ্ঞেস করেছিল।
class Outer {
    int x = 10;

    class Inner {                      // non-static inner class
        void show() { System.out.println(x); }   // can use outer's x
    }

    static class Helper {              // static nested class
        void hi() { System.out.println("hi"); }
    }
}

public class Main {
    public static void main(String[] args) {
        Outer outer = new Outer();               // 1) outer object first
        Outer.Inner in = outer.new Inner();      // 2) special syntax!
        in.show();                               // 10

        Outer.Helper h = new Outer.Helper();     // static: no outer object
        h.hi();                                  // hi
    }
}
Key line: Outer.Inner in = outer.new Inner(); — the inner object is tied to that specific outer object and can read its fields (like x). Key line: Outer.Inner in = outer.new Inner(); — inner object-টা ওই নির্দিষ্ট outer object-এর সাথে বাঁধা থাকে, আর তার field (যেমন x) পড়তে পারে।

Functional interface and lambdaFunctional interface আর lambda

A functional interface is an interface with exactly one abstract method. That is the whole definition. Because there is only one method, Java can let you write its body as a short lambda expression — no class, no method name, just (parameters) -> body. You can mark the interface with @FunctionalInterface; then the compiler gives an error if someone adds a second abstract method. (Default and static methods are allowed — they do not count, because they already have bodies.) Functional interface হলো এমন interface যাতে ঠিক একটা abstract method থাকে। Definition এটুকুই। Method যেহেতু একটাই, Java তার body ছোট একটা lambda expression হিসেবে লিখতে দেয় — কোনো class না, method-এর নামও না, শুধু (parameters) -> body। Interface-টাকে @FunctionalInterface দিয়ে mark করা যায়; তখন কেউ দ্বিতীয় abstract method যোগ করলে compiler error দেয়। (Default আর static method থাকতে পারে — ওগুলো গোনা হয় না, কারণ ওদের body আগে থেকেই আছে।)

Java already ships many built-in functional interfaces. Learn these four names: Java-তে অনেক built-in functional interface আগে থেকেই আছে। এই চারটা নাম শিখে রাখুন:

InterfaceInterface Its one abstract methodতার একমাত্র abstract method Meaningমানে
Runnable void run() A task to run (no input, no output)চালানোর মতো একটা task (input নেই, output নেই)
Comparator<T> int compare(T a, T b) Which of two objects comes first (for sorting)দুই object-এর কোনটা আগে আসবে (sorting-এর জন্য)
Function<T,R> R apply(T t) Turn a T into an Rএকটা T থেকে একটা R বানানো
Predicate<T> boolean test(T t) A yes/no check on a Tএকটা T-এর ওপর yes/no check
Example: Write your own functional interface, then implement it with a lambda in one line. নিজের functional interface লিখুন, তারপর এক লাইনের lambda দিয়ে implement করুন।
@FunctionalInterface
interface Calculator {
    int operate(int a, int b);     // the ONE abstract method
}

public class Main {
    public static void main(String[] args) {
        Calculator add = (a, b) -> a + b;        // lambda = the method body
        Calculator mul = (a, b) -> a * b;

        System.out.println(add.operate(3, 4));   // 7
        System.out.println(mul.operate(3, 4));   // 12
    }
}
The lambda (a, b) -> a + b is a short way to implement operate. Java knows which method it fills in — there is only one. Lambda (a, b) -> a + b আসলে operate implement করার ছোট রাস্তা। কোন method-এর body এটা, Java জানে — কারণ method তো একটাই।
Note: Asked April 2024: "What is a functional interface in Java? Give an example." Safe full answer: one abstract method + @FunctionalInterface + a built-in name (Runnable) + a small lambda like the one above. April 2024-এ এসেছিল: "Java-তে functional interface কী? উদাহরণ দিন।" নিরাপদ full answer: একটা abstract method + @FunctionalInterface + একটা built-in নাম (Runnable) + ওপরের মতো ছোট একটা lambda।

Lambda + Streams: shorter, loop-free codeLambda + Streams: ছোট, loop ছাড়া code

Before Java 8, passing "a piece of behavior" needed an anonymous inner class — five lines of ceremony. A lambda says the same thing in one line. Classic GUI example: a button click handler (ActionListener is a functional interface, so a lambda fits). Java 8-এর আগে "এক টুকরো behavior" pass করতে anonymous inner class লাগত — পাঁচ লাইনের আনুষ্ঠানিকতা। Lambda একই কথা এক লাইনে বলে। Classic GUI উদাহরণ: button click handler (ActionListener একটা functional interface, তাই lambda বসানো যায়)।

Example: Same button handler, old style vs lambda style. একই button handler, পুরনো style vs lambda style।
// OLD: anonymous inner class (before Java 8)
button.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        System.out.println("Clicked!");
    }
});

// NEW: lambda (Java 8+) — same meaning, one line
button.addActionListener(e -> System.out.println("Clicked!"));
Both create an object whose one method prints "Clicked!". The lambda works because ActionListener has exactly one abstract method (actionPerformed). দুটোই এমন object বানায় যার একমাত্র method "Clicked!" print করে। Lambda চলে কারণ ActionListener-এর ঠিক একটাই abstract method (actionPerformed)।

A Stream is a pipeline over a collection: you describe what to do (filter, map, collect), and Java does the looping for you. Exam favorite: process a list without writing any loop. Stream হলো collection-এর ওপর একটা pipeline: আপনি বলেন কী করতে হবে (filter, map, collect), আর loop চালানোর কাজটা Java নিজে করে। পরীক্ষার প্রিয় প্রশ্ন: কোনো loop না লিখে একটা list process করা।

Example: Get the length of every word in a list — no loop anywhere. একটা list-এর প্রতিটা word-এর length বের করুন — কোথাও loop নেই।
import java.util.*;
import java.util.stream.*;

List<String> words = Arrays.asList("BUET", "CSE", "Admission");

List<Integer> lengths = words.stream()          // 1) open the pipeline
        .map(String::length)                    // 2) each word -> its length
        .collect(Collectors.toList());          // 3) gather into a new list

System.out.println(lengths);                    // [4, 3, 9]
String::length is a method reference — an even shorter lambda; it means w -> w.length(). Bonus one-liners: words.stream().filter(w -> w.length() > 3).count() counts long words; words.forEach(System.out::println) prints them all. String::length হলো method reference — আরও ছোট lambda; মানে w -> w.length()। Bonus এক-লাইনার: words.stream().filter(w -> w.length() > 3).count() লম্বা word গোনে; words.forEach(System.out::println) সবগুলো print করে।
Note: Asked October 2017 and October 2018: rewrite an anonymous-class listener as a lambda, and process a list with streams instead of a loop. If a question says "do NOT use a loop", the expected answer is the stream() → map()/filter() → collect() chain above. October 2017 আর October 2018-এ এসেছিল: anonymous-class listener-কে lambda দিয়ে নতুন করে লেখা, আর loop-এর বদলে stream দিয়ে list process করা। প্রশ্নে যদি বলে "loop ব্যবহার করা যাবে না", expected answer হলো ওপরের stream() → map()/filter() → collect() chain।
Note: These exact things were asked in the BUET April 2019 exam: (1) output of comparing Strings made with new vs literals (== vs .equals(), string pool), (2) how to create an object of a non-static inner class (outer.new Inner()), (3) String immutability behavior. The syllabus says C++, but revise this Java corner before the exam! BUET April 2019 পরীক্ষায় ঠিক এই জিনিসগুলোই এসেছিল: (১) new vs literal দিয়ে বানানো String তুলনার output (== vs .equals(), string pool), (২) non-static inner class-এর object কীভাবে বানায় (outer.new Inner()), (৩) String immutability-র আচরণ। Syllabus-এ C++ লেখা থাকলেও পরীক্ষার আগে এই Java corner-টা অবশ্যই revise করুন!

Practice Questions (Admission Style)Practice Questions (Admission Style)

Q1. What is the default access specifier of members in a C++ class?
  • (a) public
  • (b) private
  • (c) protected
  • (d) friend
Q1. C++ এর class-এ member-দের default access specifier কোনটা?
  • (a) public
  • (b) private
  • (c) protected
  • (d) friend
Show Answerউত্তর দেখুন
Answer: (b) — In a class, members are private by default. In a struct, they are public by default. This is the only real difference between struct and class in C++.
Answer: (b)class-এ member-রা default-এ private। struct-এ default-এ public। C++ এ struct আর class-এর আসল পার্থক্য এটাই।
Q2. Which one is NOT a pillar of OOP?
  • (a) Encapsulation
  • (b) Inheritance
  • (c) Compilation
  • (d) Polymorphism
Q2. কোনটা OOP-এর pillar না?
  • (a) Encapsulation
  • (b) Inheritance
  • (c) Compilation
  • (d) Polymorphism
Show Answerউত্তর দেখুন
Answer: (c) — The four pillars are Encapsulation, Abstraction, Inheritance, and Polymorphism. Compilation is just a build step, not an OOP concept.
Answer: (c) — চারটা pillar হলো Encapsulation, Abstraction, Inheritance আর Polymorphism। Compilation শুধু একটা build step, OOP concept না।
Q3. Which statement about constructors is FALSE?
  • (a) A constructor has no return type
  • (b) A constructor can be overloaded
  • (c) A constructor can be virtual
  • (d) A constructor has the same name as the class
Q3. Constructor নিয়ে কোন কথাটা মিথ্যা?
  • (a) Constructor-এর কোনো return type নেই
  • (b) Constructor overload করা যায়
  • (c) Constructor virtual হতে পারে
  • (d) Constructor-এর নাম class-এর নামের মতো
Show Answerউত্তর দেখুন
Answer: (c) — A constructor can never be virtual. Virtual dispatch needs the vptr, but the vptr is set up by the constructor — the object does not fully exist yet. A destructor, however, can and often should be virtual.
Answer: (c) — Constructor কখনো virtual হয় না। Virtual dispatch-এর জন্য vptr লাগে, কিন্তু vptr তো constructor-ই set করে — তখনো object পুরো তৈরিই হয়নি। কিন্তু destructor virtual হতে পারে, আর প্রায়ই হওয়া উচিত।
Q4. What is the output?
class A {
    int id;
public:
    A(int i) { id = i; cout << "C" << id; }
    ~A()     { cout << "D" << id; }
};
int main() {
    A p(1);
    { A q(2); }
    A r(3);
}
  • (a) C1C2C3D3D2D1
  • (b) C1C2D2C3D3D1
  • (c) C1C2D2C3D1D3
  • (d) C1C2C3D1D2D3
Q4. Output কী হবে?
class A {
    int id;
public:
    A(int i) { id = i; cout << "C" << id; }
    ~A()     { cout << "D" << id; }
};
int main() {
    A p(1);
    { A q(2); }
    A r(3);
}
  • (a) C1C2C3D3D2D1
  • (b) C1C2D2C3D3D1
  • (c) C1C2D2C3D1D3
  • (d) C1C2C3D1D2D3
Show Answerউত্তর দেখুন
Answer: (b)q lives inside an inner block { }, so it dies as soon as the block ends: C1, C2, D2. Then r is made: C3. At the end of main, destruction is reverse of creation among the living objects (r then p): D3, D1. Full output: C1C2D2C3D3D1.
Answer: (b)q ভেতরের block { }-এ আছে, তাই block শেষ হতেই সে destroy হয়: C1, C2, D2। তারপর r তৈরি হয়: C3। main শেষে বেঁচে থাকা object-রা তৈরির উল্টা order-এ destroy হয় (আগে r, পরে p): D3, D1। পুরো output: C1C2D2C3D3D1
Q5. When is a copy constructor called? Write the three cases, and explain why its parameter must be a reference.
Q5. Copy constructor কখন call হয়? তিনটা case লিখুন, আর এর parameter কেন reference হতেই হবে ব্যাখ্যা করুন।
Show Answerউত্তর দেখুন
Answer: Called when (1) an object is initialized from another object (Point b = a;), (2) an object is passed to a function by value, (3) an object is returned from a function by value. The parameter must be a reference (const Point &) because if it were pass-by-value, that very pass would need a copy — which calls the copy constructor again, and again — infinite recursion. The compiler rejects a by-value copy constructor.
Answer: Call হয় যখন (১) এক object থেকে আরেক object initialize হয় (Point b = a;), (২) object কোনো function-এ by value pass হয়, (৩) function থেকে object by value return হয়। Parameter reference (const Point &) হতেই হবে, কারণ value হলে ওই pass করতেই একটা copy লাগত — তাতে আবার copy constructor call হতো, আবার হতো — infinite recursion। তাই compiler by-value copy constructor allow করে না।
Q6. Class D is derived as class D : protected B. A public member of B becomes what inside D?
  • (a) public
  • (b) protected
  • (c) private
  • (d) not accessible
Q6. class D : protected B — এভাবে derive করা হলো। B-এর একটা public member D-এর ভেতরে কী হয়ে যায়?
  • (a) public
  • (b) protected
  • (c) private
  • (d) not accessible
Show Answerউত্তর দেখুন
Answer: (b) — The resulting access is the more restrictive of the member's access (public) and the inheritance mode (protected). So public → protected. Remember: private members of the base are never accessible in the derived class in any mode.
Answer: (b) — Member-এর access (public) আর inheritance mode (protected) — দুটোর মধ্যে যেটা বেশি কড়া, সেটাই হয়। তাই public → protected। মনে রাখুন: base-এর private member কোনো mode-এই derived class থেকে ধরা যায় না।
Q7. Which is TRUE about a static member function?
  • (a) It can access non-static members directly
  • (b) It has a this pointer
  • (c) It can be called without any object
  • (d) Each object has its own copy of it
Q7. Static member function নিয়ে কোনটা সত্য?
  • (a) সরাসরি non-static member ধরতে পারে
  • (b) এর একটা this pointer আছে
  • (c) কোনো object ছাড়াই call করা যায়
  • (d) প্রতিটা object-এর কাছে এর আলাদা copy থাকে
Show Answerউত্তর দেখুন
Answer: (c) — A static member function belongs to the class, not to any object, so call it as ClassName::func(). It has no this pointer, so it cannot touch non-static members directly — (a), (b), (d) are all false.
Answer: (c) — Static member function object-এর না, class-এর — তাই ClassName::func() দিয়েই call করা যায়। এর this pointer নেই, তাই non-static member সরাসরি ধরতে পারে না — (a), (b), (d) সবগুলোই মিথ্যা।
Q8. What is the output?
class Base {
public:
    virtual void f() { cout << "Bf "; }
    void g()         { cout << "Bg "; }
};
class Der : public Base {
public:
    void f() { cout << "Df "; }
    void g() { cout << "Dg "; }
};
int main() {
    Der d;
    Base *p = &d;
    p->f(); p->g(); d.g();
}
  • (a) Bf Bg Dg
  • (b) Df Bg Dg
  • (c) Df Dg Dg
  • (d) Bf Dg Dg
Q8. Output কী হবে?
class Base {
public:
    virtual void f() { cout << "Bf "; }
    void g()         { cout << "Bg "; }
};
class Der : public Base {
public:
    void f() { cout << "Df "; }
    void g() { cout << "Dg "; }
};
int main() {
    Der d;
    Base *p = &d;
    p->f(); p->g(); d.g();
}
  • (a) Bf Bg Dg
  • (b) Df Bg Dg
  • (c) Df Dg Dg
  • (d) Bf Dg Dg
Show Answerউত্তর দেখুন
Answer: (b)f() is virtual, so through the base pointer the object's version runs: Df. g() is non-virtual, so the pointer type decides: Bg. Calling d.g() directly on the Der object gives Dg. Rule: virtual → object wins; non-virtual → pointer type wins.
Answer: (b)f() virtual, তাই base pointer দিয়েও object-এর version চলে: Dfg() virtual না, তাই pointer-এর type ঠিক করে: Bg। আর d.g() সরাসরি Der object-এ call, তাই Dg। নিয়ম: virtual → object জেতে; non-virtual → pointer type জেতে।
Q9. Explain the difference between function overloading and function overriding, with one small code example of each.
Q9. Function overloading আর function overriding-এর পার্থক্য ব্যাখ্যা করুন, প্রতিটার একটা ছোট code example সহ।
Show Answerউত্তর দেখুন
Answer: Overloading: same name, different parameter lists, in the same scope; resolved at compile time. Example: int add(int,int); and double add(double,double);. Overriding: a derived class redefines a base class virtual function with the same signature; resolved at runtime through the vtable. Example: virtual void draw() in Shape, redefined as void draw() override in Circle; calling through a Shape* runs Circle's version. Key line: overloading = compile time + same class; overriding = runtime + inheritance + virtual.
Answer: Overloading: একই নাম, আলাদা parameter list, একই scope-এ; compile time-এ resolve হয়। Example: int add(int,int); আর double add(double,double);Overriding: derived class base-এর virtual function একই signature দিয়ে আবার লেখে; runtime-এ vtable দিয়ে resolve হয়। Example: Shape-এ virtual void draw(), Circle-এ void draw() override; Shape* দিয়ে call করলে Circle-এর version চলে। মূল কথা: overloading = compile time + একই class; overriding = runtime + inheritance + virtual।
Q10. What is the diamond problem in multiple inheritance? How does a virtual base class solve it? Draw the class diagram.
Q10. Multiple inheritance-এ diamond problem কী? Virtual base class এটা কীভাবে সমাধান করে? Class diagram আঁকুন।
Show Answerউত্তর দেখুন
Answer: Diagram: A at top; B and C both inherit A; D inherits both B and C — a diamond shape. Problem: D contains two copies of A's members (one via B, one via C), so d.x is ambiguous and A's constructor runs twice. Fix: declare class B : virtual public A and class C : virtual public A. Then D holds a single shared A subobject, the ambiguity disappears, and the most derived class (D) constructs A exactly once.
Answer: Diagram: উপরে A; B আর C দুজনেই A থেকে inherit করে; D inherit করে B আর C থেকে — একটা diamond shape। সমস্যা: D-এর ভেতরে A-এর member-দের দুইটা copy থাকে (একটা B হয়ে, একটা C হয়ে), তাই d.x ambiguous, আর A-এর constructor দুইবার চলে। সমাধান: class B : virtual public A আর class C : virtual public A লিখুন। তখন D-তে A-এর একটাই shared subobject থাকে, ambiguity চলে যায়, আর most derived class (D) A-কে ঠিক একবার construct করে।
Q11. A class allocates memory with new in its constructor and frees it in the destructor, but has no copy constructor. What exactly goes wrong when we write MyArray b = a; and then both objects are destroyed? What is the fix called?
Q11. একটা class constructor-এ new দিয়ে memory নেয়, destructor-এ free করে, কিন্তু কোনো copy constructor নেই। MyArray b = a; লেখার পর দুই object destroy হলে ঠিক কী সমস্যা হয়? সমাধানটার নাম কী?
Show Answerউত্তর দেখুন
Answer: The compiler's default copy constructor does a shallow copy: it copies the pointer's address, not the data. Now a and b point to the same memory block. When b is destroyed, its destructor frees that block; a is left with a dangling pointer. When a is destroyed, it frees the same block again — a double free, which is undefined behavior (usually a crash). Fix: write a deep copy constructor that allocates new memory and copies element values (and, by the Rule of Three, also a matching assignment operator and destructor).
Answer: Compiler-এর default copy constructor shallow copy করে: data না, শুধু pointer-এর address copy হয়। তখন a আর b একই memory block-কে point করে। b destroy হলে তার destructor block-টা free করে দেয়; a-এর কাছে থাকে dangling pointer। এরপর a destroy হলে একই block আবার free হয় — double free, যেটা undefined behavior (সাধারণত crash)। সমাধান: deep copy constructor লেখা, যেটা নতুন memory নিয়ে element-গুলোর value copy করে (আর Rule of Three অনুযায়ী matching assignment operator ও destructor-ও লাগবে)।
Q12. What is the output?
class A {
public:
    A()  { cout << "A "; }
    ~A() { cout << "~A "; }
};
class B : public A {
public:
    B()  { cout << "B "; }
    ~B() { cout << "~B "; }
};
int main() {
    B obj;
}
  • (a) A B ~A ~B
  • (b) B A ~A ~B
  • (c) A B ~B ~A
  • (d) B A ~B ~A
Q12. Output কী হবে?
class A {
public:
    A()  { cout << "A "; }
    ~A() { cout << "~A "; }
};
class B : public A {
public:
    B()  { cout << "B "; }
    ~B() { cout << "~B "; }
};
int main() {
    B obj;
}
  • (a) A B ~A ~B
  • (b) B A ~A ~B
  • (c) A B ~B ~A
  • (d) B A ~B ~A
Show Answerউত্তর দেখুন
Answer: (c) — Construction goes base → derived: A B. Destruction is the exact reverse, derived → base: ~B ~A. Think of it like building a house: foundation (base) first, roof last; demolition removes the roof first.
Answer: (c) — Construction হয় base → derived: A B। Destruction হয় ঠিক উল্টা, derived → base: ~B ~A। বাড়ি বানানোর মতো ভাবুন: আগে foundation (base), শেষে ছাদ; ভাঙার সময় আগে ছাদ।
Q13. Why should a polymorphic base class have a virtual destructor? Show with a short code example what happens without it.
Q13. Polymorphic base class-এর destructor কেন virtual হওয়া উচিত? Virtual না হলে কী হয়, ছোট একটা code example দিয়ে দেখান।
Show Answerউত্তর দেখুন
Answer:
class Base {
public:
    ~Base() { cout << "~Base "; }     // NOT virtual
};
class Der : public Base {
    int *buf;
public:
    Der()  { buf = new int[100]; }
    ~Der() { delete[] buf; cout << "~Der "; }
};
int main() {
    Base *p = new Der();
    delete p;      // prints only "~Base " !
}
Since ~Base() is non-virtual, delete p; uses the pointer's static type and calls only ~Base(). ~Der() never runs, so buf is never freed — memory leak, and formally undefined behavior. Making the base destructor virtual makes the delete go through the vtable: ~Der() runs first, then ~Base() — correct cleanup.
Answer:
class Base {
public:
    ~Base() { cout << "~Base "; }     // virtual না
};
class Der : public Base {
    int *buf;
public:
    Der()  { buf = new int[100]; }
    ~Der() { delete[] buf; cout << "~Der "; }
};
int main() {
    Base *p = new Der();
    delete p;      // শুধু "~Base " ছাপে!
}
~Base() virtual না হওয়ায় delete p; pointer-এর static type দেখে শুধু ~Base() call করে। ~Der() কখনো চলে না, তাই buf কখনো free হয় না — memory leak, আর নিয়ম অনুযায়ী undefined behavior। Base destructor virtual করলে delete vtable দিয়ে যায়: আগে ~Der(), তারপর ~Base() — সঠিক cleanup।
Q14. What is the output?
class Shape {
public:
    virtual void draw() { cout << "Shape "; }
};
class Circle : public Shape {
public:
    void draw() override { cout << "Circle "; }
};
void byValue(Shape s)   { s.draw(); }
void byRef(Shape &s)    { s.draw(); }
int main() {
    Circle c;
    byValue(c);
    byRef(c);
}
  • (a) Circle Circle
  • (b) Shape Shape
  • (c) Shape Circle
  • (d) Circle Shape
Q14. Output কী হবে?
class Shape {
public:
    virtual void draw() { cout << "Shape "; }
};
class Circle : public Shape {
public:
    void draw() override { cout << "Circle "; }
};
void byValue(Shape s)   { s.draw(); }
void byRef(Shape &s)    { s.draw(); }
int main() {
    Circle c;
    byValue(c);
    byRef(c);
}
  • (a) Circle Circle
  • (b) Shape Shape
  • (c) Shape Circle
  • (d) Circle Shape
Show Answerউত্তর দেখুন
Answer: (c)byValue(Shape s) copies only the Shape part of the Circle — this is object slicing. The parameter is a real Shape object, so s.draw() prints "Shape". byRef(Shape &s) keeps the original Circle object, so the virtual call prints "Circle". Lesson: runtime polymorphism works only through pointers or references, never by value.
Answer: (c)byValue(Shape s) Circle-এর শুধু Shape অংশটুকু copy করে — এটাই object slicing। Parameter-টা তখন আসল একটা Shape object, তাই s.draw() ছাপে "Shape"। byRef(Shape &s)-এ original Circle object-টাই থাকে, তাই virtual call ছাপে "Circle"। শিক্ষা: runtime polymorphism শুধু pointer বা reference দিয়েই কাজ করে, by value কখনো না।
Q15. Design (write the C++ code for) a class hierarchy: an abstract class Employee with pure virtual salary(), and two derived classes — Regular (fixed monthly pay) and Hourly (rate × hours). In main, store both in an array of Employee* and print each salary using runtime polymorphism. Mention every place a virtual keyword is needed and why.
Q15. একটা class hierarchy design করুন (C++ code লিখুন): abstract class Employee, যাতে pure virtual salary() আছে, আর দুইটা derived class — Regular (fixed monthly pay) আর Hourly (rate × hours)। main-এ দুটোকেই Employee*-এর array-তে রেখে runtime polymorphism দিয়ে প্রতিটার salary print করুন। কোথায় কোথায় virtual keyword লাগবে আর কেন — উল্লেখ করুন।
Show Answerউত্তর দেখুন
Answer:
class Employee {
public:
    virtual double salary() = 0;   // (1) pure virtual: makes class abstract
    virtual ~Employee() {}         // (2) virtual destructor: safe delete via Employee*
};

class Regular : public Employee {
    double monthly;
public:
    Regular(double m) : monthly(m) {}
    double salary() override { return monthly; }
};

class Hourly : public Employee {
    double rate, hours;
public:
    Hourly(double r, double h) : rate(r), hours(h) {}
    double salary() override { return rate * hours; }
};

int main() {
    Employee *emps[2] = { new Regular(50000), new Hourly(500, 160) };
    for (int i = 0; i < 2; i++)
        cout << emps[i]->salary() << endl;   // 50000, 80000
    for (int i = 0; i < 2; i++) delete emps[i];
}
Virtual is needed in two places: (1) salary() = 0 — pure virtual so each derived class must give its own formula, and the call through Employee* picks the right one at runtime via the vtable; (2) the destructor — because we delete through an Employee*, without it the derived destructors would never run.
Answer:
class Employee {
public:
    virtual double salary() = 0;   // (১) pure virtual: class-টা abstract হয়
    virtual ~Employee() {}         // (২) virtual destructor: Employee* দিয়ে safe delete
};

class Regular : public Employee {
    double monthly;
public:
    Regular(double m) : monthly(m) {}
    double salary() override { return monthly; }
};

class Hourly : public Employee {
    double rate, hours;
public:
    Hourly(double r, double h) : rate(r), hours(h) {}
    double salary() override { return rate * hours; }
};

int main() {
    Employee *emps[2] = { new Regular(50000), new Hourly(500, 160) };
    for (int i = 0; i < 2; i++)
        cout << emps[i]->salary() << endl;   // 50000, 80000
    for (int i = 0; i < 2; i++) delete emps[i];
}
Virtual লাগবে দুই জায়গায়: (১) salary() = 0 — pure virtual, যাতে প্রতিটা derived class নিজের formula লিখতে বাধ্য হয়, আর Employee* দিয়ে call করলে vtable দিয়ে runtime-এ সঠিকটা বাছাই হয়; (২) destructor-এ — কারণ আমরা Employee* দিয়ে delete করছি, virtual না হলে derived destructor-গুলো কখনোই চলত না।
Q16. (Real exam style — asked April 2019) What is the output of this Java code? Explain each line of the output.
String a = "cse";
String b = "cse";
String c = new String("cse");

System.out.println(a == b);
System.out.println(a == c);
System.out.println(a.equals(c));
Q16. (Real exam style — April 2019-এ এসেছিল) এই Java code-এর output কী হবে? Output-এর প্রতিটা লাইন ব্যাখ্যা করুন।
String a = "cse";
String b = "cse";
String c = new String("cse");

System.out.println(a == b);
System.out.println(a == c);
System.out.println(a.equals(c));
Show Answerউত্তর দেখুন
Answer: Output is true, false, true. Why: (1) a == b is true — both literals come from the string pool, so a and b point to the very same object, and == compares references. (2) a == c is falsenew String("cse") always creates a fresh object outside the pool, so the references differ even though the text is the same. (3) a.equals(c) is trueequals() compares the characters (content), and both hold "cse". Lesson: compare String content with .equals(), never ==.
Answer: Output হবে true, false, true। কারণ: (১) a == b হয় true — দুটো literal-ই string pool থেকে আসে, তাই a আর b একদম একই object-কে point করে, আর == reference তুলনা করে। (২) a == c হয় falsenew String("cse") সবসময় pool-এর বাইরে নতুন object বানায়, তাই লেখা এক হলেও reference আলাদা। (৩) a.equals(c) হয় trueequals() character (content) তুলনা করে, আর দুটোতেই আছে "cse"। শিক্ষা: String content তুলনা .equals() দিয়ে, কখনোই == দিয়ে না।
Q17. (Real exam style — asked April 2019) (a) In Java, Inner is a non-static class written inside class Outer. Write the code to create an Inner object. (b) What does this code print, and why?
String s = "BUET";
s.concat(" CSE");
System.out.println(s);
Q17. (Real exam style — April 2019-এ এসেছিল) (a) Java-তে Outer class-এর ভেতরে Inner একটা non-static class। Inner-এর object বানানোর code লিখুন। (b) নিচের code কী print করবে, আর কেন?
String s = "BUET";
s.concat(" CSE");
System.out.println(s);
Show Answerউত্তর দেখুন
Answer: (a) A non-static inner class needs an outer object first, then the special syntax:
Outer outer = new Outer();
Outer.Inner in = outer.new Inner();
Plain new Outer.Inner() does NOT compile for a non-static inner class — that form works only for a static nested class. (b) It prints BUET. String is immutable: concat(" CSE") does not change s — it builds and returns a new String "BUET CSE", but that returned object was thrown away. To keep it, write s = s.concat(" CSE"); — then it would print BUET CSE.
Answer: (a) Non-static inner class-এর জন্য আগে একটা outer object লাগে, তারপর বিশেষ syntax:
Outer outer = new Outer();
Outer.Inner in = outer.new Inner();
শুধু new Outer.Inner() লিখলে non-static inner class-এ compile হবে না — ওই form শুধু static nested class-এর জন্য। (b) Print হবে BUET। String immutable: concat(" CSE") কখনো s বদলায় না — নতুন String "BUET CSE" বানিয়ে return করে, কিন্তু সেই return করা object-টা আমরা ফেলে দিয়েছি। রাখতে চাইলে লিখতে হতো s = s.concat(" CSE"); — তাহলে print হতো BUET CSE
Q18. (Real exam style — asked April 2024) (a) What is a functional interface in Java? What does the @FunctionalInterface annotation do? (b) Name two built-in functional interfaces. (c) Define a functional interface Square with method int calc(int x), and implement it with a lambda that returns \(x^2\). Print calc(5).
Q18. (Real exam style — April 2024-এ এসেছিল) (a) Java-তে functional interface কী? @FunctionalInterface annotation কী কাজ করে? (b) দুইটা built-in functional interface-এর নাম লিখুন। (c) int calc(int x) method-সহ একটা functional interface Square define করুন, আর এমন একটা lambda দিয়ে implement করুন যেটা \(x^2\) return করে। calc(5) print করুন।
Show Answerউত্তর দেখুন
Answer: (a) A functional interface is an interface with exactly one abstract method. Because there is only one method, a lambda expression can implement it directly. @FunctionalInterface is optional but useful: it makes the compiler give an error if the interface ever gets a second abstract method — so the lambda-friendliness is protected. (b) Any two of: Runnable (run()), Comparator (compare()), Function (apply()), Predicate (test()). (c)
@FunctionalInterface
interface Square {
    int calc(int x);
}

public class Main {
    public static void main(String[] args) {
        Square sq = x -> x * x;          // lambda implements calc
        System.out.println(sq.calc(5));  // 25
    }
}
The lambda x -> x * x becomes the body of calc; Java knows this because Square has only that one abstract method.
Answer: (a) Functional interface হলো এমন interface যাতে ঠিক একটা abstract method থাকে। Method একটাই বলে একটা lambda expression সরাসরি সেটা implement করতে পারে। @FunctionalInterface optional কিন্তু কাজের: কেউ পরে দ্বিতীয় abstract method যোগ করলে compiler error দেয় — ফলে lambda-friendliness রক্ষা পায়। (b) যেকোনো দুইটা: Runnable (run()), Comparator (compare()), Function (apply()), Predicate (test())। (c)
@FunctionalInterface
interface Square {
    int calc(int x);
}

public class Main {
    public static void main(String[] args) {
        Square sq = x -> x * x;          // lambda implements calc
        System.out.println(sq.calc(5));  // 25
    }
}
Lambda x -> x * x হয়ে যায় calc-এর body; Java এটা বোঝে কারণ Square-এ ওই একটাই abstract method।
Q19. (Real exam style — asked October 2017 / October 2018) (a) Rewrite this anonymous inner class as a lambda:
button.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        count++;
    }
});
(b) A list List<String> names is given. WITHOUT writing any loop, produce a List<Integer> of the name lengths, using streams.
Q19. (Real exam style — October 2017 / October 2018-এ এসেছিল) (a) এই anonymous inner class-টাকে lambda দিয়ে নতুন করে লিখুন:
button.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        count++;
    }
});
(b) একটা list List<String> names দেওয়া আছে। কোনো loop না লিখে, streams ব্যবহার করে name-গুলোর length-এর একটা List<Integer> বানান।
Show Answerউত্তর দেখুন
Answer: (a) ActionListener is a functional interface (one abstract method, actionPerformed), so the whole block shrinks to one line:
button.addActionListener(e -> count++);
The lambda's parameter e is the ActionEvent; the body is what the method did. (b) Open a stream, map each name to its length, collect the results:
List<Integer> lengths = names.stream()
        .map(String::length)               // or: n -> n.length()
        .collect(Collectors.toList());
map transforms every element (String → Integer), and collect(Collectors.toList()) gathers them into a new list — the stream does all the looping internally, so no for/while appears in our code.
Answer: (a) ActionListener একটা functional interface (একটাই abstract method, actionPerformed), তাই পুরো block এক লাইনে নেমে আসে:
button.addActionListener(e -> count++);
Lambda-র parameter e-ই হলো ActionEvent; body-টা method-টা যা করত তাই। (b) একটা stream খুলুন, প্রতিটা name-কে তার length-এ map করুন, result collect করুন:
List<Integer> lengths = names.stream()
        .map(String::length)               // বা: n -> n.length()
        .collect(Collectors.toList());
map প্রতিটা element বদলে দেয় (String → Integer), আর collect(Collectors.toList()) সেগুলো নতুন list-এ জমা করে — loop চালানোর কাজটা stream ভেতরে ভেতরে নিজেই করে, তাই আমাদের code-এ কোনো for/while নেই।