Monday, October 5, 2026

 Here’s a C++ template interview cheat sheet with each question followed by an interview-ready answer, explanation, and example.


1. What is a template in C++? Why do we use templates?

Answer:

 A template allows us to write generic code that works with different data types without duplicating the implementation.

There are two main types:

* Function templates

* Class templates

Example

cpp

template <typename T>

T add(T a, T b)

{

    return a + b;

}


Now the same function can work with multiple types:

cpp

add(10, 20);          // int

add(2.5, 3.5);        // double

add(std::string("A"), "B");  // string


The compiler generates the appropriate version when the template is instantiated.

Why use templates?

* Code reuse

* Type safety

* Compile-time polymorphism

* Generic programming

* Often zero runtime overhead

Interview point: Templates are primarily a mechanism for compile-time polymorphism, whereas virtual functions provide runtime polymorphism.


───


2. What's the difference between typename and class in templates?

For declaring a template type parameter, they are generally equivalent:

cpp

template <typename T>

class Box {};


and:

cpp

template <class T>

class Box {};


Both mean that T is a type.

But typename has another important use

Consider:

cpp

template <typename T>

void foo()

{

    T::value_type x;

}


This is problematic because the compiler doesn't initially know whether T::value_type is a type or something else.

We tell the compiler explicitly:

cpp

template <typename T>

void foo()

{

    typename T::value_type x;

}


Here, typename means:

T::value_type is a type.

Interview trap

Don't say "typename and class are always interchangeable."

They're interchangeable when declaring a template type parameter, but typename has additional meaning for dependent names.


───


3. What is template specialization?

Specialization allows us to provide a different implementation for a particular type or category of types.

There are two important forms.

Full specialization

cpp

template <typename T>

class Printer

{

public:

    void print()

    {

        std::cout << "Generic\n";

    }

};


For int, we can provide a completely different implementation:

cpp

template <>

class Printer<int>

{

public:

    void print()

    {

        std::cout << "Integer\n";

    }

};


Now:

cpp

Printer<double> p1;

p1.print();       // Generic


Printer<int> p2;

p2.print();       // Integer


Partial specialization

We can specialize a class template for a category of types.

cpp

template <typename T>

class Printer

{

};


For pointers:

cpp

template <typename T>

class Printer<T*>

{

};


Now:

cpp

Printer<int> p1;     // primary template

Printer<int*> p2;    // pointer specialization


Important interview question

Can function templates be partially specialized?

No.

Class templates can be partially specialized.

Function templates can instead be overloaded.


───


4. What's the difference between function template specialization and overloading?

Consider:

cpp

template <typename T>

void print(T value)

{

    std::cout << "Template\n";

}


We can specialize it:

cpp

template <>

void print<int>(int value)

{

    std::cout << "Specialization\n";

}


Or we can overload it:

cpp

void print(int value)

{

    std::cout << "Overload\n";

}


These are not equivalent.

Why?

Overloading participates in overload resolution.

Template specialization happens after the appropriate template has been selected.

This can lead to surprising behavior, particularly when templates are called through other templates.

Interview recommendation

If asked:

"Should I specialize a function template or overload it?"

A good answer is:

Function templates generally cannot be partially specialized, and overloading is often preferable when customizing function behavior. Class template specialization is the normal mechanism for specialization.


───


5. What is SFINAE?

SFINAE stands for:

Substitution Failure Is Not An Error

It means that when substituting template arguments causes an invalid type or expression in the immediate context, that template can simply be removed from consideration rather than producing a compilation error.

A classic example:

cpp

template <typename T>

typename T::value_type getValue(T obj)

{

    return obj[0];

}


Suppose:

cpp

std::vector<int> v;

getValue(v);


std::vector<int> has:

cpp

value_type


so the template works.

But:

cpp

int x;

getValue(x);


doesn't have int::value_type.

With SFINAE, we can use this fact to control which functions participate in overload resolution.

Common SFINAE tools

cpp

std::enable_if

std::void_t

std::is_same

std::is_integral

std::is_convertible


For example:

cpp

template <

    typename T,

    typename = std::enable_if_t<std::is_integral_v<T>>

>

void foo(T value)

{

    std::cout << "Integral\n";

}


This function only participates when T is an integral type.

Modern C++

C++20 concepts provide a much cleaner solution:

cpp

template <std::integral T>

void foo(T value)

{

}


So an excellent interview answer is:

