সরাসরি পর্বে যান
পর্ব ৫৪ · ৫৫-এর মধ্যে · মডিউল ৮

লিখিত ও মৌখিক (ভাইভা) প্রশ্ন — C++ মডেল উত্তর ও কৌশল

Written & Viva Questions in C++ — Model Answers and How to Present Them

Taught in Bangla, this page prepares you for written exams and viva: what examiners look for, answer structures for short and long questions, how to speak in a viva, model answers to 30 long questions on OOP, templates, STL and modern C++, and 77 rapid-fire viva questions.

এই পর্বে যা শিখবেন

  • লিখিত উত্তর কোন ক্রমে সাজালে পরীক্ষক সহজে নম্বর দেন — সংজ্ঞা থেকে উপসংহার
  • ছোট প্রশ্ন আর বড় প্রশ্নের উত্তরের দৈর্ঘ্য ও গভীরতার পার্থক্য
  • ভাইভায় আগে ছোট নির্ভুল উত্তর, তারপর উদাহরণ — আর “জানি না” সৎভাবে সামলানো
  • পুরো C++ কোর্সের ৩০টি ক্লাসিক বড় প্রশ্ন আর ৭০টির বেশি ভাইভা প্রশ্নের মডেল উত্তর
  • AI-কে ভাইভা সঙ্গী হিসেবে ব্যবহার করা — আর তার ভুল ধরা

১ · লিখিত পরীক্ষা ও ভাইভা — পরীক্ষক আসলে কী দেখেন

আগের দুই পর্বে আপনি কোড পড়ে আউটপুট বলেছেন আর MCQ অনুশীলন করেছেন। সেখানে উত্তর হয় ঠিক, নয় ভুল। লিখিত পরীক্ষা আর ভাইভা আলাদা। এখানে একই প্রশ্নে দুজন একই তথ্য জানলেও একজন বেশি নম্বর পান — কারণ তিনি তথ্যটি গুছিয়ে, প্রমাণসহ আর নিজের ভাষায় উপস্থাপন করেছেন।

C++-এর লিখিত প্রশ্ন সাধারণত তিন ধরনের হয়। “কী ও কেন” — যেমন “RAII কী? কেন দরকার?” “পার্থক্য লিখুন” — যেমন “map ও unordered_map-এর পার্থক্য।” আর “উদাহরণসহ ব্যাখ্যা করুন” — যেমন “virtual function কীভাবে কাজ করে? উদাহরণসহ লিখুন।” C-এর তুলনায় C++-এ পরীক্ষকেরা নকশার কারণ বেশি জানতে চান: কেন destructor virtual হবে, কেন move constructor-এ noexcept দেওয়া ভালো, কেন raw new এড়ানো উচিত।

যেকোনো লিখিত উত্তর পড়ার সময় একজন পরীক্ষক মনে মনে পাঁচটি জিনিস খোঁজেন:

নির্ভুল সংজ্ঞা

প্রথম এক–দুই বাক্যে মূল কথা। ভুল বা অস্পষ্ট সংজ্ঞা দিয়ে শুরু হলে বাকি উত্তর পড়ার আগেই নম্বর কমে।

শুরু

বোঝার প্রমাণ

“কীভাবে কাজ করে” আর “কেন এভাবে বানানো” — মুখস্থ সংজ্ঞার বাইরে যা বলবেন, সেটাই বোঝার প্রমাণ।

ব্যাখ্যা

চলবে এমন কোড

ছোট, সম্পূর্ণ, compile হবে এমন উদাহরণ। সাথে আউটপুট। আধুনিক C++ লিখলে (std::vector, smart pointer) আরও ভালো।

উদাহরণ

সীমা ও ঝুঁকি

কোথায় ব্যবহার করা উচিত নয়, কোথায় undefined behavior — এই অংশটি ভালো উত্তরকে সেরা উত্তরে নেয়।

উপসংহার

এই পাতার প্রশ্নগুলো কোর্সের মডিউল অনুযায়ী সাজানো। কোনো অংশে বারবার আটকালে টেবিলের পর্বগুলো আবার পড়ুন:

কোর্সের মডিউলপর্বলিখিত প্রশ্নভাইভা প্রশ্ন
১–৩ · ভিত্তি, ভাষা, মেমরি০১–১৯অংশ ৪ (ক-০১–ক-০৬)ভ-০১–ভ-২৪
৪ · অবজেক্ট-ওরিয়েন্টেড ডিজাইন২০–২৭অংশ ৫ (খ-০১–খ-১২)ভ-২৫–ভ-৪৫
৫ · জেনেরিক প্রোগ্রামিং ও STL২৮–৩৫অংশ ৬ (গ-০১–গ-০৬)ভ-৪৬–ভ-৫৭
৬–৭ · আধুনিক C++, সিস্টেম ও প্রজেক্ট৩৬–৫১অংশ ৭ (ঘ-০১–ঘ-০৬)ভ-৫৮–ভ-৭৭

এই পাতার কোনো প্রশ্ন কোনো নির্দিষ্ট পরীক্ষার প্রশ্নপত্র থেকে নেওয়া নয়। এগুলো এমন ধরনের প্রশ্ন, যা বিশ্ববিদ্যালয়, চাকরি বা ইন্টারভিউর পরীক্ষায় প্রায়ই আসে। সিলেবাস, নম্বর বণ্টন আর সময় সবসময় নিজের পরীক্ষার সর্বশেষ বিজ্ঞপ্তি থেকে মিলিয়ে নিন। সব কোড ও আউটপুট ধরে নিয়েছে সাধারণ 64-bit Linux, GCC আর C++23 (int 32-bit, pointer 64-bit).

C জানলে

উত্তর সাজানোর কাঠামো C-এর মতোই — সংজ্ঞা, ব্যাখ্যা, কোড, চিত্র, উপসংহার। পার্থক্য প্রশ্নের ধরনে: C-তে যেখানে malloc/free আর pointer নিয়ে প্রশ্ন আসে, C++-এ সেখানে আসে মালিকানা, RAII আর smart pointer. C-তে “array কি pointer?” প্রশ্নের জায়গায় C++-এ আসে “reference কি pointer?” C-এর লিখিত প্রশ্নব্যাংক দেখতে চাইলে C কোর্সের লিখিত ও মৌখিক প্রশ্ন পর্বটি দেখুন।

২ · উত্তরের কাঠামো — ছোট প্রশ্ন আর বড় প্রশ্ন

প্রায় যেকোনো “ব্যাখ্যা করুন” প্রশ্নের জন্য একটি পাঁচ অংশের কাঠামো কাজ করে। একে একটি দালানের মতো ভাবুন — সংজ্ঞা হলো ভিত, ব্যাখ্যা দেয়াল, কোড আর চিত্র জানালা-দরজা, আর উপসংহার ছাদ। ভিত না থাকলে বাকিটা দাঁড়ায় না, ছাদ না থাকলে দালান অসম্পূর্ণ।

সংজ্ঞা → ব্যাখ্যা → উদাহরণ কোড → চিত্র / টেবিল → উপসংহার

ছোট প্রশ্ন বনাম বড় প্রশ্ন

প্রশ্নের নম্বর আর সময় দেখে কাঠামো ছোট-বড় করুন। একটি সাধারণ হিসাব: মোট মিনিটকে মোট নম্বর দিয়ে ভাগ করলে পাবেন প্রতি নম্বরে কত মিনিট — সেই হিসাবে প্রতিটি প্রশ্নে সময় দিন।

বিষয়ছোট প্রশ্নবড় প্রশ্ন
দৈর্ঘ্য৫–১০ লাইন, অর্ধেক পাতার মতো১–২ পাতা
অংশসংজ্ঞা + এক লাইনের ব্যাখ্যা + ছোট উদাহরণ বা একটি পয়েন্টপাঁচটি অংশই — সংজ্ঞা, ব্যাখ্যা, কোড ও আউটপুট, চিত্র বা টেবিল, উপসংহার
কোড২–৪ লাইনের টুকরো যথেষ্ট১০–২০ লাইনের সম্পূর্ণ প্রোগ্রাম, #include ও mainসহ
“পার্থক্য লিখুন” হলে৩–৪ সারির টেবিল৫–৭ সারির টেবিল + দুই পাশের ছোট উদাহরণ + কোনটি কখন বেছে নেবেন
সাধারণ ভুলঅপ্রয়োজনীয় ইতিহাস লিখে সময় নষ্টশুধু কোড, কোনো ব্যাখ্যা নেই — অথবা শুধু লেখা, কোনো কোড নেই

এবার একটি ক্লাসিক বড় প্রশ্ন দিয়ে কাঠামোটি হাতে-কলমে দেখি: “virtual function কীভাবে কাজ করে? উদাহরণসহ লিখুন।” নিচের ডায়াগ্রামে “পরে” চাপুন — প্রতিটি ধাপে উত্তরপত্রে একটি নতুন অংশ যোগ হবে।

  1. সংজ্ঞাএক-দুই বাক্যে
  2. ব্যাখ্যাstatic বনাম dynamic
  3. কোডআউটপুটসহ
  4. চিত্রvptr ও vtable
  5. উপসংহারসতর্কতা ও খরচ
উত্তরপত্রধাপ ১ — সংজ্ঞা
Virtual function হলো base class-এর এমন member function,
যাকে derived class override করতে পারে, এবং base-এর
pointer বা reference দিয়ে ডাকলে object-এর আসল (dynamic)
টাইপের সংস্করণটি চলে — সিদ্ধান্ত হয় প্রোগ্রাম চলার সময়।
উত্তরপত্রধাপ ২ — ব্যাখ্যা যোগ হলো
… (সংজ্ঞা) …

সাধারণ ফাংশন: কোনটি চলবে, compiler ঠিক করে
  ভ্যারিয়েবলের ঘোষিত (static) টাইপ দেখে — static binding.
virtual ফাংশন: object-এর আসল (dynamic) টাইপ দেখে,
  চলার সময় — dynamic binding.
শর্ত: (১) base-এ virtual, (২) derived-এ একই signature-এ
  override, (৩) ডাক base-এর pointer বা reference দিয়ে।
  object-কে মান হিসেবে কপি করলে slicing হয়, virtual কাজ করে না।
উত্তরপত্রধাপ ৩ — উদাহরণ কোড
… (সংজ্ঞা, ব্যাখ্যা) …

struct Shape {
    virtual double area() const { return 0; }
    virtual ~Shape() = default;
};
struct Square : Shape {
    double s = 4;
    double area() const override { return s * s; }
};
Square sq;
const Shape& ref = sq;
std::println("{}", ref.area());   // আউটপুট: 16
ref-এর টাইপ Shape&, তবু Square::area চলল।
উত্তরপত্রধাপ ৪ — চিত্র
… (সংজ্ঞা, ব্যাখ্যা, কোড) …

  sq (object)              Square-এর vtable
 +-------------+          +------------------+
 | vptr  ------+--------> | &Square::area    |
 | s = 4       |          | &Square::~Square |
 +-------------+          +------------------+
 ref.area()  →  vptr পড়ো → vtable-এর ঘর → Square::area
(প্রচলিত বাস্তবায়ন; standard vtable বাধ্য করে না)
উত্তরপত্রধাপ ৫ — সম্পূর্ণ উত্তর
… (সংজ্ঞা, ব্যাখ্যা, কোড, চিত্র) …

উপসংহার:
• polymorphic base-এর destructor virtual রাখুন — নইলে
  base pointer দিয়ে delete করা undefined behavior.
• override লিখুন — signature ভুল হলে compiler ধরবে।
• constructor/destructor-এর ভেতরে virtual ডাকলে
  derived-এর সংস্করণ চলে না।
• খরচ: প্রতি object-এ একটি vptr, প্রতি ডাকে একটি
  পরোক্ষ লাফ; সাধারণত inline হয় না।
  1. ধাপ ১ — সংজ্ঞা। তিনটি মূল শব্দ থাকতেই হবে: override, base-এর pointer বা reference, আর চলার সময় সিদ্ধান্ত. এই তিনটির একটি বাদ পড়লে সংজ্ঞা অসম্পূর্ণ। বেশি লম্বা করবেন না — দুই বাক্যই যথেষ্ট।
  2. ধাপ ২ — ব্যাখ্যা। static binding আর dynamic binding-এর তুলনা এখানেই বোঝার প্রমাণ। সাথে তিনটি শর্ত আর object slicing-এর উল্লেখ — অনেকে এটি জানেন না, তাই আপনার উত্তর আলাদা হয়ে যায়।
  3. ধাপ ৩ — উদাহরণ কোড। ছোট, সম্পূর্ণ, আধুনিক। override আর virtual destructor কোডেই দেখান। শেষে আউটপুট আর এক লাইনের মন্তব্য — “ঘোষিত টাইপ Shape, তবু Square-এর ফাংশন চলল” — এটিই পুরো প্রশ্নের সারকথা।
  4. ধাপ ৪ — চিত্র। object-এর ভেতরে vptr, তা থেকে তীর vtable-এ, সেখান থেকে ফাংশনে। নিচে এক লাইনে লিখুন “প্রচলিত বাস্তবায়ন; standard বাধ্য করে না” — এই সতর্কতা আপনার জ্ঞানের গভীরতা দেখায়।
  5. ধাপ ৫ — উপসংহার। virtual destructor, override, constructor-এর ভেতরের ডাক, আর খরচ — চারটি বুলেট। পরীক্ষক এখানে দেখেন আপনি বাস্তব কোডে এটি ব্যবহার করতে জানেন কি না। এখন উত্তরটি সম্পূর্ণ।
একটি সম্ভাব্য সময়-ভাগ (আমাদের পরামর্শ)

বড় প্রশ্নে মোট সময়ের মোটামুটি এক-পঞ্চমাংশ সংজ্ঞা ও ব্যাখ্যায়, অর্ধেকের মতো কোড ও চিত্রে, আর বাকিটা উপসংহার ও শেষবার চোখ বোলাতে দিন। প্রতিটি পরীক্ষকের নম্বর-ভাগ আলাদা হতে পারে, কিন্তু পাঁচটি অংশই থাকলে কোনো ভাগে বড় ফাঁক থাকে না।

খাতায় C++ কোড লেখার ছয় নিয়ম

  1. সম্পূর্ণ প্রোগ্রাম: দরকারি #include, int main(). void main() standard C++ নয়। #include <bits/stdc++.h> GCC-র নিজস্ব header — খাতায় আসল header-এর নাম লিখুন।
  2. আধুনিক রূপ: C-style array-র বদলে std::vector, raw new-এর বদলে std::make_unique. পরীক্ষক এতে বোঝেন আপনি C++ লিখছেন, “class যোগ করা C” নয়।
  3. override আর const: ছোট শব্দ, কিন্তু নকশার বোঝাপড়া দেখায়।
  4. Indentation ও অর্থবহ নাম: balance, owner — a, b নয়।
  5. আউটপুট লিখুন: কোডের নিচে “আউটপুট: …”. দেখায় আপনি মনে মনে প্রোগ্রামটি চালিয়ে দেখেছেন।
  6. Edge case এক লাইনে: খালি vector, null pointer, self-assignment — কোডে না রাখলেও নিচে উল্লেখ করুন।

৩ · ভাইভায় কথা বলার কৌশল

ভাইভা অনেকটা ক্রিকেটে DRS রিভিউয়ের মতো — প্রথম সিদ্ধান্তের পর তৃতীয় আম্পায়ার একের পর এক অ্যাঙ্গেল দেখেন। পরীক্ষকও আপনার প্রথম উত্তর শুনে সেখান থেকে পরের প্রশ্ন বানান। এমন প্রশ্নকে বলে follow-up প্রশ্ন. তাই ভাইভার আসল দক্ষতা হলো প্রশ্নের শিকল সামলানো।

  • আগে ছোট নির্ভুল উত্তর, তারপর উদাহরণ: “RAII মানে রিসোর্সের জীবন object-এর জীবনের সাথে বাঁধা — constructor-এ নেওয়া, destructor-এ ছাড়া। যেমন std::lock_guard.” পরীক্ষক চাইলে বিস্তারে যান।
  • Think aloud: নিশ্চিত না হলে ভাবনাটা জোরে বলুন — “আমি এভাবে ভাবছি: vector বড় হলে নতুন মেমরিতে সরে যায়, তাহলে পুরোনো iterator…”. পরীক্ষক আপনার যুক্তির পথ দেখতে চান।
  • সৎ থাকুন: “জানি না, তবে এভাবে ভাবব…” বলা দুর্বলতা নয়। আন্দাজে ভুল তথ্য জোর দিয়ে বললে পরীক্ষক আপনার বাকি ঠিক উত্তরগুলো নিয়েও সন্দেহ করেন।
  • অনুমান স্পষ্ট করুন: “sizeof pointer কত?” — “সাধারণ 64-bit সিস্টেমে ৮ বাইট।” “unordered_map-এ ক্রম কী হবে?” — “নির্দিষ্ট নয়, library-র ওপর নির্ভর করে।” এই সতর্কতা অভিজ্ঞতার চিহ্ন।
  • UB-কে UB বলুন: “i++ + ++i-এর মান কত?” — সঠিক উত্তর “undefined behavior.” একটি সংখ্যা বানিয়ে বলা ভুল উত্তর।
  • বোর্ড চান: জটিল কিছু হলে বলুন “একটু এঁকে দেখাই?” — vptr আর vtable-এর ছবি মুখের কথার চেয়ে শক্তিশালী।

