C++ Fundamentals

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

RelationshipStrengthExampleLifetime
CompositionStrongestCar → EngineChild dies with parent
AggregationMediumLibrary → BooksChild lives independently
AssociationWeakestTeacher → StudentJust "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;
}
OperationArrayLinked List
Access by indexO(1)O(n)
Insert at headO(n)O(1)
Insert at tailO(1)*O(n) or O(1) with tail ptr
DeleteO(n)O(n) search + O(1) delete
MemoryContiguousScattered (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

AlgorithmBestAverageWorstSpaceStable?
Bubble SortO(n)O(n²)O(n²)O(1)
Selection SortO(n²)O(n²)O(n²)O(1)
Insertion SortO(n)O(n²)O(n²)O(1)
Merge SortO(n log n)O(n log n)O(n log n)O(n)
Quick SortO(n log n)O(n log n)O(n²)O(log n)
Heap SortO(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 (iwhile (jvoid 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 StructureAccessSearchInsertDelete
ArrayO(1)O(n)O(n)O(n)
Vector (end)O(1)O(n)O(1)*O(1)
Linked ListO(n)O(n)O(1)O(n)
StackO(n)O(n)O(1)O(1)
QueueO(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