SFINAE was historically used to constrain templates. In modern C++, concepts are usually preferred because they're clearer and produce better diagnostics.


───


6. What are variadic templates?

A variadic template can accept zero or more template arguments.

cpp

template <typename... Args>

void print(Args... args)

{

}


Args... is called a parameter pack.

For example:

cpp

print(1, 2.5, "hello", 'A');


Args could represent:

text

int

double

const char*

char


Fold expressions

C++17 introduced fold expressions, making variadic templates much easier to use.

For example:

cpp

template <typename... Args>

auto sum(Args... args)

{

    return (args + ...);

}


Then:

cpp

auto result = sum(1, 2, 3, 4);


Conceptually:

cpp

((1 + 2) + 3) + 4


Why are variadic templates useful?

They're heavily used in:

* std::tuple

* std::make_unique

* std::make_shared

* std::format

* Generic wrappers

* Perfect forwarding


───


7. What is template instantiation?

A template is essentially a blueprint. Instantiation happens when the compiler needs a concrete version of that template.

Example:

cpp

template <typename T>

T square(T x)

{

    return x * x;

}


When we write:

cpp

square(5);


the compiler can instantiate:

cpp

int square(int x)

{

    return x * x;

}


And:

cpp

square(2.5);


can result in:

cpp

double square(double x)

{

    return x * x;

}


Three concepts worth knowing

Implicit instantiation

cpp

square(5);


The compiler generates what's needed automatically.

Explicit specialization

cpp

template <>

int square<int>(int x)

{

    // special implementation

}


Explicit instantiation

cpp

template int square<int>(int);


This explicitly tells the compiler to instantiate the template for int.

Interview follow-up

Why are templates usually defined in header files?

Because the compiler generally needs to see the template definition at the point of instantiation.

This is why you'll commonly see:

cpp

// MyClass.h

template <typename T>

class MyClass

{

    ...

};


rather than putting the implementation only in a .cpp file.


───


8. What are dependent names, and why do we need typename?

This is one of the classic advanced template questions.

Consider:

cpp

template <typename T>

void foo()

{

    T::value_type x;

}


The problem is that T is a dependent type. The compiler doesn't know what T will be yet.

Therefore, it doesn't know whether:

cpp

T::value_type


is a type or something else.

We tell the compiler:

cpp

template <typename T>

void foo()

{

    typename T::value_type x;

}


The typename says:

Treat T::value_type as a type.

Another related keyword: template

You can encounter:

cpp

obj.template foo<int>();


The template keyword tells the compiler that foo should be interpreted as a template when obj depends on a template parameter.

These two keywords are frequently tested together in senior C++ interviews.


───


9. What are C++20 concepts?

Concepts allow us to specify requirements on template parameters.

Before C++20, you might write:

cpp

template <

    typename T,

    typename = std::enable_if_t<std::is_arithmetic_v<T>>

>

T add(T a, T b)

{

    return a + b;

}


This works, but it's difficult to read.

With C++20:

cpp

template <typename T>

concept Numeric = std::is_arithmetic_v<T>;


template <Numeric T>

T add(T a, T b)

{

    return a + b;

}


Or using a standard concept:

cpp

template <std::integral T>

T add(T a, T b)

{

    return a + b;

}


Advantages of concepts

* More readable

* Better compiler errors

* Clearly communicates requirements

* Cleaner overload resolution

* Replaces many traditional SFINAE techniques

Interview answer

A good concise answer:

Concepts are named compile-time constraints on template parameters introduced in C++20. They make template requirements explicit and generally provide clearer diagnostics than SFINAE.


───


10. What is perfect forwarding, and how is it related to templates?

This is probably the most important advanced topic on this list.

Consider:

cpp

template <typename T>

void wrapper(T&& arg)

{

    foo(std::forward<T>(arg));

}


Here T&& can be a forwarding reference when T is deduced.

It allows the wrapper to preserve whether the caller passed an lvalue or rvalue.

Example

cpp

void foo(const std::string& s)

{

    std::cout << "lvalue\n";

}


void foo(std::string&& s)

{

    std::cout << "rvalue\n";

}


Now:

cpp

std::string s = "hello";


wrapper(s);                  // lvalue

wrapper(std::string("hi"));  // rvalue


std::forward<T> preserves that value category.

Why not just use std::move?

This is an important interview question.

std::moveunconditionally casts its argument to an rvalue.