নিচের ডায়াগ্রামে একটি বাস্তবধর্মী ভাইভার শিকল দেখুন। প্রতিটি ধাপে প্রশ্ন একটু গভীরে যাচ্ছে। শেষ ধাপে প্রার্থী পুরো নিশ্চিত নন — তবু সঠিকভাবে সামলাচ্ছেন।

প্রশ্ন ১সহজ শুরু
পরীক্ষক: virtual function কী?
আপনি:   base-এর এমন ফাংশন, যা derived override করতে পারে;
        base-এর pointer বা reference দিয়ে ডাকলে object-এর
        আসল টাইপের সংস্করণ চলে। যেমন Shape* দিয়ে Square::area.
প্রশ্ন ২ফলো-আপ — ভেতরের কৌশল
পরীক্ষক: চলার সময় সে কীভাবে জানে কোনটি ডাকবে?
আপনি:   প্রচলিত বাস্তবায়নে প্রতিটি polymorphic class-এর একটি
        vtable থাকে — virtual ফাংশনগুলোর ঠিকানার তালিকা।
        প্রতিটি object-এ লুকানো একটি vptr সেই তালিকা দেখায়।
        ডাকের সময় vptr → vtable-এর ঘর → ফাংশন।
প্রশ্ন ৩ফলো-আপ — অবস্থান
পরীক্ষক: vtable কোথায় থাকে? প্রতি object-এ একটি করে?
আপনি:   না — প্রতি class-এ একটি, সাধারণত প্রোগ্রামের স্থির
        (read-only) ডেটা অংশে; heap বা stack-এ নয়। প্রতি
        object-এ থাকে শুধু vptr — 64-bit-এ সাধারণত ৮ বাইট।
        এগুলো compiler-এর বাস্তবায়ন, standard-এর নিয়ম নয়।
প্রশ্ন ৪ফলো-আপ — ফাঁদ
পরীক্ষক: base-এর constructor থেকে virtual ফাংশন ডাকলে?
আপনি:   base-এর সংস্করণই চলবে। base constructor চলার সময়
        derived অংশ এখনো তৈরি হয়নি, তাই object-এর dynamic
        টাইপ তখন base ধরা হয় — vptr তখন base-এর vtable
        দেখায়। destructor-এর ভেতরেও একই নিয়ম।
প্রশ্ন ৫কঠিন — পুরো নিশ্চিত নন
পরীক্ষক: আর ফাংশনটি যদি base-এ pure virtual হয়?
আপনি:   পুরো নিশ্চিত নই, তবে এভাবে ভাবছি — base-এর কোনো
        বাস্তবায়ন নেই, আর derived-এরটা তখন ডাকা যায় না।
        তাই এটি বৈধ হতে পারে না; আমার ধারণা undefined
        behavior. বাস্তবে প্রোগ্রাম সম্ভবত ক্র্যাশ করবে।
(ঠিক: undefined behavior; GCC-তে সাধারণত
"pure virtual method called" লিখে প্রোগ্রাম থেমে যায়।)
  1. সহজ শুরু। সংজ্ঞা সংক্ষেপে, সাথে একটি উদাহরণ। এখানে বেশি বলার দরকার নেই — পরীক্ষক পরের প্রশ্নের জন্য সূত্র খুঁজছেন।
  2. “কীভাবে” প্রশ্ন। vtable আর vptr — দুটি শব্দ আর এক লাইনের প্রবাহ। এই উত্তরেই বোঝা যায় আপনি শুধু ব্যবহার নয়, ভেতরের কৌশলও জানেন।
  3. প্রচলিত ভুল ধারণা পরীক্ষা। অনেকে বলেন “প্রতি object-এ একটি vtable” — ভুল। সঠিক উত্তরের সাথে “এটি বাস্তবায়ন, standard নয়” যোগ করা অভিজ্ঞতার চিহ্ন।
  4. ফাঁদের প্রশ্ন। constructor-এর ভেতরে virtual ডাক অনেক বাস্তব বাগের উৎস। কারণসহ উত্তর — “derived অংশ তখনো তৈরি হয়নি” — পূর্ণ কৃতিত্ব পায়।
  5. “জানি না” সামলানো। প্রার্থী সৎভাবে বলছেন নিশ্চিত নন, তারপর যুক্তি দিয়ে এগোচ্ছেন — আর যুক্তিটি আসলে সঠিক। এভাবে ভেবে বলা উত্তর প্রায়ই পূর্ণ বা অন্তত আংশিক কৃতিত্ব পায়।

ভাইভাকে বিকাশে টাকা পাঠানোর মতো ভাবুন। নম্বরের একটি অঙ্ক ভুল হলে টাকা ভুল জায়গায় যায়, তাই পাঠানোর আগে অ্যাপ নাম দেখিয়ে নিশ্চিত হতে বলে। ভাইভাতেও প্রশ্ন অস্পষ্ট হলে আগে নিশ্চিত হয়ে নিন — “আপনি কি C++11-এর পরের নিয়মের কথা বলছেন?” ভুল প্রশ্নের নিখুঁত উত্তরের চেয়ে সঠিক প্রশ্নের সাধারণ উত্তর অনেক বেশি কাজের।

৪ · অংশ ক — ভিত্তি, ভাষা আর মেমরি (মডিউল ১–৩)

রিভিশনের জন্য: পর্ব ০১, পর্ব ০৫, পর্ব ১০, পর্ব ১১, পর্ব ১৫, পর্ব ১৬, পর্ব ১৭, পর্ব ১৮.

প্রতিটি প্রশ্ন পড়ে আগে নিজে খাতায় উত্তর লিখুন, তারপর “→ উত্তর” চেপে মেলান। মডেল উত্তরগুলো সংক্ষিপ্ত কিন্তু সম্পূর্ণ — বড় প্রশ্নে অংশ ২-এর কাঠামো মেনে চিত্র ও কোড যোগ করুন।

ক-০১C আর C++-এর পার্থক্য কী? C থাকতে C++ কেন? (সহজ)

সংজ্ঞা: C একটি procedural ভাষা; C++ C-এর ওপর গড়া একটি multi-paradigm ভাষা — procedural, object-oriented, generic আর functional ধাঁচ একসাথে। Bjarne Stroustrup ১৯৭৯ সালে Bell Labs-এ “C with Classes” নামে কাজ শুরু করেন; ১৯৮৩ সালে নাম হয় C++. প্রথম ISO standard আসে ১৯৯৮ সালে (C++98), তারপর C++11 থেকে প্রতি তিন বছরে নতুন সংস্করণ — C++23 প্রকাশিত, আর C++26 চূড়ান্ত হওয়ার শেষ পর্যায়ে।

বিষয়CC++
নিজের টাইপstruct — শুধু ডেটাclass — ডেটা + কাজ + access control
রিসোর্স ছাড়াহাতে free, fclosedestructor-এ স্বয়ংক্রিয় (RAII)
জেনেরিক কোডmacro বা void*template, type-safe
ভুল জানানোreturn code, errnoexception, std::expected (C++23)
নাম আলাদা রাখাপ্রিফিক্স (mylib_)namespace, function overloading
লাইব্রেরিছোট standard librarySTL — container, algorithm, smart pointer

C++ কি C-এর superset? প্রায়, কিন্তু পুরোপুরি নয়। যেমন C-তে int *p = malloc(8); বৈধ, C++-এ void* থেকে স্বয়ংক্রিয় রূপান্তর নেই বলে error. C-তে int new = 5; চলে, C++-এ new একটি keyword. sizeof('a') C-তে sizeof(int), C++-এ ১.

উপসংহার: C++ কেন — বড় সিস্টেমে ভুলের সুযোগ কমাতে (RAII, type safety) আর C-এর গতি বজায় রেখে উঁচু স্তরের abstraction দিতে। এর মূলনীতি zero-overhead: যা ব্যবহার করবেন না, তার দাম দিতে হবে না। তাই game engine, browser, database, trading system-এ C++ এখনো প্রধান ভাষা।

ঝালিয়ে নিন: পর্ব ০১ · C++ কেন?

ক-০২Reference আর pointer-এর পার্থক্য লিখুন। কোনটি কখন ব্যবহার করবেন? (সহজ)

Reference হলো একটি বিদ্যমান object-এর আরেকটি নাম; pointer হলো একটি ভ্যারিয়েবল, যার মান একটি ঠিকানা।

বিষয়Reference (int& r = x;)Pointer (int* p = &x;)
শুরুর মানঘোষণার সময় বাধ্যতামূলকনা দিলেও চলে (দেওয়া উচিত)
অন্য কিছুকে দেখানোযায় না — চিরকাল একই objectযায় — p = &y;
খালি থাকাবৈধ null reference নেইnullptr হতে পারে
ব্যবহারr = 5; — সরাসরি*p = 5;, p->f()
Arithmeticনেইআছে (p + 1)
sizeofযে object দেখায় তার মাপঠিকানার মাপ (64-bit-এ সাধারণত ৮)

উদাহরণ: void addBonus(int& salary) { salary += 500; } — ডাকার জায়গায় মূল ভ্যারিয়েবল বদলায়, কোনো & বা * লিখতে হয় না। বড় object কপি ছাড়া পাঠাতে const std::string&.

উপসংহার: “অবশ্যই একটি object আছে” এমন ক্ষেত্রে reference; “হয়তো কিছু নেই” বা “পরে অন্য কিছুকে দেখাবে” হলে pointer (বা std::optional). সতর্কতা: function থেকে local ভ্যারিয়েবলের reference ফেরত দিলে dangling reference — undefined behavior.

ঝালিয়ে নিন: পর্ব ১০ · reference, পর্ব ১৫ · pointer

ক-০৩Const correctness কী? const কত জায়গায় বসে, উদাহরণসহ লিখুন। (মাঝারি)

Const correctness মানে যেখানে কোনো কিছু বদলানোর কথা নয়, সেখানে const লিখে compiler-কে সেই প্রতিশ্রুতি পাহারা দিতে দেওয়া। ভুল করে বদলালে compile error — বাগ চলার আগেই ধরা পড়ে।

  • ভ্যারিয়েবল: const int maxSeat = 40; — শুরুর পর বদলানো যায় না।
  • Parameter: void print(const std::vector<int>& v) — কপি নেই, আর ফাংশন v বদলাবে না।
  • Member function: int balance() const; — এই ফাংশন object-এর অবস্থা বদলাবে না; const object-এ শুধু এমন ফাংশনই ডাকা যায়।
  • Pointer: const int* p — যা দেখায় তা বদলানো যাবে না (pointer to const); int* const p — pointer নিজে অন্য কোথাও যাবে না (const pointer). ডান থেকে বাঁয়ে পড়ুন।
  • mutable: const ফাংশনের ভেতরেও বদলানো যায় এমন member — যেমন cache বা mutex.

const বনাম constexpr: const শুধু বলে “বদলাবে না” — মান চলার সময়ও ঠিক হতে পারে (const int n = readInput();). constexpr ভ্যারিয়েবলের মান compile-এর সময়ই জানা থাকতে হবে।

উপসংহার: const প্রথম দিন থেকে লিখুন; পরে যোগ করতে গেলে একটি ফাংশন থেকে আরেকটিতে ছড়িয়ে পড়ে। const object বা reference নিয়ে কাজ করা কোড thread-এর মধ্যে ভাগ করাও সহজ।

ঝালিয়ে নিন: পর্ব ০৫ · টাইপ, auto আর const, পর্ব ২০ · class ও object

ক-০৪Namespace কী? কেন দরকার? using namespace std; header-এ কেন লিখবেন না? (সহজ)

Namespace হলো নামের একটি আলাদা ঘর, যাতে বিভিন্ন লাইব্রেরির একই নাম ধাক্কা না খায়। std::sort আর আপনার mylib::sort পাশাপাশি থাকতে পারে, কারণ পুরো নাম আলাদা। :: হলো scope resolution operator.

namespace bank {
    double interest(double amount) { return amount * 0.07; }
}
namespace loan {
    double interest(double amount) { return amount * 0.12; }
}
double a = bank::interest(1000);   // 70
double b = loan::interest(1000);   // 120

ধরন: nested namespace (namespace app::db { }, C++17), namespace alias (namespace fs = std::filesystem;), আর anonymous namespace — যার ভেতরের নাম শুধু সেই .cpp ফাইলে দেখা যায় (internal linkage).

Header-এ using namespace std; নয় কেন: header যে ফাইলই include করুক, তার ভেতরে std-এর শত শত নাম ঢুকে পড়ে। কারও নিজের count বা distance ফাংশন থাকলে হঠাৎ ambiguity বা ভুল ফাংশন ডাকা হতে পারে — আর কেন হলো, খুঁজে পাওয়া কঠিন। .cpp ফাইলের ভেতরে, ছোট scope-এ, বা নির্দিষ্ট নামের জন্য using std::cout; তুলনামূলক নিরাপদ।

ঝালিয়ে নিন: পর্ব ১১ · namespace আর header

ক-০৫Destructor কী? RAII ব্যাখ্যা করুন, উদাহরণসহ। (মাঝারি)

Destructor হলো class-এর বিশেষ member function (~ClassName()), যা object-এর জীবন শেষ হলে আপনাআপনি চলে। এর কোনো parameter বা return type নেই, একটি class-এ একটিই থাকে, আর C++11 থেকে এটি ডিফল্টভাবে noexcept.

RAII (Resource Acquisition Is Initialization) মানে রিসোর্সের — মেমরি, ফাইল, lock, socket — জীবন একটি object-এর জীবনের সাথে বেঁধে দেওয়া: constructor-এ রিসোর্স নেওয়া, destructor-এ ছাড়া। object scope থেকে বের হলেই রিসোর্স মুক্ত — স্বাভাবিকভাবে বের হোক, return হোক বা exception-এর কারণে stack unwinding হোক।

#include <print>

struct Logger {
    const char* name;
    explicit Logger(const char* n) : name(n) { std::println("open  {}", name); }
    ~Logger() { std::println("close {}", name); }
};

int main() {
    Logger a("A");
    {
        Logger b("B");
        std::println("inside block");
    }                          // b-এর scope শেষ: এখানেই close B
    Logger c("C");
    std::println("end of main");
}                              // উল্টো ক্রমে: close C, তারপর close A

আউটপুট: open A, open B, inside block, close B, open C, end of main, close C, close A. দুটি নিয়ম চোখে পড়ে: destructor চলে ঠিক scope-এর শেষে (নির্ধারিত সময়ে, garbage collector-এর মতো “কোনো এক সময়” নয়), আর একই scope-এর object ধ্বংস হয় তৈরির উল্টো ক্রমে।

উপসংহার: standard library-র প্রায় সবকিছুই RAII — std::vector, std::string, std::fstream, std::lock_guard, std::unique_ptr. তাই আধুনিক C++-এ হাতে delete বা close() প্রায় লিখতেই হয় না। destructor থেকে exception ছোড়া উচিত নয় — বেরিয়ে গেলে std::terminate ডাকা হয়।

ঝালিয়ে নিন: পর্ব ১৭ · RAII ও smart pointer, পর্ব ২১ · constructor ও destructor

ক-০৬Smart pointer কী? unique_ptr, shared_ptr আর weak_ptr-এর পার্থক্য উদাহরণসহ লিখুন। (মাঝারি)

