C++ Fundamentals
اقرأ من اليمين لليسار: "p is const, a pointer, to int"
Variables & Data Types
الأساس — كل متغير له نوع محدد والـ compiler بيحدد الحجم في الميموري.
Basic Types
int a = 10; // 4 bytes double b = 3.14; // 8 bytes char c = 'A'; // 1 byte bool d = true; // 1 byte float e = 3.14f; // 4 bytes // const = قيمة ثابتة، لا تتغير const int MAX = 100; // يجب التهيئة فوراً // int * const p → pointer ثابت (لا يشير لمكان ثاني) // const int * p → قيمة ثابتة (لا يُعدّل المحتوى)
🔥 اتسألت عليه
int * const p = pointer ثابت لـ int (p نفسه لا يتغير، بس المحتوى يتغير)const int * p = pointer لـ int ثابت (p يتغير، المحتوى لا)اقرأ من اليمين لليسار: "p is const, a pointer, to int"
Logical Operators — Tricky Output
Example
int a = 5, b = 6; int c = 7 || (a > b); // || returns BOOLEAN: 7 is truthy → result = true → cast to int = 1 // NOT 7! The answer is 1 (None of the above) cout << c; // prints 1
Pointers & References
Pointers
int x = 10; int* ptr = &x; // ptr holds ADDRESS of x *ptr = 20; // dereference: changes x to 20 cout << *ptr; // 20 cout << ptr; // memory address (e.g. 0x7fff...) // Reference — alias, must be initialized, cannot be null int& ref = x; // ref IS x ref = 30; // changes x to 30 // Pointer Arithmetic int arr[] = {1,2,3}; int* p = arr; p++; // moves 4 bytes forward (sizeof int) cout << *p; // 2
الفرق المهم
Pointer: يمكن null، يمكن تغيير ما يشير إليه، يحتاج *Reference: لا يكون null أبداً، لا يمكن تغيير مرجعه، يعمل مثل اسم مستعار مباشر
Memory Management
new vs malloc
// new: يستدعي constructor + يخصص ذاكرة MyClass* obj = new MyClass(10); delete obj; // يستدعي destructor + يحرر ذاكرة // malloc: يخصص ذاكرة فقط — لا يستدعي constructor! MyClass* obj2 = (MyClass*) malloc(sizeof(MyClass)); // Constructor NOT called → prints nothing! free(obj2); // لا يستدعي destructor // Arrays int* arr = new int[5]; delete[] arr; // [] مهم مع arrays!
أنواع أخطاء الذاكرة
Memory Leak: تخصيص بدون تحرير (ملوش، بطيء مش crash فوري)Memory Corruption: تحرير مرتين (double free) = crash + UB
Dangling Pointer: استخدام pointer بعد delete = UB
Buffer Overflow: كتابة خارج حدود المصفوفة = UB
🔥 اتسألت عليه
Double free هو اللي بيسبب memory corruption — مش memory leak!
Scope, Static & Global Variables
Scope Resolution Operator ::
int x = 1; // global void fun() { int x = 2; // local to fun { int x = 3; // local to block cout << ::x; // :: → global x = 1 } } // OUTPUT: 1
Static Local Variable
void fun() { static Test t; // initialized ONCE on first call } main() { cout << "Before fun() called"; fun(); // Constructor Called here (first time only) cout << "After fun() called"; } // OUTPUT: Before fun() calledConstructor CalledAfter fun() called // Static local: NOT at program start, NOT multiple times!
Templates
Function & Class Templates
// Function Template template <typename T> T maxVal(T a, T b) { return a > b ? a : b; } maxVal(3, 5); // T = int maxVal(3.5, 2.1); // T = double // Template Specialization template <typename T> struct func { void x() { cout << "hi"; } void y() { cout << "hello"; } }; // Specialization for int only template <> void func<int>::x() { cout << "hello world"; } func<int> t; t.x(); // "hello world" (specialized) t.y(); // "hello" (generic)
if constexpr (C++17)
template <unsigned int n> unsigned int func() { if constexpr (n == 0) { return 1; } else { return func<5>() + func<20>(); } } // if constexpr → resolved at COMPILE TIME // func<5> and func<20> are computed once at compile time // Calling func() n times = O(n) — each call is O(1)
Lambda Expressions
Lambda Syntax & Captures
// [capture](params) → return_type { body } int x = 5; // Capture by value (copy) auto f1 = [x]() { cout << x; }; // Capture by reference auto f2 = [&x]() { x++; }; // modifies original x // Capture all by value auto f3 = [=]() { cout << x; }; // mutable: allows modifying captured-by-value copies auto f4 = [x]() mutable { x++; }; // Without mutable: operator() is const → cannot modify x copy
🔥 اتسألت عليه — Lambda Struct
[i]() mutable { ++i; } ↔ الـ struct المقابل له:struct Lambda { Lambda(int i) : i{i} {} void operator()() { ← بدون const (لأن mutable) ++i; } int i; ← بدون mutable في الـ member};
Exception Handling
try / catch / throw
try { try { throw 5; // L1 cout << "Inside inner try"; // L2 ← DEAD CODE } catch (int e) { cout << "Inner exception"; // L3 throw e; // L4 cout << "Inside inner catch"; // L5 ← DEAD CODE } } catch (int e) { cout << "Outer catch"; // L6 } // Dead code: L2 (after throw) and L5 (after rethrow) // Execution: L1(throw) → L3 → L4(rethrow) → L6
Inline Functions
بدل ما الـ compiler يعمل function call (push args, jump, return)، بيحط الـ body مكان الـ call مباشرة.
🔥 متى تستخدم inline؟
✅ Functions صغيرة وبسيطة — لتجنب overhead الـ function call❌ Functions كبيرة — هتسبب code bloat → cache misses → أبطأ!
❌ Functions فيها loops كتير أو recursion
constexpr & if constexpr
constexpr
constexpr int square(int n) { return n * n; } constexpr int result = square(5); // computed at COMPILE TIME // if constexpr: branch selection at compile time template<typename T> void print(T val) { if constexpr (is_integral_v) cout << "int: " << val; else cout << "other: " << val; }
Unions
Union — كل الـ members بيشاركوا نفس الذاكرة
union A { int x; public: A(int xx = 0) : x(xx) {} // Unions CAN have constructors! int get() { return x; } // Unions CAN have methods! }; A a(10); cout << a.get(); // 10 — no error! // Size of union = size of LARGEST member // Only ONE member can be used at a time
OOP
Classes & Objects
Class Basics
class Animal { private: int age; // only accessible inside class protected: string name; // accessible in derived classes public: Animal(int a, string n) : age(a), name(n) {} virtual void speak() { cout << "..."; } virtual ~Animal() {} // Always virtual destructor in base! };
struct vs class
الفرق الوحيد: struct default access = public، class default = private
Constructors
Types of Constructors
class Test { public: int x; // 1. Default Constructor Test() : x(0) {} // 2. Parameterized Constructor Test(int val) : x(val) { cout << "Called"; } // 3. Copy Constructor Test(const Test& other) : x(other.x + 1) {} }; // Conversion Constructor (implicit conversion) Test t(20); // "Called" — parameterized t = 30; // creates Test(30) temp → "Called" again! // Total output: "CalledCalled" // explicit keyword prevents implicit conversion: explicit Test(int val) : x(val) {} // Now: t = 30; → COMPILE ERROR
🔥 Private Constructor
Yes! يمكن أن يكون الـ constructor private — Singleton Pattern.بيمنع إنشاء objects من خارج الـ class.
🔥 Auto-generated by Compiler
إذا لم تكتبهم، الـ compiler بيولد تلقائياً:1. Default Constructor (لو مفيش user-defined constructor)
2. Copy Constructor
3. Copy Assignment Operator
4. Destructor
5. Move Constructor + Move Assignment (C++11)
Destructors & Destruction Order
Destruction Order
// Order of destruction when object goes out of scope: // 1→ Body of destructor runs // 2→ Destructors of non-static members (reverse declaration order) // 3→ Destructors of non-virtual base classes // 4→ Destructors of virtual base classes (always last) // Answer: 2 → 4 → 1 → 3 // Explicit destructor call — DANGEROUS: Dummy d(3); d.~Dummy(); // destructor runs cout << d.getX(); // UNDEFINED BEHAVIOR (object lifetime ended) // At end of scope: destructor runs AGAIN → double destructor
Return value vs Destructor
int i; class A { public: ~A() { i = 10; } // sets i=10 on destruction }; int foo() { i = 3; A ob; return i; // return value 3 is captured FIRST // THEN ob is destroyed → i becomes 10 } // But return value is already 3! cout << foo(); // prints 3
Inheritance
Constructor/Destructor Order
class Derived : public Base1, public Base2 {}; // Construction: left to right in declaration // Base1() → Base2() → Derived() // Destruction: reverse order // ~Derived() → ~Base2() → ~Base1() // Answer for output: 3 lines (Base1, Base2, Derived)
Name Hiding (Function Hiding)
class Base { public: int fun() { cout << "Base::fun()"; } int fun(int i) { cout << "Base::fun(int)"; } }; class Derived : public Base { public: int fun() { cout << "Derived::fun()"; } // HIDES all Base::fun! }; Derived d; d.fun(5); // COMPILER ERROR — fun(int) is hidden! // Fix: add "using Base::fun;" inside Derived
Diamond Problem & sizeof
class base { int arr[10]; }; // 40 bytes class b1: public base {}; // has its own copy: 40 bytes class b2: public base {}; // has its own copy: 40 bytes class derived: public b1, public b2 {}; cout << sizeof(derived); // 80 (TWO copies of base!) // Fix: virtual inheritance class b1: virtual public base {}; class b2: virtual public base {}; // Now derived has ONE copy of base = 40 bytes
Virtual Functions & Polymorphism
Virtual Dispatch — vtable
class Base { public: virtual void show() { cout << "Base"; } // virtual! void print() { cout << "Base"; } // NOT virtual }; class Derived : public Base { public: void show() { cout << "Derived"; } void print() { cout << "Derived"; } }; Base* bptr = new Derived(); bptr->show(); // "Derived" ← virtual: runtime dispatch via vtable bptr->print(); // "Base" ← non-virtual: compile-time, uses pointer type Base& bref = *bptr; bref.show(); // "Derived" ← virtual works with references too!
vtable — كيف يعمل
كل class عنده virtual functions → الـ compiler يضيف vptr (pointer للـ vtable).sizeof class بدون virtual = صغير. sizeof class مع virtual = بيزيد بحجم vptr (~8 bytes على 64-bit).
لذلك
sizeof(A) > sizeof(B) لو A عنده virtual و B مش عنده.
Private Virtual (Q8 scenario)
class Base { virtual void show() { cout << "from Base"; } // private! public: void print() { show(); } // calls show() via vtable }; class A : public Base { public: void show() { cout << "from A"; } }; Base* p2 = new A(); p2->print(); // calls print(), which calls show() via vtable → "from A"
Abstract Classes & Pure Virtual
Pure Virtual = Abstract Class
class Base { public: virtual void show() = 0; // pure virtual → Base is abstract }; Base b; // COMPILE ERROR — cannot instantiate abstract class Base* bp; // OK — pointer is fine, no instantiation // Derived must implement ALL pure virtuals, or it's also abstract: class Derived : public Base {}; // didn't implement show() Derived q; // COMPILE ERROR — Derived is also abstract! // Fix: class Derived : public Base { public: void show() { cout << "Derived"; } // now concrete! };
Operator Overloading
Prefix vs Postfix ++
class Test { public: int x; void operator++() { x++; } // prefix ++obj void operator++(int) { x++; } // postfix obj++ (dummy int param) }; // If only prefix defined and you use postfix → COMPILE ERROR // Operators that CANNOT be overloaded: // :: (scope), . (member), .* (member ptr), sizeof, typeid, ?: // Everything else CAN be overloaded ([], ->, *, +, -, etc.)
Static Members
Static Data & Methods
class Test { static int x; // shared across ALL instances public: Test() { x++; } // increments on each object creation static int getX() { return x; } }; int Test::x = 0; // must define outside class! cout << Test::getX(); // 0 Test t[5]; // 5 objects → constructor called 5 times cout << Test::getX(); // 5 // Static methods: NO 'this' pointer // Can ONLY access static members // Can be overloaded (common misconception that they can't) // Static data can be accessed by non-static methods too
Copy Constructor vs Assignment Operator
When each is called
class SomeClass { public: int x; SomeClass(int x): x(x) {} // Copy Constructor SomeClass(const SomeClass& a) { x = a.x; x++; } // +1 // Assignment Operator void operator=(const SomeClass& a) { x = a.x; x--; } // -1 }; SomeClass a(4); SomeClass b = a; // INITIALIZATION → Copy Constructor called! x = 4+1 = 5 cout << b.x; // 5 SomeClass c(0); c = a; // ASSIGNMENT → Assignment operator called! x = 4-1 = 3 cout << c.x; // 3
Shallow Copy Trap
class String { char* str; public: String(const char* s) { str = new char[strlen(s)+1]; strcpy(str, s); } void change(int i, char c) { str[i] = c; } char* get() { return str; } }; String s1("siemensTest"); String s2 = s1; // shallow copy! s1.str and s2.str → SAME memory s1.change(0, 'S'); cout << s1.get(); // "SiemensTest" cout << s2.get(); // "SiemensTest" ← changed too! (shared buffer)
Multiple Inheritance
Ambiguity
class P { public: void print() { cout << "Inside P"; } }; class Q { public: void print() { cout << "Inside Q"; } }; class R : public P, public Q {}; R obj; obj.print(); // COMPILER ERROR: ambiguous call! obj.P::print(); // OK: explicitly specify // Fix: define print() in R class R : public P, public Q { public: void print() { P::print(); } };
OOP Relationships
| Relationship | Strength | Example | Lifetime |
|---|---|---|---|
| Composition | Strongest | Car → Engine | Child dies with parent |
| Aggregation | Medium | Library → Books | Child lives independently |
| Association | Weakest | Teacher → Student | Just "uses" relationship |
🔥 Order strongest → weakest
Composition → Aggregation → Association
DSA
Big O Notation
بتقيس كيف يتصرف الـ algorithm عند زيادة الـ input (n). بنحسب الـ worst case.
O(1) — Constant
arr[0]
hashmap.find(k)
O(log n) — Logarithmic
Binary Search
BST operations
O(n) — Linear
Linear Search
Tree traversal
O(n log n)
Merge Sort
Quick Sort (avg)
O(n²) — Quadratic
Bubble Sort
Nested loops
O(2ⁿ) — Exponential
Naive recursion
Power set
Loop Complexity Analysis
// O(n log n) example from assessment: for (i = n/2; i <= n; i++) { // O(n/2) = O(n) for (j = 2; j <= n; j = j * 2) { // O(log n) — doubles each time k = k + n/2; } } // Total: O(n) × O(log n) = O(n log n) // How to identify inner loop: // j *= 2 → log n (doubles) // j += 1 → n (linear) // j *= j → log log n
Arrays & Vectors
Array vs Vector
// C-style array: fixed size, stack memory int arr[5] = {1, 2, 3, 4, 5}; // Vector: dynamic size, heap memory vector<int> v = {1, 2, 3}; v.push_back(4); // O(1) amortized v.pop_back(); // O(1) v.insert(v.begin(), 0); // O(n) — shifts elements v.erase(v.begin()); // O(n) — shifts elements v[2]; // O(1) random access // Complexity: // Access: O(1) // Search: O(n) // Insert/Delete at end: O(1) // Insert/Delete at middle: O(n)
Linked Lists
Singly Linked List
struct Node { int data; Node* next; Node(int d) : data(d), next(nullptr) {} }; // Insert at head: O(1) void insertHead(Node*& head, int val) { Node* newNode = new Node(val); newNode->next = head; head = newNode; } // Traversal: O(n) Node* curr = head; while (curr) { cout << curr->data; curr = curr->next; }
| Operation | Array | Linked List |
|---|---|---|
| Access by index | O(1) | O(n) |
| Insert at head | O(n) | O(1) |
| Insert at tail | O(1)* | O(n) or O(1) with tail ptr |
| Delete | O(n) | O(n) search + O(1) delete |
| Memory | Contiguous | Scattered (pointers overhead) |
Stack & Queue
Stack (LIFO) & Queue (FIFO)
// Stack — Last In, First Out stack<int> s; s.push(1); s.push(2); s.push(3); s.top(); // 3 (peek) s.pop(); // removes 3 // Use cases: function call stack, undo/redo, expression parsing // Queue — First In, First Out queue<int> q; q.push(1); q.push(2); q.push(3); q.front(); // 1 q.pop(); // removes 1 // Use cases: BFS, task scheduling, print queue // Both: push/pop/peek = O(1)
Binary Trees & Traversals
Tree Node & Traversals
struct TreeNode { int val; TreeNode* left; TreeNode* right; }; // Inorder: Left → Root → Right (BST: sorted order) void inorder(TreeNode* root) { if (!root) return; inorder(root->left); cout << root->val; inorder(root->right); } // Preorder: Root → Left → Right (copy tree) // Postorder: Left → Right → Root (delete tree, LAST = ROOT) // KEY: In Postorder → LAST element = ROOT! // Use this to reconstruct tree from traversals
🔥 اتسألت عليه — Tree Height from Traversals
Postorder's last element = Root.Find Root in Inorder → left part = left subtree, right part = right subtree.
Recurse to rebuild the tree, then find max depth.
Height = max edges from root to any leaf.
Binary Representation with Recursion (fun(n))
void fun(int n) { if (n > 1) fun(n >> 1); // divide by 2 (go deeper toward MSB) cout << (n & 1); // print last bit on the way back } // fun(5): binary 5 = 101 // Recursion: fun(5) → fun(2) → fun(1) → prints 1 // Back: fun(2) prints 0, fun(5) prints 1 // Output: 101 ← normal binary representation (MSB first)
Sorting Algorithms
| Algorithm | Best | Average | Worst | Space | Stable? |
|---|---|---|---|---|---|
| Bubble Sort | O(n) | O(n²) | O(n²) | O(1) | ✅ |
| Selection Sort | O(n²) | O(n²) | O(n²) | O(1) | ❌ |
| Insertion Sort | O(n) | O(n²) | O(n²) | O(1) | ✅ |
| Merge Sort | O(n log n) | O(n log n) | O(n log n) | O(n) | ✅ |
| Quick Sort | O(n log n) | O(n log n) | O(n²) | O(log n) | ❌ |
| Heap Sort | O(n log n) | O(n log n) | O(n log n) | O(1) | ❌ |
Bubble Sort (simplest)
void bubbleSort(int arr[], int n) { for (int i = 0; i < n-1; i++) { for (int j = 0; j < n-i-1; j++) { if (arr[j] > arr[j+1]) swap(arr[j], arr[j+1]); } } } // O(n²) — bad for large data, simple to understand
Merge Sort (O(n log n), stable)
void merge(int arr[], int l, int m, int r) { vector<int> left(arr+l, arr+m+1); vector<int> right(arr+m+1, arr+r+1); int i=0, j=0, k=l; while (iwhile (i while (j void mergeSort(int arr[], int l, int r) { if (l >= r) return; int m = l + (r-l)/2; mergeSort(arr, l, m); mergeSort(arr, m+1, r); merge(arr, l, m, r); }
Searching Algorithms
Binary Search — O(log n)
// Array must be SORTED! int binarySearch(int arr[], int n, int target) { int left = 0, right = n - 1; while (left <= right) { int mid = left + (right - left) / 2; // avoids overflow! if (arr[mid] == target) return mid; else if (arr[mid] < target) left = mid + 1; else right = mid - 1; } return -1; // not found } // Each iteration: eliminates half → O(log n)
Complete Complexity Reference
| Data Structure | Access | Search | Insert | Delete |
|---|---|---|---|---|
| Array | O(1) | O(n) | O(n) | O(n) |
| Vector (end) | O(1) | O(n) | O(1)* | O(1) |
| Linked List | O(n) | O(n) | O(1) | O(n) |
| Stack | O(n) | O(n) | O(1) | O(1) |
| Queue | O(n) | O(n) | O(1) | O(1) |
| BST (avg) | O(log n) | O(log n) | O(log n) | O(log n) |
| BST (worst) | O(n) | O(n) | O(n) | O(n) |
| Hash Table (avg) | O(1) | O(1) | O(1) | O(1) |
Quick Reference — Linker vs Compiler Errors
Error Types
// Compiler Error: syntax, type mismatch, abstract class instantiation Base b; // abstract → COMPILER error void foo(int); // declaration only, no definition foo(5); // LINKER error (compiled ok, can't find body) // Runtime Error: division by zero, nullptr dereference, out of bounds // Logical Error: wrong algorithm, no crash but wrong output // Undefined Behavior: double free, use after free, signed overflow
Siemens Interview Tips
✅ اشرح كيف تفكر بصوت عالٍ — أهم من الإجابة الصح مباشرة✅ لو مش عارف الإجابة قول "I'm not sure but I think..." وحاول
✅ ربط الإجابات بالـ project بتاعك (Secure Notes) كلما أمكن
✅ اذكر الـ edge cases: null pointers, empty arrays, abstract classes
✅ Big O: دايماً اذكر worst case ما لم يُطلب average