std::forward<T> conditionally casts based on the original type/value category.

So:

cpp

std::move(x)


means roughly:

"Treat x as an rvalue."

Whereas:

cpp

std::forward<T>(x)


means:

"Preserve whether the caller originally gave me an lvalue or rvalue."

Reference collapsing

Perfect forwarding relies on reference collapsing rules:


Combination

Result


T& &

T&


T& &&

T&


T&& &

T&


T&& &&

T&&



This is very commonly asked in senior C++ interviews.


───


🔥 The 10 to memorize

If you want a compact interview revision list:


#

Question

Key concept


1

What are templates?

Generic/compile-time programming


2

typename vs class?

Template parameters + dependent types


3

What is specialization?

Full vs partial specialization


4

Specialization vs overloading?

Overload resolution


5

What is SFINAE?

Substitution failure


6

What are variadic templates?

Parameter packs/fold expressions


7

What is template instantiation?

Implicit/explicit instantiation


8

What are dependent names?

typename, template


9

What are concepts?

C++20 constraints


10

What is perfect forwarding?

Forwarding references/reference collapsing



For a senior C++ interview, I'd spend the most time on #5, #8, #9 and #10. Those are where interviewers can quickly move from basic template knowledge into deeper C++ understanding.

 Here’s a C++ lambda syntax cheat sheet from basics → advanced, with the pieces building up progressively.

1. Basic lambda
cpp
[]() {
    std::cout << "Hello";
};
General syntax:
cpp
[capture](parameters) -> return_type {
    // body
};
The -> return_type is usually optional because C++ can deduce it.
cpp
[]() {
    return 10;
};

───
2. Store a lambda in a variable
cpp
auto add = [](int a, int b) {
    return a + b;
};
std::cout << add(2, 3);   // 5
Think of a lambda as an unnamed function object.

───
3. Parameters
cpp
auto multiply = [](int a, int b) {
    return a * b;
};
multiply(3, 4);
Explicit return type:
cpp
auto divide = [](int a, int b) -> double {
    return static_cast<double>(a) / b;
};

───
4. Capture list []
The capture list controls which outside variables the lambda can access.
cpp
int x = 10;
auto f = []() {
    // std::cout << x;  // ❌ x not captured
};
Capture x by value:
cpp
int x = 10;
auto f = [x]() {
    std::cout << x;
};
Capture x by reference:
cpp
int x = 10;
auto f = [&x]() {
    x = 20;
};

───
5. Capture everything
Capture everything by value
cpp
int x = 10;
int y = 20;
auto f = [=]() {
    std::cout << x << y;
};
Capture everything by reference
cpp
int x = 10;
int y = 20;
auto f = [&]() {
    x++;
    y++;
};
Mix value and reference
cpp
int x = 10;
int y = 20;
auto f = [x, &y]() {
    // x → copied
    // y → referenced
};
You can also write:
cpp
[x, &y]

───
6. Mutable lambda
This is an important concept.
By default, variables captured by value cannot be modified inside the lambda:
cpp
int x = 10;
auto f = [x]() {
    // x++;  // ❌
};
Use mutable:
cpp
int x = 10;
auto f = [x]() mutable {
    x++;
    std::cout << x;
};
f();  // 11
f();  // 12
std::cout << x;  // 10
Notice:
text
Original x       = 10
Lambda's copy    = 10 → 11 → 12
mutable changes the lambda's captured copy, not the original variable.

───
7. Lambda with no parameters
cpp
auto hello = [] {
    std::cout << "Hello";
};
The () can be omitted when there are no parameters.
Equivalent:
cpp
[]() {
    std::cout << "Hello";
};

───
8. Lambda with return type
Usually:
cpp
auto f = [](int x) {
    return x * 2;
};
Compiler deduces int.
Explicit:
cpp
auto f = [](int x) -> int {
    return x * 2;
};
Useful when deduction is problematic or when you want to be explicit.

───
9. Lambda passed to an algorithm
This is where lambdas become extremely useful.
cpp
std::vector<int> v = {1, 2, 3, 4, 5};
std::for_each(v.begin(), v.end(), [](int x) {
    std::cout << x << " ";
});
Sorting:
cpp
std::sort(v.begin(), v.end(), [](int a, int b) {
    return a > b;
});
Result:
text
5 4 3 2 1