Smart pointer হলো এমন RAII object, যা heap-এর একটি object-এর মালিক হয় এবং মালিকানা শেষ হলে নিজেই delete করে। এতে memory leak, double delete আর অনেক dangling pointer-এর ঝুঁকি দূর হয়।

  • std::unique_ptr — একক মালিক। কপি করা যায় না, শুধু std::move দিয়ে মালিকানা সরানো যায়। সাধারণত raw pointer-এর সমান মাপ, বাড়তি খরচ প্রায় নেই। ডিফল্ট পছন্দ।
  • std::shared_ptr — যৌথ মালিকানা। একটি control block-এ মালিকের সংখ্যা (reference count) রাখে; শেষ মালিক চলে গেলে object ধ্বংস। count বাড়ানো-কমানো atomic, তাই খরচ আছে।
  • std::weak_ptr — মালিক নয়, শুধু পর্যবেক্ষক। count বাড়ায় না; lock() দিয়ে ব্যবহারের আগে দেখে নেয় object এখনো আছে কি না। দুটি shared_ptr একে অপরকে ধরে রাখলে (reference cycle) কেউ মুক্ত হয় না — একদিকে weak_ptr দিলে সমস্যা মেটে।
#include <memory>
#include <print>
#include <utility>

struct Node {
    int id;
    explicit Node(int i) : id(i) {}
    ~Node() { std::println("Node {} destroyed", id); }
};

int main() {
    auto u = std::make_unique<Node>(1);
    auto u2 = std::move(u);                   // মালিকানা সরল
    std::println("u empty? {}", u == nullptr);

    auto s1 = std::make_shared<Node>(2);
    std::weak_ptr<Node> w = s1;
    {
        auto s2 = s1;                         // দুই মালিক
        std::println("use_count = {}", s1.use_count());
    }
    std::println("use_count = {}", s1.use_count());
    s1.reset();                               // শেষ মালিক চলে গেল
    std::println("expired? {}", w.expired());
}

আউটপুট: u empty? true, use_count = 2, use_count = 1, Node 2 destroyed, expired? true, আর একদম শেষে Node 1 destroyed — যখন main শেষে u2 ধ্বংস হয়। weak_ptr থাকা সত্ত্বেও Node 2 ধ্বংস হয়েছে, কারণ weak_ptr মালিক নয়।

উপসংহার: ডিফল্ট unique_ptr; সত্যিই যৌথ মালিকানা লাগলে shared_ptr; cycle ভাঙতে বা “থাকলে দেখব” ধরনের সম্পর্কে weak_ptr. তৈরি করুন std::make_unique / std::make_shared দিয়ে — raw new লিখতে হয় না, আর make_shared object ও control block একবারে বরাদ্দ করে। যেখানে মালিকানা নেই, শুধু ব্যবহার, সেখানে ফাংশনে সাধারণ reference বা raw pointer পাঠানোই ঠিক।

ঝালিয়ে নিন: পর্ব ১৭ · RAII ও smart pointer

৫ · অংশ খ — অবজেক্ট-ওরিয়েন্টেড ডিজাইন (মডিউল ৪)

রিভিশনের জন্য: পর্ব ০২, পর্ব ২০, পর্ব ২১, পর্ব ২২, পর্ব ২৩, পর্ব ২৪, পর্ব ২৫, পর্ব ২৬, পর্ব ২৭.

C++-এর লিখিত পরীক্ষায় সবচেয়ে বেশি প্রশ্ন আসে এই অংশ থেকে। “পার্থক্য লিখুন” প্রশ্নে টেবিল ব্যবহার করুন — একই মাপকাঠিতে সারি, নিচে একটি ছোট উদাহরণ।

খ-০১OOP-এর চারটি স্তম্ভ কী? প্রতিটি C++ উদাহরণসহ ব্যাখ্যা করুন। (সহজ)

Object-oriented programming হলো প্রোগ্রামকে object দিয়ে সাজানো — প্রতিটি object নিজের ডেটা আর সেই ডেটার ওপর কাজ একসাথে রাখে। এর চারটি স্তম্ভ:

  • Encapsulation: ডেটা লুকিয়ে শুধু নিয়ন্ত্রিত উপায়ে বদলাতে দেওয়া। class Account { long balance_; public: void deposit(long t); }; — বাইরে থেকে কেউ সরাসরি balance ঋণাত্মক করতে পারে না; deposit নিয়ম যাচাই করে।
  • Abstraction: ভেতরের জটিলতা লুকিয়ে সহজ interface দেওয়া। std::vector-এ push_back ডাকলেই হয় — মেমরি বাড়ানো, কপি করা নিয়ে ভাবতে হয় না।
  • Inheritance: একটি class আরেকটির বৈশিষ্ট্য নিয়ে নতুন class বানানো — “is-a” সম্পর্ক। class SavingsAccount : public Account { };
  • Polymorphism: একই ডাক, ভিন্ন কাজ। compile-time — function overloading ও template; run-time — virtual function: Payment& p = bkash; p.fee(500); চালায় Bkash-এর নিয়ম।

উপসংহার: চারটি স্তম্ভ উপায়, লক্ষ্য নয়। লক্ষ্য হলো পরিবর্তন সহজ করা — একটি জায়গায় বদলালে অন্য জায়গা না ভাঙা। C++ শুধু OOP-এর ভাষা নয়; STL মূলত generic programming দিয়ে বানানো। অনেক ক্ষেত্রে inheritance-এর চেয়ে composition ভালো।

ঝালিয়ে নিন: পর্ব ০২ · বস্তু দিয়ে ভাবা, পর্ব ২০, পর্ব ২৫

খ-০২C++-এ class আর struct-এর পার্থক্য কী? (সহজ)

C++-এ class আর struct প্রায় একই জিনিস — দুটিতেই member function, constructor, inheritance, virtual, template সবই চলে। ভাষার নিয়মে পার্থক্য মাত্র দুটি:

বিষয়classstruct
member-এর ডিফল্ট accessprivatepublic
inheritance-এর ডিফল্ট accessclass D : B মানে private inheritancestruct D : B মানে public inheritance
প্রচলিত ব্যবহার (নিয়ম নয়)invariant আছে, ডেটা লুকানো — Accountসরল ডেটার গুচ্ছ — Point { int x, y; }

উপসংহার: C-এর struct-এর সাথে গুলিয়ে ফেলবেন না — C-তে struct-এ ফাংশন বা access control নেই। প্রচলিত নির্দেশিকা: object-এর কোনো নিয়ম (invariant) রক্ষা করতে হলে class আর private ডেটা; শুধু কয়েকটি মান একসাথে রাখতে struct.

ঝালিয়ে নিন: পর্ব ১২ · struct, পর্ব ২০ · class ও object

খ-০৩Constructor কত প্রকার? Member initializer list কী, আর কখন বাধ্যতামূলক? (মাঝারি)

Constructor হলো object তৈরির সময় আপনাআপনি চলা বিশেষ ফাংশন, যার নাম class-এর নামে আর কোনো return type নেই। এর কাজ object-কে প্রথম মুহূর্ত থেকেই বৈধ অবস্থায় আনা।

  • Default: argument ছাড়া — Account a;
  • Parameterized: Account b("Rahim", 5000);
  • Copy: Account(const Account&) — আরেকটি object থেকে কপি।
  • Move: Account(Account&&) noexcept — অস্থায়ী object-এর রিসোর্স সরিয়ে নেওয়া (C++11).
  • Delegating: একটি constructor আরেকটিকে ডাকে (C++11).
  • Converting: এক argument-এর constructor, যা স্বয়ংক্রিয় রূপান্তর ঘটাতে পারে — অনাকাঙ্ক্ষিত হলে explicit লিখুন।
#include <print>
#include <string>
#include <utility>

class Account {
    std::string owner_;
    long balance_;
public:
    Account() : Account("unknown", 0) {}              // default → delegating
    Account(std::string owner, long bal)              // parameterized
        : owner_(std::move(owner)), balance_(bal) {}  // initializer list
    Account(const Account& o)                         // copy
        : owner_(o.owner_ + "-copy"), balance_(o.balance_) {}
    void show() const { std::println("{}: {}", owner_, balance_); }
};

int main() {
    Account a;
    Account b("Rahim", 5000);
    Account c = b;              // copy constructor চলে, assignment নয়
    a.show();
    b.show();
    c.show();
}

আউটপুট: unknown: 0, Rahim: 5000, Rahim-copy: 5000. Account c = b; দেখতে assignment-এর মতো, কিন্তু এটি নতুন object তৈরি — তাই copy constructor চলে। “-copy” যোগ করা হয়েছে শুধু দেখানোর জন্য যে কোন constructor চলেছে; বাস্তবে copy constructor হুবহু কপিই করবে।

Member initializer list (: owner_(...), balance_(...)) member-কে সরাসরি শুরুর মান দেয়; constructor-এর শরীরের ভেতরে = দিলে member আগে ডিফল্টভাবে তৈরি হয়, পরে আবার assign হয়। চারটি ক্ষেত্রে list বাধ্যতামূলক: const member, reference member, যে member-এর default constructor নেই, আর যে base class-এর default constructor নেই।

সতর্কতা: member-গুলো তৈরি হয় class-এ ঘোষণার ক্রমে, list-এ লেখার ক্রমে নয়। এক member দিয়ে আরেকটির মান দিলে ক্রম মিলিয়ে লিখুন — GCC -Wreorder দিয়ে সতর্ক করে।

ঝালিয়ে নিন: পর্ব ২১ · constructor ও destructor

খ-০৪Copy আর move-এর পার্থক্য কী? Rule of Zero, Three ও Five ব্যাখ্যা করুন। (কঠিন)

Copy মানে উৎসের একটি স্বাধীন প্রতিলিপি বানানো — উৎস অপরিবর্তিত থাকে। Move মানে উৎসের রিসোর্স (যেমন heap buffer) নিজের কাছে সরিয়ে নেওয়া — উৎস থাকে বৈধ কিন্তু অনির্দিষ্ট অবস্থায় (moved-from state). এক লাখ উপাদানের vector কপি করতে এক লাখ উপাদান কপি করতে হয়; move করতে শুধু তিনটি pointer.

পাঁচটি special member function object-এর জীবনচক্র নিয়ন্ত্রণ করে: destructor, copy constructor, copy assignment, move constructor, move assignment.

নিয়মকী বলেকখন
Rule of Zeroপাঁচটির একটিও নিজে লিখবেন না; রিসোর্স রাখুন std::vector, std::string, std::unique_ptr-এর মতো সদস্যেপ্রায় সবসময় — আধুনিক C++-এর ডিফল্ট
Rule of Threedestructor, copy constructor, copy assignment — একটি নিজে লিখলে বাকি দুটিও লিখুনC++11-এর আগের কোড, বা raw রিসোর্স সামলানো class
Rule of FiveThree-এর সাথে move constructor ও move assignmentনিজে raw রিসোর্স সামলালে, C++11 থেকে

কেন একসাথে: নিজে destructor লিখেছেন মানে class কোনো রিসোর্সের মালিক। তখন compiler-এর বানানো copy শুধু pointer কপি করবে — দুটি object একই মেমরি delete করবে। আর একটি গুরুত্বপূর্ণ নিয়ম: destructor বা কোনো copy অপারেশন নিজে ঘোষণা করলে compiler আর move অপারেশন নিজে বানায় না — তখন “move” আসলে চুপচাপ copy হয়ে যায়।

উপসংহার: move constructor ও move assignment-এ noexcept দিন — নইলে std::vector বড় হওয়ার সময় নিরাপত্তার জন্য move-এর বদলে copy করে। নিজের রিসোর্স সামলানো class খুব কম লিখুন; লিখলে পাঁচটিই ভেবে লিখুন, বা যেগুলো লাগবে না সেগুলো = delete করুন।

ঝালিয়ে নিন: পর্ব ২২ · copy, move আর Rule of 0/3/5, পর্ব ৩৬ · move semantics

খ-০৫Shallow copy আর deep copy কী? কোন ক্ষেত্রে shallow copy বিপজ্জনক? (মাঝারি)

Shallow copy শুধু member-গুলোর মান কপি করে — pointer member থাকলে ঠিকানাটি কপি হয়, ঠিকানার ডেটা নয়। Deep copy pointer যে ডেটা দেখায়, সেটির নতুন একটি কপি বানায়, যাতে দুটি object সম্পূর্ণ স্বাধীন হয়।

class Buffer {
    int* data_;
    std::size_t n_;
public:
    explicit Buffer(std::size_t n) : data_(new int[n]{}), n_(n) {}
    ~Buffer() { delete[] data_; }
    // compiler-এর বানানো copy = shallow: দুজনেরই data_ একই ঠিকানা
    Buffer(const Buffer& o) : data_(new int[o.n_]), n_(o.n_) {   // deep copy
        std::copy(o.data_, o.data_ + n_, data_);
    }
    Buffer& operator=(const Buffer&) = delete;   // এখানে সহজ রাখতে বন্ধ
};

চিত্র: shallow copy-র পর a.data_ → [0 0 0] ← b.data_; deep copy-র পর a.data_ → [0 0 0] আর b.data_ → [0 0 0] (আলাদা ব্লক)।

বিপদ: raw pointer-এর মালিক class-এ shallow copy হলে (১) একজন বদলালে অন্যজনও বদলায়, (২) দুজনের destructor একই মেমরি দুবার delete[] করে — double delete, undefined behavior, (৩) একজন ধ্বংস হলে অন্যজন dangling pointer নিয়ে বাঁচে।

উপসংহার: সেরা সমাধান সমস্যাটাই এড়ানো — int*-এর বদলে std::vector<int> রাখুন। vector নিজেই deep copy করে, তখন Rule of Zero মেনে কিছুই লিখতে হয় না। একই ডেটা ইচ্ছে করে ভাগ করতে চাইলে std::shared_ptr.

ঝালিয়ে নিন: পর্ব ২২ · copy, move আর Rule of 0/3/5

খ-০৬Static data member আর static member function কী? উদাহরণসহ লিখুন। (সহজ)

Static member class-এর অংশ, কিন্তু কোনো object-এর ভেতরে থাকে না — পুরো প্রোগ্রামে এর একটিই কপি, সব object ভাগ করে ব্যবহার করে।

class Ticket {
    inline static int issued_ = 0;     // C++17: class-এর ভেতরেই সংজ্ঞা
    int number_;
public:
    Ticket() : number_(++issued_) {}
    static int issued() { return issued_; }   // this নেই
};
Ticket t1, t2, t3;
int n = Ticket::issued();   // 3 — object ছাড়াই ডাকা যায়

নিয়ম: static member function-এ this থাকে না, তাই সে সরাসরি non-static member ছুঁতে পারে না; এটি virtual বা const হতে পারে না। C++17-এর আগে static data member-এর সংজ্ঞা আলাদা .cpp ফাইলে দিতে হতো (int Ticket::issued_ = 0;); এখন inline static লিখলেই চলে। sizeof(Ticket)-এ static member-এর জায়গা ধরা হয় না।

উপসংহার: ব্যবহার — object গোনা, সব object-এর ভাগের constant, factory function (Account::fromCsv(...)). সতর্কতা: একাধিক thread থেকে বদলানো static ডেটায় mutex বা std::atomic লাগে।

ঝালিয়ে নিন: পর্ব ২০ · class ও object

খ-০৭Operator overloading কী? এর নিয়ম ও সীমাবদ্ধতা উদাহরণসহ লিখুন। (মাঝারি)

Operator overloading মানে নিজের টাইপের জন্য +, ==, << ইত্যাদি অপারেটরের অর্থ সংজ্ঞায়িত করা, যাতে নিজের টাইপও built-in টাইপের মতো স্বাভাবিকভাবে লেখা যায়। এটি আসলে operator+ নামের একটি ফাংশন।

#include <iostream>

struct Money {
    long taka = 0;
    Money& operator+=(const Money& o) { taka += o.taka; return *this; }
    friend Money operator+(Money a, const Money& b) { a += b; return a; }
    friend bool operator==(const Money&, const Money&) = default;  // C++20
    friend std::ostream& operator<<(std::ostream& os, const Money& m) {
        return os << m.taka << " taka";
    }
};

int main() {
    Money a{500}, b{250};
    Money c = a + b;
    c += Money{50};
    std::cout << c << '\n';
    std::cout << std::boolalpha << (a + b == Money{750}) << '\n';
}

আউটপুট: 800 taka আর true. প্রচলিত কৌশল: += member হিসেবে লিখে +-কে তার ওপর বানানো — একই যুক্তি দুবার লিখতে হয় না। <<-এর বাঁ দিকের operand হলো std::ostream, তাই এটি Money-র member হতে পারে না — non-member (এখানে friend).

নিয়ম ও সীমাবদ্ধতা:

  • নতুন অপারেটর বানানো যায় না (যেমন **); precedence, associativity আর operand-এর সংখ্যা বদলানো যায় না (ব্যতিক্রম: () যেকোনো সংখ্যক argument নেয়, আর C++23 থেকে []-ও)।
  • অন্তত একটি operand নিজের টাইপ হতে হবে — int + int-এর অর্থ বদলানো যায় না।
  • overload করা যায় না: ::, ., .*, ?: (আর sizeof, typeid-এর মতো keyword-অপারেটর)।
  • =, [], (), -> অবশ্যই member function হতে হবে।
  • &&, || overload করলে short-circuit আচরণ হারায় — তাই প্রায় কখনো করা হয় না।

উপসংহার: অপারেটর এমন অর্থে দিন, যা পাঠক আশা করেন — + দিয়ে বিয়োগ নয়। C++20 থেকে operator== আর operator<=> = default করলে compiler সব তুলনা নিজেই বানায়।

ঝালিয়ে নিন: পর্ব ২৩ · operator overloading

খ-০৮Inheritance কী? Public, protected ও private inheritance-এ base-এর member-এর access কীভাবে বদলায়? (মাঝারি)

Inheritance হলো একটি বিদ্যমান class (base) থেকে নতুন class (derived) বানানো, যাতে derived base-এর ডেটা ও কাজ পায় এবং নিজের কিছু যোগ করে। public inheritance বোঝায় “is-a” সম্পর্ক — SavingsAccount একটি Account.

base-এ memberpublic inheritanceprotected inheritanceprivate inheritance
publicpublicprotectedprivate
protectedprotectedprotectedprivate
privatederived থেকে দেখা যায় নাদেখা যায় নাদেখা যায় না

private member derived object-এর ভেতরে থাকে, শুধু derived-এর কোড সরাসরি ছুঁতে পারে না। গঠনের দিক থেকে ধরন: single, multilevel (A → B → C), hierarchical (এক base, অনেক derived), multiple (একাধিক base). multiple inheritance-এ একই base দুই পথে এলে diamond problem — সমাধান virtual inheritance.

ক্রম: তৈরি হয় আগে base, তারপর derived-এর member, তারপর derived-এর constructor-এর শরীর; ধ্বংস হয় ঠিক উল্টো ক্রমে।

উপসংহার: প্রায় সবসময় public inheritance ব্যবহার হয়; private inheritance মানে আসলে “এর সাহায্যে বানানো” — সেখানে সাধারণত composition (member হিসেবে রাখা) পরিষ্কার। inheritance শুধু কোড পুনর্ব্যবহারের জন্য নয় — derived যেন সব জায়গায় base-এর জায়গা নিতে পারে (Liskov substitution).

ঝালিয়ে নিন: পর্ব ২৪ · inheritance

খ-০৯Virtual function, vtable আর virtual destructor ব্যাখ্যা করুন। Destructor virtual না হলে কী হয়? (কঠিন)

সংজ্ঞা, ব্যাখ্যা আর চিত্র অংশ ২-এর ডায়াগ্রামে ধাপে ধাপে দেখানো হয়েছে। এখানে একটি সম্পূর্ণ প্রোগ্রাম, যেখানে ভিন্ন টাইপের object একটি container-এ রেখে একই ডাকে ভিন্ন কাজ হয়:

#include <memory>
#include <print>
#include <vector>

struct Shape {
    virtual ~Shape() = default;                  // virtual destructor
    virtual double area() const = 0;             // pure virtual
    void info() const { std::println("area = {}", area()); }
};
struct Rect : Shape {
    double w, h;
    Rect(double a, double b) : w(a), h(b) {}
    double area() const override { return w * h; }
};
struct Square : Shape {
    double s;
    explicit Square(double x) : s(x) {}
    double area() const override { return s * s; }
    ~Square() override { std::println("~Square"); }
};

int main() {
    std::vector<std::unique_ptr<Shape>> shapes;
    shapes.push_back(std::make_unique<Rect>(2, 3));
    shapes.push_back(std::make_unique<Square>(4));
    for (const auto& s : shapes) s->info();     // একই ডাক, ভিন্ন area
}

আউটপুট: area = 6, area = 16, আর শেষে ~Square. info() নিজে virtual নয়, কিন্তু ভেতরের area() virtual — তাই প্রতিটি object-এর নিজের সংস্করণ চলে। vector ধ্বংস হলে প্রতিটি unique_ptr base-এর pointer দিয়ে delete করে; destructor virtual বলেই ~Square চলেছে।

Destructor virtual না হলে: base-এর pointer দিয়ে derived object delete করা undefined behavior. বাস্তবে সাধারণত শুধু base-এর destructor চলে — derived-এর রিসোর্স (string, vector, file) কখনো মুক্ত হয় না। নিয়ম: যে class-এ অন্তত একটি virtual ফাংশন আছে বা যাকে base হিসেবে polymorphic-ভাবে ব্যবহার করা হবে, তার destructor public virtual (অথবা protected non-virtual, যাতে base pointer দিয়ে delete-ই করা না যায়)।

উপসংহার: vtable প্রতি class-এ একটি, vptr প্রতি object-এ একটি — দুটিই প্রচলিত বাস্তবায়ন, standard-এর বাধ্যবাধকতা নয়। constructor virtual হতে পারে না; constructor-এর ভেতরে virtual ডাকলে derived-এর সংস্করণ চলে না।

ঝালিয়ে নিন: পর্ব ২৫ · polymorphism ও virtual ফাংশন

খ-১০Abstract class আর interface কী? C++-এ এদের পার্থক্য লিখুন। (মাঝারি)

Abstract class হলো এমন class, যাতে অন্তত একটি pure virtual function (virtual void pay() = 0;) আছে। এর object বানানো যায় না, কিন্তু এর pointer বা reference রাখা যায়। derived class সব pure virtual override না করলে সে-ও abstract থাকে।