───
10. Lambda with std::find_if
cpp
auto it = std::find_if(
    v.begin(),
    v.end(),
    [](int x) {
        return x > 10;
    }
);
The lambda acts as a predicate.

───
11. Generic lambda — C++14
Instead of specifying parameter types:
cpp
auto print = [](auto x) {
    std::cout << x;
};
print(10);
print(3.14);
print("Hello");
The lambda effectively behaves like a function template.
Conceptually:
text
print(int)
print(double)
print(const char*)

───
12. Generic lambda with multiple parameters
cpp
auto add = [](auto a, auto b) {
    return a + b;
};
add(10, 20);
add(2.5, 3.5);

───
13. Generic lambda with forwarding references
More advanced:
cpp
auto f = [](auto&& x) {
    // x can bind to lvalue or rvalue
};
This is commonly used when writing generic code.
For perfect forwarding:
cpp
auto f = [](auto&& x) {
    some_function(std::forward<decltype(x)>(x));
};

───
14. Lambda returning a lambda
Yes, lambdas can return lambdas.
cpp
auto createAdder = [](int x) {
    return [x](int y) {
        return x + y;
    };
};
auto add10 = createAdder(10);
std::cout << add10(5);  // 15
Here:
text
createAdder(10)
       ↓
lambda capturing x = 10
       ↓
add10(5)
       ↓
15

───
15. Immediately Invoked Lambda — IIFE
You can create and immediately execute a lambda:
cpp
int result = [](int a, int b) {
    return a + b;
}(10, 20);
result becomes 30.
This:
cpp
[](int a, int b) {
    return a + b;
}(10, 20);
means:
Create lambda → immediately call it with 10, 20.


───
16. Capture this
Inside a member function:
cpp
class A {
    int value = 10;
public:
    void foo() {
        auto f = [this]() {
            std::cout << value;
        };
        f();
    }
};
[this] captures the this pointer.
You can therefore access:
cpp
value
which is essentially:
cpp
this->value

───
17. Capture *this — C++17
This is different.
cpp
auto f = [*this]() {
    std::cout << value;
};
[*this] captures a copy of the object.
Compare:
cpp
[this]
with:
cpp
[*this]

Capture
Captures
[this]
this pointer
[*this]
copy of the object

This distinction becomes important when the lambda outlives the object.


───
18. Init capture — C++14
You can create a new variable inside the capture list:
cpp
int x = 10;
auto f = [y = x + 5]() {
    std::cout << y;
};
y is a new variable belonging to the lambda.
Very useful for moving objects:
cpp
auto ptr = std::make_unique<int>(10);
auto f = [p = std::move(ptr)]() {
    std::cout << *p;
};
Now ownership of the unique_ptr has been moved into the lambda.


───
19. Generalized lambda capture
You can have multiple init captures:
cpp
int x = 10;
auto f = [
    a = x + 1,
    b = x * 2
]() {
    std::cout << a << b;
};

───
20. constexpr lambda
Modern C++ allows constexpr lambdas:
cpp
constexpr auto square = [](int x) {
    return x * x;
};
constexpr int result = square(5);
result can be evaluated at compile time.
───


21. Lambda with constraints — C++20
Generic lambda:
cpp
auto add = [](auto a, auto b) {
    return a + b;
};
You can constrain it:
cpp
auto add = []<typename T>(T a, T b) {
    return a + b;
};
With concepts:
cpp
auto add = []<std::integral T>(T a, T b) {
    return a + b;
};
Now the lambda only accepts integral types.
This <typename T> syntax is called a template parameter list for the lambda and was introduced in C++20.


───
22. Lambda conversion to function pointer
A lambda with no captures can convert to a function pointer:
cpp
auto f = [](int x) {
    return x * 2;
};
int (*ptr)(int) = f;
std::cout << ptr(5);
But this doesn't work for a capturing lambda:
cpp
int x = 10;
auto f = [x](int y) {
    return x + y;
};
// int (*ptr)(int) = f;  // ❌
Why?
Because the lambda needs stored state (x).


───
23. std::function
You can store lambdas in std::function:
cpp
std::function<int(int, int)> add =
    [](int a, int b) {
        return a + b;
    };
std::cout << add(2, 3);
This is useful when you need a common callable type.
But std::function has some overhead, so don't automatically use it everywhere.


───
24. Lambda as a comparator
Very common in interviews:
cpp
std::sort(v.begin(), v.end(),
    [](int a, int b) {
        return a < b;
    });