C++-এ interface নামে কোনো keyword নেই (Java বা C#-এর মতো)। প্রচলিতভাবে interface বলতে বোঝায় এমন abstract class, যাতে শুধু pure virtual ফাংশন আর একটি virtual destructor আছে — কোনো ডেটা নেই, কোনো বাস্তবায়ন নেই।

বিষয়Abstract classInterface (প্রচলিত অর্থে)
Pure virtualঅন্তত একটিসব (destructor বাদে)
ডেটা memberথাকতে পারেথাকে না
তৈরি ফাংশনথাকতে পারে — সাধারণ সাহায্যকারী কাজথাকে না
উদ্দেশ্যআংশিক বাস্তবায়ন ভাগ করাশুধু চুক্তি — “কী করা যায়”
Multiple inheritanceডেটা থাকলে জটিল হতে পারেনিরাপদ — একাধিক interface একসাথে নেওয়া সহজ
struct Notifier {                               // interface
    virtual ~Notifier() = default;
    virtual void send(const std::string& msg) = 0;
};
struct SmsNotifier : Notifier {
    void send(const std::string& msg) override { /* SMS gateway */ }
};
// Notifier n;    // error: abstract class-এর object হয় না

উপসংহার: একটি সূক্ষ্ম তথ্য: pure virtual ফাংশনেরও সংজ্ঞা দেওয়া যায় — আর pure virtual destructor হলে সংজ্ঞা দিতেই হবে, কারণ derived-এর destructor শেষে base-এর destructor ডাকে। compile-time-এ “interface” বোঝাতে C++20 থেকে concept-ও ব্যবহার করা যায়, তখন কোনো virtual খরচ থাকে না।

ঝালিয়ে নিন: পর্ব ২৬ · abstract class ও interface

খ-১১Function overloading আর function overriding-এর পার্থক্য লিখুন। (সহজ)
বিষয়OverloadingOverriding
সংজ্ঞাএকই scope-এ একই নামের একাধিক ফাংশন, parameter আলাদাderived class base-এর virtual ফাংশনকে একই signature-এ নতুন করে লেখে
কোথায়একই class বা একই namespacebase আর derived — দুটি class লাগে
Signatureparameter-এর সংখ্যা বা টাইপ আলাদা হতেই হবে; শুধু return type আলাদা হলে চলে নাহুবহু এক (covariant return ব্যতিক্রম)
সিদ্ধান্তcompile-এর সময় — static polymorphismচলার সময় — dynamic polymorphism
Keywordলাগে নাbase-এ virtual, derived-এ override (ঐচ্ছিক, কিন্তু লেখা উচিত)

উদাহরণ: int area(int s); আর double area(double w, double h); — overloading. struct Bkash : Payment { long fee(long) const override; }; — overriding.

উপসংহার — একটি ফাঁদ: derived-এ base-এর ফাংশনের নামে কিন্তু ভিন্ন parameter-এ একটি ফাংশন লিখলে সেটি overload নয়, override-ও নয় — base-এর একই নামের সব ফাংশন লুকিয়ে যায় (name hiding). সমাধান: derived-এ using Base::area;. আর override লিখলে signature-এর ভুল compiler নিজেই ধরে।

ঝালিয়ে নিন: পর্ব ০৯ · ফাংশন ও overloading, পর্ব ২৫

খ-১২SOLID নীতিগুলো কী? প্রতিটির একটি করে উদাহরণ দিন। (মাঝারি)

SOLID হলো object-oriented ডিজাইনের পাঁচটি নীতির সংক্ষিপ্ত নাম; উদ্দেশ্য এমন কোড, যা বদলানো, পরীক্ষা করা আর বাড়ানো সহজ।

  • S — Single Responsibility: একটি class-এর বদলানোর কারণ একটিই। Invoice হিসাব করবে; PDF বানানো আর ইমেইল পাঠানো আলাদা class-এর কাজ।
  • O — Open/Closed: নতুন আচরণ যোগে খোলা, পুরোনো কোড বদলানোয় বন্ধ। নতুন পেমেন্ট পদ্ধতি (Nagad) যোগ করতে নতুন Payment-derived class লিখুন, পুরোনো switch বদলাতে হবে না।
  • L — Liskov Substitution: base-এর জায়গায় যেকোনো derived বসালে প্রোগ্রাম ঠিক থাকবে। ক্লাসিক উদাহরণ: Square-কে Rectangle থেকে derive করলে setWidth একা চালালে Square-এর নিয়ম ভাঙে।
  • I — Interface Segregation: বড় এক interface-এর বদলে ছোট ছোট interface. প্রিন্টার Printer নেবে, Scanner নয় — যা লাগে না, তা বাস্তবায়ন করতে বাধ্য করা উচিত নয়।
  • D — Dependency Inversion: উঁচু স্তরের কোড নির্ভর করবে abstraction-এর ওপর। OrderService নেবে Notifier&, সরাসরি SmsNotifier নয় — test-এ নকল notifier বসানো যায় (dependency injection).

উপসংহার: SOLID নিয়ম নয়, নির্দেশিকা। ছোট প্রোগ্রামে সব নীতি জোর করে প্রয়োগ করলে অকারণ জটিলতা আসে। C++-এ এগুলো শুধু virtual দিয়ে নয়, template আর concept দিয়েও (compile-time-এ) প্রয়োগ করা যায়।

ঝালিয়ে নিন: পর্ব ২৭ · ডিজাইন নীতি — composition ও SOLID

৬ · অংশ গ — template ও STL (মডিউল ৫)

রিভিশনের জন্য: পর্ব ২৮, পর্ব ২৯, পর্ব ৩০, পর্ব ৩১, পর্ব ৩২, পর্ব ৩৩, পর্ব ৩৪, পর্ব ৩৫.

এই অংশের প্রশ্নে complexity (Big-O) লিখলে উত্তর অনেক শক্ত হয়। “পার্থক্য লিখুন” প্রশ্নে অন্তত একটি সারি রাখুন “কখন কোনটি বেছে নেবেন”।

গ-০১Template কী? Function template, class template আর template specialization উদাহরণসহ লিখুন। (মাঝারি)

Template হলো টাইপকে parameter বানিয়ে লেখা কোডের নকশা; compiler প্রতিটি ব্যবহৃত টাইপের জন্য আসল কোড বানায় (instantiation). এতে একই যুক্তি int, double, std::string — সবার জন্য একবার লিখলেই হয়, আর টাইপ যাচাইও পুরোপুরি থাকে।

#include <print>
#include <string>

template <typename T>                       // function template
T biggest(T a, T b) { return (a < b) ? b : a; }

template <typename T>                       // class template
struct Box {
    T value;
    void show() const { std::println("Box holds {}", value); }
};

template <>                                 // full specialization
struct Box<bool> {
    bool value;
    void show() const { std::println("Box holds {}", value ? "yes" : "no"); }
};

int main() {
    std::println("{}", biggest(3, 7));
    std::println("{}", biggest(std::string("apple"), std::string("mango")));
    Box<int>{42}.show();
    Box<bool>{true}.show();
}

আউটপুট: 7, mango, Box holds 42, Box holds yes. biggest(3, 7)-এ compiler নিজেই T = int বের করে (template argument deduction). Box<bool>-এর জন্য আলাদা specialization লেখা হয়েছে, তাই সেখানে সাধারণ সংস্করণের বদলে বিশেষ সংস্করণ চলেছে।

Specialization: full specialization — একটি নির্দিষ্ট টাইপের জন্য সম্পূর্ণ আলাদা বাস্তবায়ন (template <> struct Box<bool>). Partial specialization — টাইপের একটি পরিবারের জন্য, যেমন সব pointer: template <typename T> struct Box<T*>; এটি শুধু class (ও variable) template-এ চলে, function template-এ নয় — সেখানে overloading ব্যবহার করুন। standard library-র উদাহরণ: std::vector<bool>.

উপসংহার: template-এর পূর্ণ সংজ্ঞা সাধারণত header-এ রাখতে হয়, কারণ instantiation-এর সময় compiler-কে পুরো কোড দেখতে হয়। অসুবিধা: লম্বা error message, compile সময় বাড়া, আর বেশি টাইপে বাড়তি binary (code bloat). C++20-এর concept টাইপের শর্ত স্পষ্ট করে error সহজ করে।

ঝালিয়ে নিন: পর্ব ২৮ · function template, পর্ব ২৯ · class template

গ-০২STL কী? এর মূল অংশগুলো কী কী, আর তারা কীভাবে একসাথে কাজ করে? (সহজ)

STL (Standard Template Library) হলো C++ standard library-র template-ভিত্তিক অংশ — তৈরি data structure আর algorithm. এর নকশা মূলত Alexander Stepanov-এর; ১৯৯৪ সালে এটি standard-এ গৃহীত হয়ে C++98-এর অংশ হয়।

  • Container: ডেটা রাখে — sequence (vector, deque, list, array), associative (map, set), unordered (unordered_map), আর adaptor (stack, queue, priority_queue).
  • Iterator: container-এর ভেতর দিয়ে হাঁটার সাধারণ উপায় — pointer-এর মতো *it, ++it.
  • Algorithm: sort, find, count_if, transform — iterator জোড়ার ওপর কাজ করে, container-এর ওপর সরাসরি নয়।
  • Function object ও lambda: algorithm-কে নিয়ম জানায় — কীভাবে তুলনা, কোনটি গুনবে।

মূল ভাবনা: iterator হলো সেতু। M টি container আর N টি algorithm থাকলে M × N টি সংস্করণ লিখতে হয় না — M + N টিই যথেষ্ট। std::sort(v.begin(), v.end()) vector, array, deque — যেকোনো random-access container-এ চলে।

উপসংহার: C++20 থেকে std::ranges::sort(v) লেখা যায় — পুরো container একবারে, আর concept দিয়ে ভুল টাইপ হলে পরিষ্কার error. নিজে loop লেখার আগে দেখুন STL-এ তৈরি algorithm আছে কি না।

ঝালিয়ে নিন: পর্ব ৩০, পর্ব ৩২, পর্ব ৩৩

গ-০৩vector, list আর deque-এর পার্থক্য লিখুন। কখন কোনটি বেছে নেবেন? (মাঝারি)
বিষয়vectorlistdeque
মেমরিএক টানা (contiguous)ছড়ানো node, প্রতিটিতে দুটি pointerকয়েকটি নির্দিষ্ট মাপের খণ্ড
v[i]O(1)নেই — হাঁটতে হয়, O(n)O(1) (vector-এর চেয়ে একটু ধীর)
শেষে যোগamortized O(1)O(1)O(1)
শুরুতে যোগO(n)O(1)O(1)
মাঝে যোগ/বাদO(n)O(1) — iterator জানা থাকলেO(n)
Cacheসবচেয়ে ভালোখারাপভালো
Iterator invalidationreallocation হলে সবশুধু মুছে ফেলা উপাদানেরদুই প্রান্তে যোগ করলে সব iterator, কিন্তু উপাদানের reference টিকে থাকে

উদাহরণ: ছাত্রদের নম্বরের তালিকা — vector; রিকশার সারির মতো দুই দিক থেকে ঢোকা-বের হওয়া — deque (std::queue-এর ডিফল্ট ভিত্তিও deque); মাঝখানে অনবরত যোগ-বাদ আর উপাদানের ঠিকানা স্থির থাকা দরকার — list.

উপসংহার: ডিফল্ট vector. বইয়ের হিসাবে list-এর মাঝে যোগ O(1) হলেও, সেই জায়গা খুঁজতেই O(n) হাঁটতে হয়, আর ছড়ানো node-এ cache miss বেশি — তাই বাস্তবে ছোট-মাঝারি আকারে vector প্রায়ই list-এর চেয়ে দ্রুত। সিদ্ধান্ত নিন মেপে।

ঝালিয়ে নিন: পর্ব ৩০ · sequence container, পর্ব ৪৯ · পারফরম্যান্স

গ-০৪map আর unordered_map-এর পার্থক্য লিখুন। (মাঝারি)

দুটিই key-value জোড়া রাখে, প্রতিটি key একবার। পার্থক্য ভেতরের গঠনে:

বিষয়std::mapstd::unordered_map
ভেতরের গঠনbalanced binary search tree (প্রচলিত বাস্তবায়নে red-black tree)hash table
খোঁজা/যোগ/বাদO(log n), নিশ্চিতগড়ে O(1), worst case O(n)
ক্রমkey অনুযায়ী সাজানোনির্দিষ্ট নয় — library ও ইনপুটের ওপর নির্ভর করে
key-এর শর্ত< দিয়ে তুলনা (strict weak ordering)std::hash আর ==
পরিসর খোঁজাআছে — lower_bound, upper_boundনেই
মেমরিপ্রতি node-এ তিনটি pointer + রঙbucket array + node; load factor বাড়লে rehash

উদাহরণ: রোল নম্বর অনুযায়ী সাজিয়ে ফল ছাপা — map; শুধু “এই ফোন নম্বরের মালিক কে” দ্রুত খোঁজা — unordered_map.

উপসংহার: দুটিতেই m[key] পড়তে গেলে key না থাকলে নতুন ডিফল্ট উপাদান ঢুকে যায় — শুধু খুঁজতে find বা C++20-এর contains ব্যবহার করুন। contest-এ বিশেষভাবে বানানো ইনপুট দিয়ে unordered_map-কে worst case-এ ঠেলে দেওয়া যায় (anti-hash test) — সেখানে custom hash বা map নিরাপদ।

ঝালিয়ে নিন: পর্ব ৩১ · map, set আর unordered_map

গ-০৫Iterator কী? Iterator invalidation কী, উদাহরণসহ ব্যাখ্যা করুন। (কঠিন)

Iterator হলো একটি object, যা container-এর একটি উপাদানকে নির্দেশ করে এবং পরের উপাদানে যেতে পারে — pointer-এর সাধারণীকৃত রূপ। begin() প্রথম উপাদান, end() শেষের পরের জায়গা (half-open range). ক্ষমতা অনুযায়ী ধরন: input, output, forward, bidirectional (list, map), random-access (vector, deque), আর C++20-এ contiguous (vector, array).

Iterator invalidation মানে container বদলানোর পর আগের iterator (বা reference, pointer) আর বৈধ না থাকা। এমন iterator ব্যবহার করা undefined behavior.

std::vector<int> v{1, 2, 3};
auto it = v.begin();
v.push_back(4);          // capacity ভরা থাকলে নতুন মেমরিতে সরে যায়
// std::println("{}", *it);   // UB: it পুরোনো মেমরি দেখাচ্ছে

for (auto i = v.begin(); i != v.end(); ) {   // লুপে মুছতে নিরাপদ পথ
    if (*i % 2 == 0) i = v.erase(i);   // erase নতুন বৈধ iterator ফেরত দেয়
    else ++i;
}
std::erase_if(v, [](int x) { return x > 2; });   // C++20: আরও সহজ

নিয়মের সারাংশ: vector — reallocation হলে সব invalid; না হলে যোগের জায়গা থেকে পরেরগুলো। reserve দিয়ে আগে জায়গা নিলে push_back-এ reallocation হয় না। list ও map — যোগ করলে কিছুই invalid হয় না, মুছলে শুধু মুছে ফেলা উপাদানের iterator. unordered_map — rehash হলে সব iterator invalid, কিন্তু উপাদানের reference টিকে থাকে।

উপসংহার: range-for লুপের ভেতরে একই vector-এ push_back বা erase করা একটি ক্লাসিক বাগ। AddressSanitizer আর libstdc++-এর debug mode (-D_GLIBCXX_DEBUG) এমন ভুল ধরতে সাহায্য করে।

ঝালিয়ে নিন: পর্ব ৩২ · iterator, পর্ব ১৩ · vector ও array

গ-০৬Lambda expression কী? Capture-এর ধরনগুলো উদাহরণসহ লিখুন। (মাঝারি)

Lambda হলো নামহীন ফাংশন, যা যেখানে দরকার সেখানেই লেখা যায় (C++11). গঠন: [capture](parameter) -> return_type { body }. compiler প্রতিটি lambda-র জন্য একটি নামহীন class বানায়, যার operator() আছে; lambda-টি সেই class-এর একটি object (closure).

#include <algorithm>
#include <print>
#include <vector>

int main() {
    std::vector<int> marks{72, 45, 88, 39, 91};
    int pass = 40;

    auto passed = std::count_if(marks.begin(), marks.end(),
                                [pass](int m) { return m >= pass; });  // by value

    int total = 0;
    std::ranges::for_each(marks, [&total](int m) { total += m; });     // by reference

    auto counter = [n = 0]() mutable { return ++n; };                  // init-capture
    counter();
    counter();

    std::println("passed={} total={} counter={}", passed, total, counter());
}

আউটপুট: passed=4 total=335 counter=3. [pass] মানের একটি কপি রাখে; [&total] আসল ভ্যারিয়েবলকে reference দিয়ে ধরে, তাই lambda-র ভেতরের যোগ বাইরে দেখা যায়। [n = 0] lambda-র নিজের একটি ভ্যারিয়েবল বানায়; তা বদলাতে mutable লাগে, কারণ ডিফল্টে closure-এর operator() const.

  • [] — কিছুই ধরে না; [x] — কপি; [&x] — reference; [=] / [&] — ব্যবহৃত সব কিছু কপি / reference-এ (default capture).
  • [this] — object-কে pointer দিয়ে; [*this] (C++17) — পুরো object-এর কপি। C++20 থেকে [=] দিয়ে this আপনাআপনি ধরা deprecated.
  • [p = std::move(ptr)] — init-capture (C++14), move-only জিনিস ধরতে।

উপসংহার: সবচেয়ে বড় ঝুঁকি — [&] দিয়ে local ভ্যারিয়েবল ধরে lambda-টি পরে চালানো (thread, callback, ফেরত দেওয়া), যখন ভ্যারিয়েবলটি আর নেই: dangling reference. দীর্ঘজীবী lambda-তে কপি বা init-capture পছন্দ করুন, আর কী ধরছেন তা স্পষ্ট লিখুন।

ঝালিয়ে নিন: পর্ব ৩৪ · lambda ও function object

৭ · অংশ ঘ — আধুনিক C++, সিস্টেম ও প্রজেক্ট (মডিউল ৬–৭)

রিভিশনের জন্য: পর্ব ৩৬, পর্ব ৩৭, পর্ব ৩৮, পর্ব ৩৯, পর্ব ৪০, পর্ব ৪৩, পর্ব ৪৫, পর্ব ৪৬, পর্ব ৪৮.

এই অংশের প্রশ্ন আধুনিক ইন্টারভিউতে খুব জনপ্রিয়, কারণ এগুলো দেখায় আপনি শুধু পুরোনো C++ নয়, C++11-এর পরের ভাষাও জানেন। উত্তরে কোন সংস্করণ থেকে বৈশিষ্ট্যটি এসেছে, তা লিখুন।

ঘ-০১Move semantics আর rvalue reference ব্যাখ্যা করুন। std::move আসলে কী করে? (কঠিন)

Move semantics (C++11) হলো এমন object থেকে রিসোর্স কপি না করে সরিয়ে নেওয়া, যার আর দরকার নেই — যেমন অস্থায়ী object বা যাকে আর ব্যবহার করা হবে না। এর ভিত্তি rvalue reference T&&, যা শুধু rvalue-র সাথে বাঁধে। ফলে compiler আলাদা করতে পারে: “এটি কপি করতে হবে” (lvalue) আর “এটি থেকে চুরি করা যায়” (rvalue).

#include <cstddef>
#include <print>
#include <utility>
#include <vector>

struct Buffer {
    std::vector<int> data;
    explicit Buffer(std::size_t n) : data(n) {}
    Buffer(const Buffer& o) : data(o.data) { std::println("copy"); }
    Buffer(Buffer&& o) noexcept : data(std::move(o.data)) { std::println("move"); }
};

int main() {
    Buffer a(1000);
    Buffer b = a;               // a একটি lvalue → copy
    Buffer c = std::move(a);    // xvalue → move
    Buffer d = Buffer(10);      // prvalue → C++17-এ নিশ্চিত elision, কিছুই ছাপে না
    std::println("b={} c={} d={}", b.data.size(), c.data.size(), d.data.size());
}

আউটপুট: copy, move, b=1000 c=1000 d=10. লক্ষ করুন Buffer d = Buffer(10);-এ copy বা move কোনোটিই চলেনি — C++17 থেকে prvalue দিয়ে শুরুর মান দিলে object সরাসরি গন্তব্যেই তৈরি হয় (guaranteed copy elision). move-এর পর a-কে ব্যবহার করা যায়, কিন্তু তার vector-এ কী আছে তা standard নির্দিষ্ট করে না।

std::move কী করে: নিজে কিছুই সরায় না। এটি শুধু একটি cast — static_cast<T&&> — যা একটি lvalue-কে xvalue বানায়, যাতে move constructor বা move assignment বেছে নেওয়া হয়। আসল সরানোর কাজ করে move constructor. তাই const object-এ std::move দিলে সাধারণত copy-ই হয়, কারণ const T&& move constructor-এ বাঁধে না।

উপসংহার: move-এর পর object “বৈধ কিন্তু অনির্দিষ্ট” — নতুন মান বসানো বা ধ্বংস করা নিরাপদ, পড়ে কিছু আশা করা নয়। return local;-এ std::move লিখবেন না — এতে NRVO বন্ধ হয়ে যেতে পারে (pessimizing move). template-এ T&& আসলে forwarding reference, সেখানে std::forward.

ঝালিয়ে নিন: পর্ব ৩৬ · move semantics, পর্ব ২২

ঘ-০২C++-এ exception handling কীভাবে কাজ করে? Exception safety-র তিন স্তরের guarantee ব্যাখ্যা করুন। (মাঝারি)

Exception হলো ভুল জানানোর এমন উপায়, যেখানে ভুলের জায়গা থেকে throw করা হয় আর যে জায়গা ভুল সামলাতে জানে সেখানে catch করা হয়। মাঝের ফাংশনগুলোকে প্রতিটি ধাপে return code যাচাই করতে হয় না।

double withdraw(double balance, double amount) {
    if (amount > balance) throw std::runtime_error("insufficient balance");
    return balance - amount;
}
try {
    withdraw(500, 1000);
} catch (const std::exception& e) {          // const reference দিয়ে ধরুন
    std::println("error: {}", e.what());
}

কীভাবে কাজ করে: throw-এর পর প্রোগ্রাম ফাংশনের পর ফাংশন পেছনে যায়, প্রতিটি scope-এর local object-এর destructor চালায় (stack unwinding), যতক্ষণ না মেলে এমন catch পায়। কোনো catch না পেলে std::terminate. তাই RAII আর exception একসাথে কাজ করে — ফাইল, lock, মেমরি আপনাআপনি মুক্ত হয়। by value না ধরে const& দিয়ে ধরা হয়, যাতে কপি না হয় আর derived exception slicing-এ না কাটে।

Guaranteeপ্রতিশ্রুতিউদাহরণ
Nothrowকখনো exception ছোড়ে না (noexcept)destructor, swap, move constructor (প্রায়ই)
Strongব্যর্থ হলে অবস্থা ঠিক আগের মতো — হয় পুরো কাজ, নয় কিছুই নাvector::push_back (শর্তসাপেক্ষে), copy-and-swap
Basicকোনো leak নেই, object বৈধ — কিন্তু মান বদলে থাকতে পারেবেশিরভাগ standard library অপারেশন

উপসংহার: exception রাখুন সত্যিকারের ব্যতিক্রমী অবস্থার জন্য; প্রত্যাশিত ব্যর্থতায় (যেমন ব্যবহারকারীর ভুল ইনপুট) C++23-এর std::expected বা std::optional প্রায়ই পরিষ্কার। destructor থেকে exception বের হতে দেবেন না।

ঝালিয়ে নিন: পর্ব ৩৭ · exception আর std::expected, পর্ব ৩৮

ঘ-০৩constexpr কী? const, constexpr আর consteval-এর পার্থক্য লিখুন। (মাঝারি)

constexpr (C++11, C++14-এ অনেক শিথিল) মানে “compile-এর সময় হিসাব করা যায়”। constexpr ভ্যারিয়েবলের মান compile-এর সময়ই ঠিক হতে হবে; constexpr ফাংশন compile-এর সময়ের মান দরকার এমন জায়গায় (যেমন static_assert বা constexpr ভ্যারিয়েবল) compile-এর সময় হিসাব হয়, আর সাধারণ argument পেলে চলার সময় চলে।

#include <array>
#include <print>

constexpr long long fact(int n) { return n <= 1 ? 1 : n * fact(n - 1); }

constexpr std::array<int, 6> make_squares() {
    std::array<int, 6> a{};
    for (int i = 0; i < 6; ++i) a[i] = i * i;
    return a;
}

int main() {
    static_assert(fact(5) == 120);          // compile-এর সময় যাচাই
    constexpr auto sq = make_squares();     // টেবিল compile-এর সময় তৈরি
    static_assert(sq[5] == 25);
    int n = 10;                             // চলার সময়ের মান
    std::println("fact(20)={} sq[4]={} fact(n)={}", fact(20), sq[4], fact(n));
}

আউটপুট: fact(20)=2432902008176640000 sq[4]=16 fact(n)=3628800. static_assert দুটি compile-এর সময়ই পাস করেছে — ভুল হলে প্রোগ্রাম compile-ই হতো না। একই fact ফাংশন fact(n)-এ চলার সময়ের মান নিয়েও কাজ করেছে।

Keywordঅর্থ
constশুরুর পর বদলাবে না; মান চলার সময়ও আসতে পারে
constexpr ভ্যারিয়েবলমান compile-এর সময় জানা, আর const
constexpr ফাংশনcompile-এর সময় চলতে পারে, চলার সময়ও চলে
consteval (C++20)compile-এর সময় চলতেই হবে (immediate function)
constinit (C++20)static ভ্যারিয়েবলের শুরুর মান compile-এর সময় — কিন্তু পরে বদলানো যায়

উপসংহার: লাভ — চলার সময়ের হিসাব কমে, lookup table আগে থেকে তৈরি, আর compile-এর সময়ের হিসাবে ভাষার স্তরের undefined behavior (যেমন signed overflow) থাকলে compiler সেটিকে error হিসেবে ধরে। খরচ — compile সময় বাড়ে।

ঝালিয়ে নিন: পর্ব ৩৯ · constexpr

ঘ-০৪Concepts কী? Template-এ কেন দরকার? উদাহরণ দিন। (মাঝারি)

Concept (C++20) হলো template parameter-এর ওপর একটি নামযুক্ত শর্ত — compile-এর সময় যাচাই হওয়া একটি bool predicate. এটি বলে দেয় একটি টাইপের কী কী করতে পারা চাই।

#include <concepts>

template <std::integral T>                  // শুধু পূর্ণসংখ্যা টাইপ
T gcd(T a, T b) { return b == 0 ? a : gcd(b, a % b); }

template <typename T>
concept Printable = requires(const T& x) { x.print(); };   // নিজের concept

void show(const Printable auto& x) { x.print(); }

// gcd(4.5, 1.5);   // error: double, std::integral শর্ত পূরণ করে না

কেন দরকার: (১) পরিষ্কার error: concept ছাড়া ভুল টাইপ দিলে template-এর গভীর থেকে শত লাইনের error আসে; concept-এ এক লাইনে বলে “শর্ত পূরণ হয়নি”। (২) নকশার দলিল: ঘোষণা দেখেই বোঝা যায় কী টাইপ চলবে। (৩) overload বাছাই: শর্ত অনুযায়ী আলাদা সংস্করণ — বেশি নির্দিষ্ট শর্তওয়ালাটি প্রাধান্য পায় (subsumption). এর আগে এই কাজ std::enable_if আর SFINAE দিয়ে কঠিনভাবে করতে হতো।

উপসংহার: concept শুধু syntax যাচাই করে — x.print() লেখা যায় কি না; ফাংশনটি ঠিক কাজ করে কি না, সেটি যাচাই করে না। virtual interface-এর মতো চুক্তি, কিন্তু compile-time-এ এবং কোনো রানটাইম খরচ ছাড়া।

ঝালিয়ে নিন: পর্ব ৪০ · concepts

ঘ-০৫Undefined behavior কী? C++-এর পাঁচটি সাধারণ উদাহরণ দিন। এটি কেন বিপজ্জনক? (কঠিন)

Undefined behavior (UB) হলো এমন কাজ, যার ফল সম্পর্কে C++ standard কোনো শর্ত দেয় না। প্রোগ্রাম ঠিক চলতে পারে, ভুল ফল দিতে পারে, crash করতে পারে, বা optimization চালু করলে আচরণ বদলে যেতে পারে। এটি implementation-defined (compiler নিজে ঠিক করে আর নথিতে লেখে, যেমন sizeof(int)) আর unspecified (কয়েকটি সম্ভাবনার যেকোনোটি, যেমন function argument-এর মূল্যায়নের ক্রম) থেকে আলাদা।

  1. Signed integer overflow: int x = INT_MAX; x + 1; (unsigned-এ overflow সংজ্ঞায়িত — মান ঘুরে যায়)।
  2. সীমার বাইরে প্রবেশ: v[10] যখন v.size() == 3 (v.at(10) হলে exception).
  3. Dangling: শেষ হয়ে যাওয়া object-এর reference, pointer বা string_view ব্যবহার; delete-এর পর ব্যবহার (use-after-free).
  4. শুরুর মান ছাড়া পড়া: int n; std::println("{}", n);
  5. Data race: দুই thread একই ভ্যারিয়েবলে synchronization ছাড়া, অন্তত একটি লিখছে।
  6. অন্যান্য: nullptr dereference, virtual destructor ছাড়া base pointer দিয়ে derived delete, new[]-কে delete দিয়ে মুক্ত করা, string literal বদলানো।

কেন বিপজ্জনক: compiler ধরে নেয় সঠিক প্রোগ্রামে UB নেই, আর সেই অনুমানে কোড বদলায়। যেমন if (x + 1 < x) দিয়ে overflow যাচাই — compiler ধরে নেয় signed overflow হয় না, তাই পুরো শর্তটাই মুছে দিতে পারে। ফলে “আমার মেশিনে চলে” প্রমাণ নয়।

উপসংহার: ধরার উপায় — -Wall -Wextra, -fsanitize=address,undefined, -fsanitize=thread, static analysis (clang-tidy), আর constexpr-এ পরীক্ষা। ভাইভায় “এর আউটপুট কী?” প্রশ্নের উত্তর যদি UB হয়, “undefined behavior” বলাটাই সঠিক উত্তর।

ঝালিয়ে নিন: পর্ব ৪৩ · Undefined Behavior ও নিরাপদ C++, পর্ব ১৮ · lifetime

ঘ-০৬Multithreading-এ race condition, mutex আর deadlock ব্যাখ্যা করুন। Deadlock কীভাবে এড়াবেন? (কঠিন)

Thread হলো একই process-এর ভেতরে স্বাধীনভাবে চলা একটি কাজের ধারা; সব thread একই মেমরি ভাগ করে। C++11 থেকে standard-এ std::thread, C++20-এ std::jthread.

  • Race condition: ফল নির্ভর করে কোন thread আগে চলল তার ওপর। ++counter আসলে তিন ধাপ — পড়া, যোগ, লেখা; দুই thread মাঝপথে ঢুকে পড়লে একটি যোগ হারায়। synchronization ছাড়া একই ভ্যারিয়েবলে এমন লেখা data race — undefined behavior.
  • Mutex: একসাথে শুধু একটি thread একটি critical section-এ ঢুকতে পারে। হাতে lock()/unlock() না করে RAII — std::lock_guard বা std::scoped_lock.
  • Deadlock: দুই বা ততোধিক thread একে অপরের ধরে রাখা lock-এর জন্য চিরকাল অপেক্ষা করে। T1 ধরেছে A, চায় B; T2 ধরেছে B, চায় A.
#include <mutex>
#include <print>
#include <thread>
#include <vector>

int main() {
    long counter = 0;
    std::mutex m;
    auto work = [&] {
        for (int i = 0; i < 100000; ++i) {
            std::lock_guard<std::mutex> lock(m);   // এই লাইন মুছলে data race (UB)
            ++counter;
        }
    };
    std::vector<std::jthread> pool;
    for (int t = 0; t < 4; ++t) pool.emplace_back(work);
    pool.clear();                                 // jthread destructor-এ join করে
    std::println("counter = {}", counter);
}

আউটপুট: counter = 400000 — প্রতিবার। চারটি thread একই counter বাড়াচ্ছে, কিন্তু mutex একসাথে একজনকেই ঢুকতে দেয়। pool.clear() সব jthread ধ্বংস করে, আর jthread-এর destructor নিজেই join করে — তাই ছাপার আগে সব কাজ শেষ। সাধারণ std::thread join না করে ধ্বংস হলে std::terminate. এমন সরল counter-এ std::atomic<long> আরও হালকা সমাধান।

Deadlock-এর চার শর্ত (সবগুলো একসাথে থাকলে তবেই হয়): mutual exclusion, hold and wait, no preemption, circular wait. এড়ানোর উপায়: (১) সব জায়গায় একই ক্রমে lock নেওয়া (lock ordering); (২) একাধিক mutex একসাথে std::scoped_lock lk(a, b); — এটি deadlock এড়ানোর কৌশল নিজেই প্রয়োগ করে; (৩) lock ধরে রেখে অজানা ফাংশন বা callback না ডাকা; (৪) lock-এর ভেতরে কাজ যত সম্ভব ছোট রাখা।

উপসংহার: মুদ্রণ করে বা debugger দিয়ে race ধরা কঠিন, কারণ সময় বদলালে বাগ লুকিয়ে যায় — -fsanitize=thread (ThreadSanitizer) ব্যবহার করুন। সবচেয়ে ভালো সমাধান প্রায়ই ভাগ করা ডেটা কমানো।

ঝালিয়ে নিন: পর্ব ৪৫ · মাল্টিথ্রেডিং, পর্ব ৪৬ · async, future আর atomics

৮ · অংশ ঙ — ভাইভা কুইকফায়ার (৭৭টি প্রশ্ন)

ভাইভায় প্রশ্ন আসে দ্রুত, উত্তরও হতে হয় এক–দুই বাক্যে। জোরে জোরে উত্তর বলুন, তারপর মেলান — প্রতিটিতে ২০ সেকেন্ডের বেশি নয়। “ফলো-আপ” লেখা প্রশ্নগুলো আগের প্রশ্নের উত্তর থেকে জন্মানো; এগুলো পরপর পড়ুন, যেন একজন পরীক্ষক আপনাকে জেরা করছেন।

ভিত্তি, ভাষা আর মেমরি (পর্ব ০১–১৯)

রিভিশনের জন্য: পর্ব ০১, পর্ব ০৩, পর্ব ০৫, পর্ব ০৮, পর্ব ১০, পর্ব ১৩, পর্ব ১৬, পর্ব ১৭.

ভ-০১C++ কে বানিয়েছেন? শুরুতে এর নাম কী ছিল? (সহজ)

Bjarne Stroustrup, Bell Labs-এ, ১৯৭৯ সালে কাজ শুরু করেন — নাম ছিল “C with Classes”. ১৯৮৩ সালে নাম হয় C++; ++ মানে “C-এর এক ধাপ পরের”। পর্ব ০১

ভ-০২C++ কি C-এর superset? (মাঝারি)

প্রায়, পুরোপুরি নয়। void* থেকে স্বয়ংক্রিয় রূপান্তর C++-এ নেই (তাই int* p = malloc(8); error), আর new, class-এর মতো শব্দ C++-এ keyword. পর্ব ০১

ভ-০৩Compile আর link-এর পার্থক্য কী? (সহজ)

Compile প্রতিটি .cpp ফাইলকে আলাদাভাবে object file বানায়; link সব object file আর library জুড়ে একটি executable বানায়। “undefined reference” হলো linker error — ঘোষণা আছে, সংজ্ঞা পাওয়া যায়নি। পর্ব ০৩

ভ-০৪std::endl আর '\n'-এর পার্থক্য? (সহজ)

দুটিই নতুন লাইন দেয়, কিন্তু std::endl সাথে stream flush-ও করে। লুপে বারবার flush ধীর, তাই সাধারণত '\n'. পর্ব ০৭

ভ-০৫auto কী করে? const int& r = x; auto a = r; — a-র টাইপ কী? (মাঝারি)

initializer থেকে টাইপ বের করে (type deduction). শীর্ষ স্তরের const আর reference বাদ পড়ে, তাই a হলো int — একটি কপি। reference চাইলে auto& বা const auto&. পর্ব ০৫

ভ-০৬int x{3.5}; লিখলে কী হবে? (সহজ)

Compile error — brace initialization-এ narrowing conversion নিষিদ্ধ। int x = 3.5; চলে, মান হয় 3 — এই নীরব ক্ষতি ঠেকাতেই {} পছন্দ করা হয়। পর্ব ০৫

ভ-০৭int কত বাইট? (সহজ)

Standard শুধু বলে অন্তত 16 bit; সাধারণ 64-bit Linux ও Windows-এ ৪ বাইট। নির্দিষ্ট মাপ লাগলে std::int32_t, std::int64_t. ভাইভায় অনুমানটি বলুন। পর্ব ০৫

ভ-০৮7 / 2 আর 7 % -3-এর মান কত? (মাঝারি)

3 আর 1. দুটিই int, তাই integer division — ভাগফল শূন্যের দিকে কাটা হয় (C++11 থেকে নিশ্চিত)। 7 / -3 = -2, তাই ভাগশেষ 7 − 6 = 1; ভাগশেষের চিহ্ন বাঁ দিকের সংখ্যার মতো। পর্ব ০৬

ভ-০৯switch-এ break না দিলে কী হয়? (সহজ)

Fall-through — পরের case-এর কোডও চলতে থাকে। ইচ্ছে করে করলে C++17-এর [[fallthrough]]; লিখুন — compiler-এর সতর্কতা থামে, পাঠকও বোঝেন। পর্ব ০৮

ভ-১০Range-for-এ auto, auto& আর const auto& — কখন কোনটি? (মাঝারি)

auto — প্রতিটি উপাদানের কপি (ছোট টাইপে ঠিক আছে); auto& — উপাদান বদলাতে; const auto& — বড় object শুধু পড়তে, কপি ছাড়া। পর্ব ০৮

ভ-১১দুটি ফাংশনের শুধু return type আলাদা হলে কি overload হয়? (সহজ)

না — compile error. Overload বাছাই হয় শুধু argument দেখে; ডাকার জায়গায় return type দেখে বোঝার উপায় নেই। parameter-এর সংখ্যা বা টাইপ আলাদা হতে হবে। পর্ব ০৯

ভ-১২ফাংশন থেকে local ভ্যারিয়েবলের reference ফেরত দিলে কী হয়? (মাঝারি)

ফাংশন শেষ হলেই ভ্যারিয়েবলটির জীবন শেষ, তাই reference-টি dangling — ব্যবহার করা undefined behavior. GCC প্রায়ই সতর্ক করে (-Wreturn-local-addr); আর ফেরত টাইপ int&-এর মতো non-const reference হলে C++23-এ return x; সরাসরি compile error. মান ফেরত দিন; বাড়তি কপির ভয় নেই, RVO আর move আছে। পর্ব ১৮

ভ-১৩Reference কি পরে অন্য ভ্যারিয়েবলকে দেখাতে পারে? (সহজ)

না। int& r = x; r = y; মানে r-কে y-তে সরানো নয়, x-এ y-এর মান কপি করা। reference শুরুর সময়েই চিরকালের জন্য বাঁধা। পর্ব ১০

ভ-১৪ফলো-আপ: তাহলে null reference বানানো যায়? (মাঝারি)

বৈধ উপায়ে না। int& r = *p; যখন p null — এখানেই null dereference, undefined behavior. তাই “কিছু নাও থাকতে পারে” বোঝাতে pointer বা std::optional. পর্ব ১০

ভ-১৫Include guard আর #pragma once-এর পার্থক্য? (সহজ)

দুটিই একই header দুবার ঢোকা ঠেকায়। Include guard (#ifndef … #define … #endif) standard; #pragma once standard নয়, কিন্তু GCC, Clang, MSVC সবাই সমর্থন করে আর লেখা সহজ। পর্ব ১১

ভ-১৬enum class সাধারণ enum-এর চেয়ে ভালো কেন? (সহজ)

নাম নিজের scope-এ থাকে (Color::Red), আপনাআপনি int-এ রূপান্তর হয় না, আর underlying type ঠিক করে দেওয়া যায়। ভুল তুলনা compile-এর সময়ই ধরা পড়ে। পর্ব ১২

ভ-১৭Structured binding কী? (সহজ)

C++17-এর বৈশিষ্ট্য — একটি pair, tuple বা struct-এর অংশগুলো একবারে আলাদা নামে নেওয়া: for (const auto& [name, marks] : result). map-এর লুপে সবচেয়ে কাজে লাগে। পর্ব ১২

ভ-১৮vector-এর size() আর capacity()-এর পার্থক্য? (সহজ)

size — এখন কয়টি উপাদান আছে; capacity — নতুন মেমরি না নিয়ে কয়টি ধরবে। আগে জানা থাকলে reserve(n) দিয়ে বারবার reallocation এড়ানো যায়। পর্ব ১৩

ভ-১৯v[i] আর v.at(i)-এর পার্থক্য? (সহজ)

at সীমা যাচাই করে, বাইরে গেলে std::out_of_range ছোড়ে। [] যাচাই করে না — সীমার বাইরে গেলে undefined behavior, কিন্তু দ্রুত। পর্ব ১৩

ভ-২০std::string_view-এর সবচেয়ে বড় ঝুঁকি কী? (মাঝারি)

এটি লেখার মালিক নয়, শুধু দেখে। অস্থায়ী string থেকে বানিয়ে রেখে দিলে — যেমন std::string_view sv = getName(); — string ধ্বংস হলেই sv dangling. পর্ব ১৪

ভ-২১nullptr কেন NULL বা 0-এর চেয়ে ভালো? (সহজ)

nullptr-এর নিজস্ব টাইপ std::nullptr_t, যা শুধু pointer-এ রূপান্তর হয়। f(int) আর f(char*) থাকলে f(nullptr) নিশ্চিতভাবে pointer সংস্করণ ডাকে; f(0) ডাকে int সংস্করণ। পর্ব ১৫

ভ-২২new/delete আর malloc/free-এর পার্থক্য? (মাঝারি)

new মেমরি নিয়ে constructor চালায় আর সঠিক টাইপের pointer দেয়; ব্যর্থ হলে std::bad_alloc. malloc শুধু কাঁচা বাইট দেয়, ব্যর্থ হলে NULL. delete destructor চালায়, free চালায় না। একটি দিয়ে নিয়ে অন্যটি দিয়ে ছাড়া undefined behavior. পর্ব ১৬

ভ-২৩ফলো-আপ: new int[10]-কে delete দিয়ে মুক্ত করলে? (মাঝারি)

Undefined behavior — new[]-এর জোড়া delete[]. আধুনিক সমাধান: হাতে কোনোটিই নয়, std::vector<int> বা std::make_unique<int[]>(10). পর্ব ১৬

ভ-২৪unique_ptr কপি করা যায়? না গেলে মালিকানা কীভাবে দেবেন? (মাঝারি)

না — এটি move-only; copy constructor = delete. মালিকানা দিতে std::move(p); ফাংশন মালিকানা নিলে parameter std::unique_ptr<T> by value. শুধু ব্যবহার করলে T& বা T*. পর্ব ১৭

অবজেক্ট-ওরিয়েন্টেড ডিজাইন (পর্ব ২০–২৭)

রিভিশনের জন্য: পর্ব ২০, পর্ব ২১, পর্ব ২২, পর্ব ২৩, পর্ব ২৪, পর্ব ২৫, পর্ব ২৬, পর্ব ২৭.

ভ-২৫Class আর object-এর পার্থক্য এক লাইনে? (সহজ)

Class হলো নকশা — কী ডেটা, কী কাজ; object হলো সেই নকশায় তৈরি বাস্তব নমুনা, যার নিজের মেমরি আছে। বাড়ির নকশা একটি, বাড়ি অনেক। পর্ব ২০

ভ-২৬this কী? (সহজ)

Non-static member function-এর ভেতরে, যে object-এর ওপর ফাংশনটি ডাকা হয়েছে তার pointer (this pointer). static member function-এ this নেই। পর্ব ২০

ভ-২৭const member function-এর ভেতরে একটি member বদলাতে হলে? (মাঝারি)

সেই member-কে mutable ঘোষণা করুন — যেমন cache, গণনার counter বা mutex, যা object-এর বাইরের দৃশ্যমান অবস্থার অংশ নয়। অন্য কিছু হলে ফাংশনটি আসলে const হওয়ার কথাই নয়। পর্ব ২০

ভ-২৮Compiler কখন নিজে default constructor বানায়? (সহজ)

যখন আপনি কোনো constructor-ই লেখেননি। একটি parameterized constructor লিখলেই আর বানায় না — তখন দরকার হলে Account() = default; লিখুন। পর্ব ২১

ভ-২৯explicit keyword কেন? (মাঝারি)

এক argument-এর constructor দিয়ে অনাকাঙ্ক্ষিত স্বয়ংক্রিয় রূপান্তর ঠেকাতে। explicit Meters(double) থাকলে Meters m = 5.0; বা f(5.0) চলবে না, লিখতে হবে Meters{5.0}. পর্ব ২১

ভ-৩০Member-গুলো কোন ক্রমে তৈরি হয়? (মাঝারি)

আগে base class, তারপর member-গুলো class-এ ঘোষণার ক্রমে — initializer list-এ যে ক্রমেই লিখুন। ধ্বংস হয় উল্টো ক্রমে। পর্ব ২১

ভ-৩১Copy constructor-এর parameter reference কেন, by value নয় কেন? (মাঝারি)

by value হলে parameter বানাতেই একটি কপি লাগত — অর্থাৎ আবার copy constructor ডাকা, তার জন্য আবার… অসীম। তাই ভাষার নিয়মেই by-value copy constructor নিষিদ্ধ; লেখা হয় const T&. পর্ব ২২

ভ-৩২Account c = b; আর c = b; — কোনটিতে কী চলে? (সহজ)

প্রথমটি নতুন object তৈরি — copy constructor. দ্বিতীয়টি আগে থেকে থাকা object-এ নতুন মান — copy assignment (operator=). পর্ব ২২

ভ-৩৩Self-assignment (a = a;) কেন সমস্যা হতে পারে? (কঠিন)

হাতে লেখা operator= আগে নিজের পুরোনো রিসোর্স delete করে তারপর উৎস থেকে কপি করলে, উৎস আর গন্তব্য একই বলে কপির ডেটা আগেই মুছে গেছে। সমাধান: if (this == &o) যাচাই, বা copy-and-swap. পর্ব ২২

ভ-৩৪= delete কী কাজে লাগে? (সহজ)

একটি ফাংশন ইচ্ছে করে নিষিদ্ধ করা (deleted function) — যেমন copy বন্ধ করে class-কে move-only বানানো, বা void f(double) = delete; দিয়ে অনাকাঙ্ক্ষিত রূপান্তরের ডাক আটকানো। ব্যবহার করলে compile error. পর্ব ২২

ভ-৩৫কোন অপারেটরগুলো overload করা যায় না? (সহজ)

::, ., .* আর ?:; এছাড়া sizeof, typeid, alignof-এর মতো keyword-অপারেটর। পর্ব ২৩

ভ-৩৬Prefix আর postfix ++ overload কীভাবে আলাদা করা হয়? (মাঝারি)

Postfix-এ একটি নকল int parameter থাকে: T operator++(int), যা পুরোনো মানের কপি ফেরত দেয়। Prefix T& operator++() নিজেকেই ফেরত দেয় — কপি নেই বলে প্রায়ই দ্রুত। পর্ব ২৩

ভ-৩৭Object slicing কী? (মাঝারি)

Derived object-কে base টাইপের মান হিসেবে কপি করলে derived অংশ কেটে বাদ পড়ে — Payment p = bkash;. এরপর virtual ডাকেও base-এর সংস্করণ চলে। এড়াতে reference বা pointer ব্যবহার করুন। পর্ব ২৪

ভ-৩৮Diamond problem কী, সমাধান কী? (কঠিন)

B আর C দুটিই A থেকে derived, আর D দুটি থেকেই — তখন D-র ভেতরে A-র দুটি কপি থাকে, A-র member ধরলে ambiguity. সমাধান: B আর C-তে class B : virtual public A — তখন A-র একটিই কপি থাকে। পর্ব ২৪

ভ-৩৯Virtual function কী — এক বাক্যে? (সহজ)

Base-এর এমন ফাংশন, যা derived override করতে পারে, আর base-এর pointer বা reference দিয়ে ডাকলে object-এর আসল টাইপের সংস্করণ চলার সময় বাছাই হয়। পর্ব ২৫

ভ-৪০ফলো-আপ: vtable কোথায় থাকে? কয়টি থাকে? (কঠিন)

প্রচলিত বাস্তবায়নে প্রতিটি polymorphic class-এর একটি vtable, প্রোগ্রামের স্থির ডেটা অংশে — heap বা stack-এ নয়। প্রতিটি object-এ শুধু একটি vptr (64-bit-এ সাধারণত ৮ বাইট)। এগুলো standard-এর নিয়ম নয়, compiler-এর কৌশল। পর্ব ২৫

ভ-৪১ফলো-আপ: base-এর constructor-এর ভেতরে virtual ফাংশন ডাকলে কোনটি চলে? (কঠিন)

Base-এর সংস্করণ। তখনো derived অংশ তৈরি হয়নি, তাই object-এর dynamic type ধরা হয় যে class-এর constructor চলছে সেটি। destructor-এর ভেতরেও একই নিয়ম। ফাংশনটি pure virtual হলে undefined behavior. পর্ব ২৫

ভ-৪২ফলো-আপ: constructor কি virtual হতে পারে? (মাঝারি)

না। object তৈরির সময় টাইপ আপনি নিজেই লিখে দেন, আর vptr বসানোই constructor-এর কাজ — তার আগে বাছাইয়ের কিছু নেই। “virtual constructor”-এর দরকার মেটায় virtual clone() ফাংশন বা factory function. পর্ব ২৫

ভ-৪৩override আর final কী কাজে? (সহজ)

override — base-এ মেলানো virtual ফাংশন না থাকলে compile error, তাই নামের বা signature-এর ভুল ধরা পড়ে। final — এই ফাংশন আর override করা যাবে না, বা এই class থেকে আর derive করা যাবে না। পর্ব ২৫

ভ-৪৪Abstract class-এর object বানানো যায়? তার pointer? (সহজ)

Object বানানো যায় না — compile error. কিন্তু তার pointer বা reference রাখা যায়, আর সেটিই polymorphism-এর মূল ব্যবহার: std::unique_ptr<Shape> s = std::make_unique<Square>(4); পর্ব ২৬

ভ-৪৫Composition কেন প্রায়ই inheritance-এর চেয়ে ভালো? (মাঝারি)

Composition (“has-a”) দুটি class-কে কম শক্তভাবে বাঁধে — ভেতরের অংশ বদলানো বা চলার সময় অন্যটি বসানো সহজ, base-এর ভেতরের পরিবর্তনে derived ভাঙে না। inheritance রাখুন সত্যিকারের “is-a” সম্পর্কের জন্য, যেখানে derived সব জায়গায় base-এর জায়গা নিতে পারে। পর্ব ২৭

Template ও STL (পর্ব ২৮–৩৫)

রিভিশনের জন্য: পর্ব ২৮, পর্ব ২৯, পর্ব ৩০, পর্ব ৩১, পর্ব ৩২, পর্ব ৩৩, পর্ব ৩৪, পর্ব ৩৫.

ভ-৪৬Template-এর কোড সাধারণত header-এ রাখা হয় কেন? (মাঝারি)

Instantiation-এর সময় compiler-কে পুরো সংজ্ঞা দেখতে হয় — শুধু ঘোষণা দেখে Box<int>-এর কোড বানাতে পারে না। বিকল্প: .cpp-তে নির্দিষ্ট টাইপের জন্য explicit instantiation. পর্ব ২৮

ভ-৪৭Template আর macro-র পার্থক্য? (সহজ)

Macro preprocessor-এর লেখা বদল — টাইপ যাচাই নেই, scope মানে না, argument একাধিকবার মূল্যায়ন হতে পারে। Template compiler-এর অংশ — টাইপ যাচাই হয়, namespace মানে, debug করা যায়। পর্ব ২৮

ভ-৪৮CTAD কী? (মাঝারি)

Class template argument deduction (C++17) — constructor-এর argument দেখে class template-এর টাইপ বের করা। std::vector v{1, 2, 3}; লিখলেই std::vector<int>, std::pair p{1, 2.5}; হয় pair<int, double>. পর্ব ২৯

ভ-৪৯vector-এ push_back-এর complexity কত? (মাঝারি)

Amortized O(1). মাঝে মাঝে জায়গা ফুরালে সব উপাদান নতুন মেমরিতে সরাতে হয় (O(n)), কিন্তু capacity গুণিতক হারে বাড়ে (libstdc++-এ দ্বিগুণ), তাই গড়ে প্রতি push_back-এ ধ্রুবক খরচ। পর্ব ৩০

ভ-৫০emplace_back আর push_back-এর পার্থক্য? (মাঝারি)

push_back একটি তৈরি object কপি বা move করে ঢোকায়; emplace_back constructor-এর argument নিয়ে উপাদানটি vector-এর ভেতরেই তৈরি করে — v.emplace_back("Rahim", 5000);. আগে থেকে তৈরি object-এ দুটির পার্থক্য প্রায় নেই। পর্ব ৩০

ভ-৫১std::sort কি std::list-এ চলে? (মাঝারি)

না — std::sort-এর random-access iterator লাগে, list-এর iterator শুধু bidirectional. তাই list-এর নিজের member function আছে: lst.sort(); পর্ব ৩২

ভ-৫২if (m[key] == 0) দিয়ে map-এ খোঁজায় সমস্যা কী? (মাঝারি)

key না থাকলে operator[] নতুন একটি ডিফল্ট উপাদান ঢুকিয়ে দেয় — map অকারণে বড় হয়, আর const map-এ এটি compile-ই হয় না। খুঁজতে find বা C++20-এর contains. পর্ব ৩১

ভ-৫৩unordered_map-এর worst case কখন হয়? (মাঝারি)

যখন অনেক key একই bucket-এ পড়ে (hash collision) — তখন খোঁজা O(n). খারাপ hash function বা ইচ্ছে করে বানানো ইনপুটে এমন হয়। পর্ব ৩১

ভ-৫৪Erase-remove idiom কী? (মাঝারি)

std::remove_if আসলে কিছু মোছে না — রাখার উপাদানগুলো সামনে সরিয়ে নতুন “শেষ” ফেরত দেয়; তারপর v.erase(that, v.end()) বাকিটা মোছে। C++20 থেকে এক লাইনে: std::erase_if(v, pred); পর্ব ৩৩

ভ-৫৫Lambda ভেতরে আসলে কী? (কঠিন)

Compiler একটি নামহীন class বানায়, যার operator()-ই lambda-র শরীর, আর capture করা ভ্যারিয়েবলগুলো সেই class-এর member. lambda-টি সেই class-এর একটি object — একটি function object. পর্ব ৩৪

ভ-৫৬std::function কখন ব্যবহার করবেন? এর খরচ কী? (কঠিন)

যখন যেকোনো ধরনের callable (lambda, ফাংশন, function object) একই টাইপে রাখতে হয় — যেমন callback-এর তালিকা। খরচ: ভেতরে type erasure, বড় capture-এ heap allocation হতে পারে, আর ডাক সাধারণত inline হয় না। template বা auto parameter-এ এই খরচ নেই। পর্ব ৩৪

ভ-৫৭Ranges-এর view-কে “lazy” বলা হয় কেন? (মাঝারি)

v | std::views::filter(...) | std::views::transform(...) কোনো নতুন container বানায় না; উপাদান চাওয়ার মুহূর্তেই হিসাব হয় (lazy evaluation). view মূল ডেটার মালিক নয় — মূল container ধ্বংস হলে view dangling. পর্ব ৩৫

আধুনিক C++, সিস্টেম ও প্রজেক্ট (পর্ব ৩৬–৫১)

রিভিশনের জন্য: পর্ব ৩৬, পর্ব ৩৭, পর্ব ৩৮, পর্ব ৩৯, পর্ব ৪২, পর্ব ৪৩, পর্ব ৪৫, পর্ব ৪৬, পর্ব ৪৭, পর্ব ৪৮, পর্ব ৫০.

ভ-৫৮std::move কি কিছু সরায়? (মাঝারি)

না। std::move শুধু একটি cast — lvalue-কে rvalue reference (xvalue) বানায়, যাতে move constructor বা move assignment বাছাই হয়। আসল সরানোর কাজ করে সেই ফাংশনগুলো। পর্ব ৩৬

ভ-৫৯ফলো-আপ: move করার পর পুরোনো object ব্যবহার করা যায়? (কঠিন)

Standard library-র object থাকে “বৈধ কিন্তু অনির্দিষ্ট” অবস্থায় — ধ্বংস করা বা নতুন মান বসানো নিরাপদ, কিন্তু পড়ে কোনো নির্দিষ্ট মান আশা করা নয়। std::string বাস্তবে সাধারণত খালি হয়, তবু তার ওপর নির্ভর করবেন না। পর্ব ৩৬

ভ-৬০ফলো-আপ: move constructor-এ noexcept কেন দেওয়া উচিত? (কঠিন)

vector বড় হওয়ার সময় strong guarantee রাখতে চায়। move মাঝপথে exception ছুড়লে পুরোনো অবস্থা ফেরানো যায় না, তাই move constructor noexcept না হলে (আর copy সম্ভব হলে) vector move-এর বদলে copy করে — ধীর। পর্ব ৩৬

ভ-৬১Lvalue আর rvalue-এর পার্থক্য? (মাঝারি)

মোটা দাগে: lvalue-এর পরিচয় আছে — নাম, ঠিকানা নেওয়া যায় (x, v[0]); rvalue অস্থায়ী মান (x + 1, std::string("hi")). C++11 থেকে আরও সূক্ষ্ম ভাগ: lvalue, prvalue, xvalue. পর্ব ৩৬

ভ-৬২Destructor থেকে exception ছুড়লে কী হয়? (কঠিন)

C++11 থেকে destructor ডিফল্টভাবে noexcept, তাই exception বের হলেই std::terminate — প্রোগ্রাম বন্ধ। destructor-এর ভেতরে ভুল হলে সেখানেই সামলান বা লগ করুন। পর্ব ৩৭

ভ-৬৩catch (...) কী? কখন ব্যবহার করবেন? (মাঝারি)

যেকোনো exception ধরে (catch-all). সাধারণত সবার শেষে, প্রোগ্রামের সীমানায় — লগ করে throw; দিয়ে আবার ছুড়তে বা নিরাপদে বন্ধ করতে। এতে exception-এর ধরন জানা যায় না। পর্ব ৩৭

ভ-৬৪optional, variant আর expected — এক লাইনে করে? (মাঝারি)

optional<T> — একটি মান থাকতেও পারে, না-ও পারে (C++17); variant<A, B> — কয়েকটি টাইপের ঠিক একটি (C++17); expected<T, E> — হয় মান, নয় ভুলের কারণ (C++23). পর্ব ৩৮

ভ-৬৫static_assert কী? (সহজ)

Compile-এর সময় একটি শর্ত যাচাই — মিথ্যা হলে compile error. যেমন static_assert(sizeof(void*) == 8); নিশ্চিত করে কোডটি 64-bit-এর জন্য compile হচ্ছে। পর্ব ৩৯

ভ-৬৬C++20-এর চারটি বড় বৈশিষ্ট্যের নাম বলুন। (সহজ)

Concepts, ranges, coroutines আর modules — প্রচলিতভাবে “বড় চার”। সাথে তিন-মুখী তুলনা <=>, std::span, std::format, consteval. পর্ব ৪২

ভ-৬৭Signed আর unsigned overflow-এর পার্থক্য? (মাঝারি)

Signed overflow undefined behavior; unsigned overflow সংজ্ঞায়িত — মান 2ⁿ দিয়ে ভাগশেষে ঘুরে যায় (UINT_MAX + 1u == 0). পর্ব ৪৩

ভ-৬৮std::thread join না করে ধ্বংস হলে কী হয়? (মাঝারি)

joinable অবস্থায় destructor চললে std::terminate. হয় join(), নয় detach() করতে হয়। C++20-এর std::jthread destructor-এ নিজেই join করে, আর stop token দিয়ে থামার অনুরোধও পাঠাতে পারে। পর্ব ৪৫

ভ-৬৯ফলো-আপ: data race আর race condition কি একই? (কঠিন)

না। Data race নির্দিষ্ট — synchronization ছাড়া একই মেমরিতে দুই thread, অন্তত একটি লিখছে; C++-এ UB. Race condition বড় ধারণা — ফল thread-এর সময়ের ওপর নির্ভর করা; প্রতিটি অপারেশনে mutex থাকলেও যুক্তির ভুলে race condition থাকতে পারে (যেমন “যাচাই, তারপর কাজ” আলাদা দুই lock-এ)। পর্ব ৪৫

ভ-৭০ফলো-আপ: deadlock এড়ানোর দুটি উপায় এক লাইনে? (মাঝারি)

সব জায়গায় একই ক্রমে lock নিন, অথবা একাধিক mutex একসাথে std::scoped_lock দিয়ে নিন — এটি নিজেই deadlock এড়ানোর কৌশল প্রয়োগ করে। পর্ব ৪৫

ভ-৭১std::atomic আর mutex — কখন কোনটি? (মাঝারি)

std::atomic একটি ভ্যারিয়েবলের একক অপারেশন (যোগ, পড়া, compare-exchange) lock ছাড়াই নিরাপদ করে — সাধারণত একটি hardware instruction. কয়েকটি ভ্যারিয়েবল একসাথে সামঞ্জস্য রেখে বদলাতে হলে mutex. পর্ব ৪৬

ভ-৭২volatile দিয়ে কি thread-safe হয়? (কঠিন)

না। C++-এ volatile শুধু বলে প্রতিটি পড়া-লেখা সত্যিই মেমরিতে হবে (hardware register-এর জন্য); এটি atomicity বা thread-এর মধ্যে ক্রম দেয় না। thread-এর জন্য std::atomic বা mutex. পর্ব ৪৬

ভ-৭৩CMake কী? (সহজ)

একটি build system generator — CMakeLists.txt-এর বর্ণনা থেকে Makefile, Ninja বা Visual Studio project বানায়। একই প্রজেক্ট Linux, Windows, macOS-এ build করা যায়। পর্ব ৪৭

ভ-৭৪Debug build আর release build-এর পার্থক্য? (সহজ)

Debug: সাধারণত -O0 -g — optimization নেই, debugger-এর তথ্য আছে। Release: -O2 বা -O3, প্রায়ই -DNDEBUG — তাতে assert বন্ধ হয়ে যায়। কিছু UB-জনিত বাগ শুধু release build-এ দেখা দেয়। পর্ব ৪৭

ভ-৭৫প্রোগ্রাম segmentation fault দিচ্ছে — প্রথমে কী করবেন? (মাঝারি)

-g দিয়ে compile করে gdb-তে চালান; crash-এর পর bt (backtrace) দেখায় কোন লাইনে থেমেছে। সাথে -fsanitize=address দিয়ে চালালে ভুল পড়া-লেখার সঠিক জায়গা ও কারণ জানা যায়। পর্ব ৪৮

ভ-৭৬Unit test কী? C++-এ একটি জনপ্রিয় framework-এর নাম বলুন। (সহজ)

Unit test একটি ছোট অংশ — সাধারণত একটি ফাংশন বা class — জানা ইনপুটে প্রত্যাশিত ফল দেয় কি না স্বয়ংক্রিয়ভাবে যাচাই করে। জনপ্রিয় framework: GoogleTest, Catch2, doctest. edge case অবশ্যই রাখুন। পর্ব ৪৮

ভ-৭৭Contest-এ std::ios::sync_with_stdio(false) কেন লেখা হয়? (মাঝারি)

এটি C-এর stdio-র সাথে iostream-এর সমন্বয় বন্ধ করে, আর std::cin.tie(nullptr) প্রতিটি ইনপুটের আগে cout flush বন্ধ করে — বড় ইনপুটে cin/cout অনেক দ্রুত হয়। এরপর একই stream-এ printf/scanf আর cin/cout মেশাবেন না। পর্ব ৫০

৯ · AI-কে ভাইভা সঙ্গী বানান — আর তাকে যাচাই করুন

ভাইভা অনুশীলনের সবচেয়ে বড় সমস্যা হলো প্রশ্ন করার মানুষ না থাকা। AI এখানে কাজের সঙ্গী — ক্লান্ত হয় না, যেকোনো সময় প্রস্তুত, আর আপনার উত্তর থেকে follow-up প্রশ্ন বানাতে পারে। কিন্তু নিজে থেকে AI প্রায়ই খুব নরম পরীক্ষক — সব উত্তরেই “চমৎকার!” বলে। আর C++-এর সূক্ষ্ম বিষয়ে (move-এর পরের অবস্থা, iterator invalidation, UB) AI-ও আত্মবিশ্বাসের সাথে ভুল বলতে পারে। তাই তাকে স্পষ্ট নিয়ম দিন, আর প্রতিটি দাবি যাচাই করুন।

নিচের prompt-টি কপি করে যেকোনো AI চ্যাটে দিন। বিষয়ের জায়গায় যে মডিউল ঝালাতে চান সেটি লিখুন:

তুমি একজন কড়া C++ ভাইভা পরীক্ষক। বিষয়: [copy, move আর Rule of 0/3/5]. ধরে নাও standard C++23, 64-bit Linux, GCC. নিয়ম: ১. একবারে একটিই প্রশ্ন করো, তারপর আমার উত্তরের জন্য অপেক্ষা করো। ২. আমার উত্তর থেকেই আরও গভীর একটি follow-up প্রশ্ন বানাও — যেমন সত্যিকারের ভাইভা বোর্ড করে। ৩. প্রতিটি উত্তরকে ১০-এর মধ্যে নম্বর দাও, আর ঠিক কোন তথ্য ভুল বা বাদ পড়েছে বলো। প্রশংসা নয়, সঠিকতা। ৪. আমি ভুল বললে সাথে সাথে সঠিক উত্তর দিও না — আগে একটা ইঙ্গিত দাও, আরেকবার চেষ্টা করতে দাও। ৫. যেখানে উত্তর undefined behavior, unspecified বা compiler-নির্ভর, সেখানে আমি সেটা বলছি কি না দেখো। ৬. কোনো তথ্যে তুমি নিশ্চিত না হলে স্পষ্ট বলো; C++ standard-এর কোন সংস্করণ থেকে কোনো বৈশিষ্ট্য এসেছে, তা আন্দাজে বলো না। ৭. ১০টি প্রশ্নের পর আমার দুর্বল জায়গার তালিকা দাও, আর কোন ধারণা আবার পড়া উচিত বলো।

লিখিত উত্তরের জন্য খাতার উত্তর টাইপ করে দিন এবং বলুন: “এটি একটি বড় প্রশ্নের উত্তর। পরীক্ষক হিসেবে নম্বর দাও, আর সংজ্ঞা, ব্যাখ্যা, কোড, চিত্র, উপসংহার — কোন অংশ দুর্বল বলো; কিন্তু পুরো উত্তর নতুন করে লিখে দিও না।” শেষ শর্তটি জরুরি — নইলে আপনি শিখবেন না, শুধু আরেকটি উত্তর মুখস্থ করবেন।

C++ নিয়ে AI-এর উত্তরে যেসব ভুল প্রায়ই থাকে

AI যা বলে বা লেখেআসল সত্য
“C++ হলো C-এর superset”প্রায়, পুরোপুরি নয় (ক-০১)
“std::move object সরিয়ে দেয়”এটি শুধু cast; সরায় move constructor (ঘ-০১)
“vtable C++ standard-এর অংশ”প্রচলিত বাস্তবায়ন; standard শুধু আচরণ বলে (খ-০৯)
“unordered_map-এ খোঁজা সবসময় O(1)”গড়ে O(1), worst case O(n) (গ-০৪)
কোডে raw new/delete, header-এ using namespace std;smart pointer ও container; header-এ পুরো নাম (ক-০৪, ক-০৬)
UB-ওয়ালা কোডের “নির্দিষ্ট আউটপুট” বলাUB-এর কোনো সঠিক আউটপুট নেই (ঘ-০৫)
“struct-এ member function রাখা যায় না”C-তে ঠিক, C++-এ ভুল — পার্থক্য শুধু ডিফল্ট access (খ-০২)

AI-এর উত্তর যাচাইয়ের চেকলিস্ট

নিজেকে যাচাই করুন — উত্তর লেখা ও C++-এর মূল তথ্য

প্রথমে একটি ক্রম সাজানোর প্রশ্ন, তারপর উত্তর লেখার কৌশল আর C++-এর ক্লাসিক ভাইভা তথ্য নিয়ে MCQ. ভুল হলে কারণসহ ব্যাখ্যা পাবেন।

ক্রম“উদাহরণসহ ব্যাখ্যা করুন” প্রশ্নের একটি ভালো লিখিত উত্তরের অংশগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. 📌 এক–দুই বাক্যের নির্ভুল সংজ্ঞা
  2. 🧩 ব্যাখ্যা — কীভাবে কাজ করে, কেন এভাবে
  3. 💻 ছোট উদাহরণ কোড ও তার আউটপুট
  4. 🗺️ চিত্র বা তুলনার টেবিল
  5. ✅ উপসংহার — সতর্কতা, খরচ, কখন ব্যবহার

“virtual function কীভাবে কাজ করে? উদাহরণসহ লিখুন” — একটি বড় প্রশ্নে কোন উত্তরটি পূর্ণ নম্বরের সবচেয়ে কাছে?

  • “base-এর pointer দিয়ে derived-এর ফাংশন ডাকা” — এক লাইন
  • দুই পাতা জুড়ে Simula থেকে C++ পর্যন্ত OOP-এর ইতিহাস
  • সংজ্ঞা, static বনাম dynamic binding, override-সহ ছোট কোড ও আউটপুট, vptr-vtable চিত্র, আর virtual destructor-এর সতর্কতা
  • শুধু একটি ৪০ লাইনের প্রোগ্রাম, কোনো লেখা ছাড়া

ভাইভায় এমন প্রশ্ন এলো, যার উত্তর আপনি পুরোপুরি জানেন না। সবচেয়ে ভালো পদক্ষেপ কোনটি?

  • আত্মবিশ্বাস দেখাতে আন্দাজে একটি উত্তর জোর দিয়ে বলা
  • “পুরো নিশ্চিত নই, তবে এভাবে ভাবব…” বলে যা জানেন তা থেকে যুক্তি দিয়ে এগোনো
  • চুপ করে থাকা, যতক্ষণ না পরের প্রশ্ন আসে
  • প্রশ্ন এড়িয়ে নিজের জানা অন্য বিষয়ে কথা বলা শুরু করা

C++-এ নিচের কোন অপারেটরটি overload করা যায় না?

  • +
  • []
  • ()
  • ::

Base class-এর destructor virtual নয়। Base* p = new Derived; delete p; লিখলে C++ standard অনুযায়ী কী হয়?

  • Undefined behavior
  • Compile error
  • ঠিকঠাক — আগে Derived, তারপর Base-এর destructor চলে
  • নিশ্চিতভাবে প্রোগ্রাম crash করে

Rule of Five-এর পাঁচটি special member function-এর মধ্যে কোনটি পড়ে না?

  • Destructor
  • Move assignment operator
  • Default constructor
  • Copy constructor

std::vector<int>-এর একটি iterator রাখা আছে। এরপর push_back করায় reallocation হলো। সেই পুরোনো iterator ব্যবহার করলে কী হয়?

  • vector সেটিকে আপনাআপনি নতুন জায়গায় সরিয়ে দেয়
  • Iterator invalid হয়ে যায়; ব্যবহার করা undefined behavior
  • std::out_of_range exception
  • শুধু end() invalid হয়, বাকিগুলো ঠিক থাকে

std::move(x) আসলে কী করে?

  • x-এর ডেটা নতুন একটি মেমরিতে সরিয়ে দেয়
  • x-কে সাথে সাথে খালি করে দেয়
  • x-এর destructor ডাকে
  • x-কে rvalue reference-এ cast করে, যাতে move অপারেশন বাছাই হতে পারে

লিখিত পরীক্ষায় একটি ছোট প্রশ্ন: “RAII কী?” — কোন উত্তরটি সবচেয়ে উপযুক্ত?

  • রিসোর্সের জীবন object-এর জীবনে বাঁধা — constructor-এ নেওয়া, destructor-এ ছাড়া; exception হলেও মুক্ত হয়। উদাহরণ: std::lock_guard, std::vector.
  • তিন পাতা — RAII-এর ইতিহাস, চারটি পূর্ণ প্রোগ্রাম আর অন্য ভাষার সাথে তুলনা
  • “Resource Acquisition Is Initialization” — শুধু পূর্ণ নাম
  • “C++-এর garbage collector, যা অব্যবহৃত মেমরি নিজে মুছে দেয়”

শব্দকোষ

লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বে ব্যবহৃত সব শব্দ এখানে একসাথে:

মনে রাখুন

  1. বড় প্রশ্নে পাঁচ অংশ: সংজ্ঞা → ব্যাখ্যা → উদাহরণ কোড → চিত্র বা টেবিল → উপসংহার; ছোট প্রশ্নে সংজ্ঞা, এক লাইনের ব্যাখ্যা আর একটি উদাহরণ।
  2. “পার্থক্য লিখুন” প্রশ্নে টেবিল — একই মাপকাঠিতে সারি, complexity, আর “কখন কোনটি” সারি।
  3. খাতার কোডে আধুনিক C++: std::vector, smart pointer, override, const — আর নিচে আউটপুট।
  4. ভাইভায় আগে ছোট নির্ভুল উত্তর, তারপর উদাহরণ; অনুমান স্পষ্ট করুন, UB-কে UB বলুন, না জানলে সৎভাবে ভেবে বলুন।
  5. AI দিয়ে ভাইভা অনুশীলন করুন, কিন্তু তার প্রতিটি কোড চালিয়ে আর প্রতিটি দাবি মিলিয়ে নিন।

পরের পর্বে: লিখিত আর মৌখিক প্রশ্নের পর শেষ ধাপ — C++ কোডিং ইন্টারভিউ। অচেনা সমস্যা থেকে প্রশ্ন করে শর্ত বোঝা, brute force থেকে ভালো সমাধানে যাওয়া, আর ইন্টারভিউয়ারের সামনে জোরে ভেবে পরিষ্কার C++ লেখা।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

এই পর্বটি শেয়ার করুন:
এই পর্বে ভুল পেয়েছেন? জানান