For objects:
cpp
std::sort(students.begin(), students.end(),
    [](const Student& a, const Student& b) {
        return a.age < b.age;
    });


───
25. Recursive lambda
A lambda cannot simply refer to itself by its own variable during its initialization:
cpp
// ❌
auto factorial = [](int n) {
    return n * factorial(n - 1);
};
One common solution is std::function:
cpp
std::function<int(int)> factorial =
    [&](int n) {
        if (n <= 1)
            return 1;
        return n * factorial(n - 1);
    };
Modern C++ also allows more efficient patterns using an explicit self parameter:
cpp
auto factorial = [](this auto&& self, int n) {
    if (n <= 1)
        return 1;
    return n * self(n - 1);
};
The explicit object parameter form above is C++23.


───
26. The full syntax to remember
The most useful mental model is:
cpp
[captures] <template_params> (parameters)
    mutable
    constexpr
    noexcept
    -> return_type
{
    body
}
Not every part is required.
For example:
cpp
auto f =
    [x, &y]                 // capture
    <typename T>            // template parameters (C++20)
    (T value)               // parameters
    mutable                 // mutable
    noexcept                // noexcept
    -> T                    // return type
{
    // body
};

───
The progression I'd memorize
text
[]() { }
 ↓
[](int x) { }
 ↓
[x](int y) { }
 ↓
[&x](int y) { }
 ↓
[=](int y) { }
 ↓
[&](int y) { }
 ↓
[x]() mutable { }
 ↓
[x = std::move(obj)]() { }
 ↓
[](auto x) { }                    // C++14
 ↓
[*this]() { }                     // C++17
 ↓
[]<typename T>(T x) { }           // C++20
 ↓
[](this auto&& self) { }          // C++23
If you're preparing for a C++ interview, the most important lambda topics are: capture by value/reference, mutable, this vs *this, init-capture, generic lambdas, lambda-to-function-pointer conversion, std::function, and using lambdas with STL algorithms.

Saturday, March 22, 2025

FIX : Custom messages and fields

 Defining custom FIX protocol messages and custom fields involves extending the standard FIX protocol with your own message types and fields. These customizations are often necessary to support specific business requirements that are not covered by the standard FIX specification.

Here’s a detailed guide on how to define both custom messages and fields in the FIX protocol:


1. Defining Custom FIX Protocol Fields

Steps to Define Custom Fields:

  1. Choose a Custom Tag Number:

    • The FIX protocol assigns tag numbers to fields, with the range 5000 and above typically being used for custom or proprietary fields.
    • Ensure that the tag number you choose does not conflict with the standard FIX field tags (i.e., 1–4999).
  2. Define the Field Name and Description:

    • Field Name: A descriptive name for the field (e.g., CustomOrderID, TraderNote).
    • Tag Number: The number associated with the custom field (e.g., 5500).
    • Data Type: Specify the data type of the field (e.g., String, Integer, Date).
    • Field Description: Clearly describe the purpose of the field.
  3. Example Custom Field Definition:

    • Tag: 5500
    • Name: CustomOrderID
    • Type: String
    • Description: A unique identifier for the custom order used internally by the trading system.

Example of Custom Field in a FIX Message:

8=FIX.4.2|9=74|35=D|49=SenderCompID|56=TargetCompID|34=123|5500=OrderABC123|10=154|

Here, the custom field 5500 (CustomOrderID) is sent with the value OrderABC123.


2. Defining Custom FIX Protocol Messages

Steps to Define Custom Messages:

  1. Define a New Message Type:

    • Each FIX message consists of a set of fields (tags) and has a Message Type identified by a specific MsgType. To create a custom message, you need to assign a new MsgType identifier.
    • Custom message types are typically assigned tag numbers in the range of Z to AZ or from the extended custom tag range (e.g., U1, U2).
  2. Create a Message Definition:

    • MsgType: This is the unique identifier for your custom message.
    • Fields: Define the tags and fields that make up your custom message. These can include both standard and custom fields.
    • Sequence and Structure: Define the order in which fields will appear in the message.
  3. Define the Message Description and Usage:

    • Message Name: A meaningful name for the custom message (e.g., CustomOrderMessage).
    • Purpose: Describe the purpose of the custom message.
    • Tags/Fields: List the tags and their corresponding fields used in the message.

Example Custom Message Definition:

  • MsgType: U1 (custom message type)
  • Message Name: CustomOrderMessage
  • Tags/Fields:
    • 35=U1 (indicating the custom message type)
    • 5500=OrderABC123 (custom field for order ID)
    • 53=1 (standard FIX field for order side, e.g., buy/sell)
    • 54=1 (standard FIX field for quantity)
    • 38=1000 (standard FIX field for quantity of the order)

3. Example of Custom FIX Message Using Custom Fields:

Here’s an example of how you might send a custom message with a custom field in a FIX message:

8=FIX.4.2|9=105|35=U1|49=SenderCompID|56=TargetCompID|34=123|5500=OrderABC123|53=1|54=1|38=1000|10=154|

Explanation:

  • 35=U1: This indicates a custom message type (U1).
  • 5500=OrderABC123: This is the custom field CustomOrderID with the value OrderABC123.
  • 53=1: This is the standard Side field, where 1 might mean a buy order.
  • 54=1: This represents the quantity field, here with a value of 1000.
  • 38=1000: This is the standard Quantity field in FIX, indicating the size of the order.

4. Implementation and Configuration

After defining your custom messages and fields, you will need to:

  1. Update FIX Engine Configuration:

    • Ensure that the FIX engine or parser you are using understands your custom tags and message types.
    • This could mean updating the FIX engine’s configuration files to include the new message types and custom fields.
  2. Custom Message Parsing Logic:

    • You may need to write custom parsers or message handlers to interpret your custom messages and fields. Ensure that both encoding and decoding functions support your custom message structure.
  3. Communication with Counterparties:

    • When using custom fields and messages, ensure that both your side and your counterparties agree on the structure, tags, and message types. This avoids potential issues in message interpretation.
    • Document the custom message types and field definitions and share them with anyone who needs to communicate with your system via FIX.

5. Example of Full Process:

1. Define Custom Field:

  • Tag: 5500
  • Name: CustomOrderID
  • Type: String
  • Description: Internal unique identifier for orders.

2. Define Custom Message:

  • MsgType: U1
  • Name: CustomOrderMessage
  • Fields:
    • 5500=OrderABC123
    • 53=1 (Buy)
    • 54=1 (Quantity)
    • 38=1000

3. Send Message:

8=FIX.4.2|9=105|35=U1|49=SenderCompID|56=TargetCompID|34=123|5500=OrderABC123|53=1|54=1|38=1000|10=154|

By following these steps, you can successfully define and implement custom FIX protocol fields and messages that are specific to your application’s needs.

Tuesday, March 11, 2025

Misc Questions

 Misc Interview Questions


Size of shared_ptr

The size of std::shared_ptr is typically 16 bytes or more on a 64-bit system.

The size consists of an 8-byte pointer to the object and 8+ bytes for the control block that handles reference counting.

The actual size can vary depending on the platform, architecture, and standard library implementation, so you can use sizeof to check it for your environment.



Diamond problem

The diamond problem in C++ (and other object-oriented languages that support multiple inheritance) refers to an ambiguity that arises when a class inherits from two classes that both inherit from the same base class. This situation can cause issues with inheritance and method resolution, specifically when the derived class is unsure which path to take to access the base class's methods or members.

To solve the diamond problem, C++ introduces virtual inheritance. Virtual inheritance ensures that the base class is shared between all the derived classes.


what is array decay in C++

Array decay in C++ refers to the process by which an array is automatically converted to a pointer when passed to a function. This occurs because, in most contexts, the name of an array is interpreted as a pointer to its first element, which causes the loss of the array's size and type information.

Key Points About Array Decay:

  1. Array to Pointer Conversion: When you pass an array to a function, it decays into a pointer to the first element of the array. This means the function only receives a pointer, and it no longer has access to the full array's size or type.
  2. Loss of Array Size Information: When an array decays into a pointer, the size of the array is lost. The function receiving the array will not know how many elements the array has. This is why, when passing arrays to functions, it's common to also pass the array's size as a separate argument.

To prevent problems from array decay, you can use alternatives like std::array or std::vector, which retain size information and provide safer, more flexible handling of arrays.


Key Differences Between Abstract Class and Interface

Feature

Abstract Class

Interface

Instantiation

Cannot be instantiated directly.

Cannot be instantiated directly.

Methods

Can have both abstract and concrete methods.

Can only have abstract methods (except default and static methods).

Constructor

Can have constructors.

Cannot have constructors.

Fields

Can have instance variables (fields).

Can only have public static final variables (constants).

Inheritance

A class can extend only one abstract class.

A class can implement multiple interfaces.

Access Modifiers

Can have any access modifiers for methods and fields.

All methods in an interface are implicitly public, and they cannot have other access modifiers.

Default Methods

Cannot have default methods.

Can have default methods (Java 8+).

Purpose

Used when classes share common functionality but might not have a strict contract.

Used to define a contract or capability that classes should adhere to.

Multiple Inheritance

No multiple inheritance (one class only).

Supports multiple inheritance (a class can implement multiple interfaces).


REST (Representational State Transfer Application Programming Interface)

Stateless means that each request from the client to the server must contain all the information the server needs to fulfill the request. The server does not store any state about the client between requests. Each request is independent.

HTTP Methods

REST APIs commonly use standard HTTP methods (also called verbs) to perform operations on resources:

GET: Retrieve data from the server. For example, GET /users might fetch all users.

POST: Create a new resource on the server. For example, POST /users might create a new user.

PUT: Update an existing resource. For example, PUT /users/123 might update the user with ID 123.

DELETE: Delete a resource. For example, DELETE /users/123 might delete the user with ID 123.

PATCH: Partially update a resource.

HTTP Status Codes

REST APIs use HTTP status codes to indicate the outcome of the request:

200 OK: The request was successful, and the server has responded with the requested data.

201 Created: The request was successful, and a new resource was created.

400 Bad Request: The server could not understand the request, often due to malformed syntax.

404 Not Found: The resource was not found.

500 Internal Server Error: The server encountered an error while processing the request.

CRUD Operations

REST APIs typically align with the CRUD operations:

Create (POST)

Read (GET)

Update (PUT or PATCH)

Delete (DELETE)

Idempotency

RESTful APIs emphasize idempotency in certain operations. This means that making multiple identical requests should have the same effect as making a single request.

For example, a GET request is idempotent because it will always return the same data.

A DELETE request is also typically idempotent, as deleting a resource multiple times will have the same result: the resource will be gone.


STUB, MOCK or FAKE

Stub: If you’re testing a service that calls an external API, and you want to simulate a successful response from that API, you’d use a stub.

Mock: If you’re testing the interaction between a service and a logging mechanism, and you want to assert that the log method was called with the correct parameters, you’d use a mock.

Fake: If you’re testing a database-driven application and don’t want to rely on a real database, you might use a fake in-memory database.


Some C++ process is running slow - how would you go about investigating

To investigate why a C++ process is running slow, you should:

  1. Profile the application using tools like gprof, perf, or Valgrind to find bottlenecks.
  2. Analyze algorithms for inefficiency and optimize them.
  3. Check for memory leaks or excessive memory usage using profiling tools.
  4. Investigate multi-threading issues (e.g., thread contention, lock contention).
  5. Look for disk or network I/O issues.
  6. Use compiler optimizations and review the code for any unnecessary copies or suboptimal code paths.


Possible Outcomes When There's a Connection Problem:

  • Connection Failure: The connection cannot be established or is refused (e.g., server unreachable, port closed).
  • Packet Loss: Lost packets trigger retransmissions, slowing down the connection.
  • Timeouts: If acknowledgments aren't received within the timeout period, retransmissions are attempted. Multiple timeouts can lead to connection termination.
  • Congestion Control: TCP reduces the transmission rate to avoid congestion, which can cause slowdowns.
  • Connection Reset: A reset is initiated due to a forced termination or unexpected error.
  • Half-Open Connections: Inconsistent connection states when one side terminates while the other side is unaware.
  • Firewall/NAT Issues: Network security devices can block or drop TCP packets, resulting in connection issues.


Git and Github Differences:

Git

GitHub

A version control system used to manage source code history.

A platform/hosting service built around Git to store and manage Git repositories online.

CLI-based (command-line interface) tool.

Web-based platform with a GUI for repository management and collaboration.

Git is used locally on your computer to track changes and manage code.

GitHub allows you to host repositories and collaborate with others remotely.

Focuses on version control and local repository management.

Focuses on collaboration, project management, and hosting Git repositories in the cloud.

In a typical workflow:

  • Git is used to create and manage repositories on your local machine, commit changes, and track history.
  • GitHub is used to store the remote version of your repositories, collaborate with others, and share code. You push and pull changes to and from GitHub using Git commands.