Siksha Sarovar

Siksha Sarovar (sikshasarovar.com) is a free educational web application that helps students in India learn programming and prepare for academic and competitive exams. The platform offers structured coding courses (C, C++, Python, Java, HTML, CSS, PHP, Power BI, AI, Machine Learning, Data Science), complete university curriculum notes for BCA/MCA students with previous year question papers, Class 10 and Class 12 CBSE/HBSE school notes, and dedicated preparation material for SSC, UPSC, Banking, Railway and other government exams. Browsing the site is completely free and requires no account. Users may optionally sign in with Google solely to save their learning progress, quiz scores and personal preferences across devices.

Privacy Policy | Terms of Service | Contact Siksha Sarovar | About Siksha Sarovar

v4.0.9 · PWA
Siksha Sarovar logo
Siksha Sarovar
Your Learning Universe

Siksha Sarovar is a free e-learning platform for coding courses, BCA university notes and competitive exam preparation. Optional Google sign-in saves your learning progress across devices.

Initializing knowledge base…
Compiling modules 0%

1.3 Functions in C++ — Default Args, Parameter Passing, Inline

Lesson 5 of 22 in the free Object Oriented Programming with C++ notes on Siksha Sarovar, written by Rohit Jangra.

1.3 Functions in C++

Function Basics — quick recap

returnType functionName(parameterList) {
    // body
    return value;
}

Example:

int add(int a, int b) {
    return a + b;
}

int main() {
    cout << add(5, 3);   // 8
    return 0;
}

C++ inherits all C function features and adds:

  • Default arguments
  • Function overloading
  • Reference parameters
  • Inline functions
  • Templates (Unit IV)
  • Lambda expressions (C++11+)

---

Default Arguments

A default argument allows a function to be called with fewer arguments than parameters — missing parameters use the default value.

void greet(string name = "Friend", string greeting = "Hello") {
    cout << greeting << ", " << name << "!" << endl;
}

int main() {
    greet();                        // Hello, Friend!
    greet("Rohit");                 // Hello, Rohit!
    greet("Rohit", "Namaste");      // Namaste, Rohit!
    return 0;
}

Rules for default arguments

  1. Defaults must be specified from right to left — once you give one a default, all to its right must also have defaults.
void f(int a, int b = 5, int c = 10);   // OK
void f(int a = 1, int b, int c = 10);    // ERROR — b needs default too
  1. Defaults can only be specified once — either in the declaration or the definition, not both.
  1. Default values are evaluated at the call site — they can be expressions or even function calls.
  1. Default values are not part of the function signature for overload resolution.

Why use default arguments?

  • Backward compatibility — add a parameter without breaking callers
  • Convenience — common case needs no argument
  • Cleaner API — fewer overloads needed

Equivalent without default arguments (function overloading)

void greet() { cout << "Hello, Friend!" << endl; }
void greet(string name) { cout << "Hello, " << name << "!" << endl; }
void greet(string name, string greeting) {
    cout << greeting << ", " << name << "!" << endl;
}

Default arguments achieve the same with less code.

---

Function Overloading

Function overloading = defining multiple functions with the same name but different parameter lists.

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

add(2, 3);          // calls int add(int, int)
add(2.5, 3.5);      // calls double add(double, double)
add(1, 2, 3);       // calls int add(int, int, int)

Rules for overloading

Can differ inCannot differ in
Number of parametersReturn type alone
Type of parametersDefault values alone
Order of parameters

Compiler's selection rule (name mangling)

The compiler renames overloaded functions internally based on parameter types. int add(int, int) may become _Z3addii; double add(double, double) may become _Z3adddd. So at the linker level there is no ambiguity.

Use cases for overloading

  • Constructors with different argument lists
  • Mathematical operations on different types
  • Print functions for different objects

---

Parameter Passing

C++ supports three ways to pass arguments to a function:

1. Pass-by-Value

void modify(int x) {
    x = 100;        // changes only the local copy
}

int a = 5;
modify(a);
cout << a;          // 5 — unchanged

A copy is made. Changes in the function do not affect the caller's variable. Cheap for primitives, expensive for large objects.

2. Pass-by-Reference

void modify(int& x) {
    x = 100;        // changes the original variable
}

int a = 5;
modify(a);
cout << a;          // 100 — changed

The parameter is an alias for the argument. No copy. Caller's variable can be modified.

3. Pass-by-Pointer

void modify(int* p) {
    *p = 100;       // changes the variable pointed to
}

int a = 5;
modify(&a);
cout << a;          // 100 — changed

The parameter is a pointer to the argument. Must use * to access value, and caller must pass with &.

Comparison — value vs reference vs pointer

AspectValueReferencePointer
Copy made?YesNoNo (copy of address)
Caller can be modified?NoYesYes (via dereference)
Syntax in declarationint xint& xint* x
Syntax in callf(a)f(a)f(&a)
Access in functionxx*x
Can be null?N/ANoYes
Reseatable?N/ANoYes
Best forSmall data, safetyLarge objects, output paramsOptional output, dynamic memory

Const reference — the most useful idiom

void printVector(const vector<int>& v) {  // no copy, no modification
    for (int x : v) cout << x << " ";
}

This is the C++ idiom for passing large containers / objects — efficient AND safe.

---

Inline Functions

An inline function is a function whose body is inserted (expanded) at the call site, eliminating function-call overhead.

inline int square(int x) {
    return x * x;
}

int y = square(5);   // compiler may expand to: int y = 5 * 5;

Why inline?

  • Avoids call overhead — no jump, no stack frame
  • Enables optimisation — compiler sees the body in context
  • Useful for tiny functions called millions of times

How it works

  1. Programmer hints to compiler: "consider inlining this"
  2. Compiler decides — may inline, may not (it's a hint, not a command)
  3. If inlined, function call → body substitution
  4. Function symbol may still exist for non-inlined uses

When to use inline

✅ Small functions (1-3 lines, no loops) ✅ Frequently called functions ✅ Performance-critical paths ✅ Getter / setter methods in classes

When NOT to use inline

❌ Large functions (code bloat) ❌ Functions with loops or recursion ❌ Functions whose address is taken (need a real function symbol) ❌ Virtual functions (usually can't be inlined)

Macros vs inline functions

AspectMacro (#define)Inline Function
ResolutionPreprocessor — text substitutionCompiler
Type safetyNoneYes
Debugger supportHardNormal
Side effectsRisky: #define SQR(x) ((x)*(x))SQR(i++) evaluates twiceSingle evaluation
ScopeGlobalRespects scope
RecommendedNo (legacy)Yes

Modern C++ strongly prefers inline over macros for code-substitution.

---

Type Conversion (more)

Already covered in Lesson 2; here's how it interacts with overloading:

void print(int x)    { cout << "int: " << x << endl; }
void print(double x) { cout << "double: " << x << endl; }

print(5);       // int
print(5.5);     // double
print(5.0f);    // ambiguous? — actually picks double (float promotes)
print('A');     // int (char promotes to int)

The compiler picks the best match using implicit conversion rules.

---

Functions as First-Class Citizens

C++ supports function pointers (from C), functors (objects with operator()), and lambdas (C++11+):

Function pointer

int (*fp)(int, int) = &add;
fp(2, 3);   // 5

Functor (function object)

class Adder {
public:
    int operator()(int a, int b) { return a + b; }
};
Adder add;
add(2, 3);   // 5 — looks like a function call

Lambda (C++11)

auto add = [](int a, int b) { return a + b; };
add(2, 3);   // 5

Lambdas are widely used in modern C++ — STL algorithms, callbacks, threading.

---

Friend Functions (preview — covered in Unit II)

A friend function is a non-member function that has access to a class's private members:

class A {
private:
    int data;
public:
    A(int d) : data(d) {}
    friend void print(A&);   // grants access
};

void print(A& a) {
    cout << a.data;          // can access private!
}

We cover this in detail in Unit II.

---

Key Terms — Lesson 1.3

The terms below define C++'s function-related vocabulary — every PYQ on default arguments, overloading, inline, or parameter passing expects fluent use.

Function — A named block of code that takes inputs (parameters), performs an action, and optionally returns a result. The basic unit of code reuse in C and C++.

Function Prototype / Declaration — A statement that declares a function's signature (return type, name, parameter types) without defining the body. Allows the function to be called before its definition appears. Typically lives in header files.

Function Definition — The full implementation of a function — its prototype plus the body. There can be many declarations of a function but only one definition per program (the One Definition Rule).

Parameter vs Argument — A parameter is the variable in the function's declaration (int x in void f(int x)). An argument is the value passed at the call site (5 in f(5)). The two terms are often used loosely but mean different things.

Default Argument — A C++ feature: a function parameter can have a default value used when the caller omits the argument. void greet(string name = "Friend"); lets greet() or greet("Rohit") both compile. Defaults must be at the right end of the parameter list; you cannot have a default in the middle followed by a non-default.

Function Overloading — Defining multiple functions with the same name but different parameter lists (different number, types, or order of parameters). The compiler picks the right overload based on the call's arguments — compile-time polymorphism. Return type alone cannot distinguish overloads.

Name Mangling — The compiler's technique for implementing function overloading: each overload's internal symbol name encodes its parameter types (_Z3addii for int add(int, int) etc.). Name mangling is why C++ code cannot directly call C functions without extern "C".

Pass-by-Value — Function-call style where the argument is copied into the parameter. The function operates on the copy; the original is untouched. Safe but expensive for large objects.

Pass-by-Reference — Function-call style where the parameter is a reference to the argument (declared with &). The function operates on the original, can modify it, and avoids the copy cost. C++'s preferred idiom for output parameters and large objects.

Pass-by-Pointer — Function-call style where the parameter is a pointer to the argument. The function dereferences the pointer to access or modify the original. Predates references; still used for optional parameters (pass nullptr to skip) and dynamic arrays.

Inline Function — A function annotated with the inline keyword as a hint to the compiler to substitute the function body at the call site instead of generating a call/return. Avoids call overhead for tiny functions. The compiler may ignore the hint; in modern C++ the keyword's bigger role is allowing the function to be defined in headers (multiple translation units) without violating the One Definition Rule.

Macro vs Inline Function — Two ways to avoid function-call overhead. Macros (#define SQUARE(x) ((x)*(x))) are textual substitution by the preprocessor — no type checking, no scoping, side effects can multiply (SQUARE(i++) evaluates i++ twice). Inline functions are real functions — type-checked, scoped, evaluate arguments exactly once. Inline functions are always preferred over macros in modern C++.

Recursive Function — A function that calls itself, directly or indirectly, with a base case to terminate. Classical examples: factorial, Fibonacci, tree traversal. Most recursive functions should not be marked inline because the substitution cannot bottom out.

Friend Function — A non-member function declared with the friend keyword inside a class, granting it access to the class's private and protected members. Friend functions are not methods (no this pointer) but can read/write private data. Covered in detail in Unit II.

One Definition Rule (ODR) — A C++ rule: every entity (function, variable, class) must have exactly one definition across the entire program. Multiple declarations are fine; multiple definitions are a linker error. Inline functions and templates are exempt — they can be defined in multiple translation units provided every definition is identical.

Function Signature — The combination of a function's name and parameter list (types, count, order, and const/volatile qualifiers on member functions). Two functions with the same signature cannot coexist; two with different signatures can overload.

Overload Resolution — The compiler's algorithm for picking the right overload at a call site. The compiler ranks each candidate by how well its parameters match the arguments (exact match, promotion, conversion); the best match wins. Ambiguous calls (multiple equally-good matches) are compile errors.

Default Argument Evaluation — Default arguments are evaluated at each call, not at function definition. So void f(int x = currentTime()); calls currentTime() every time f() is invoked, not once at declaration.

---

Study deep

  1. Default arguments + overloading can conflict. void f(int a, int b = 5); AND void f(int a); — ambiguous when called f(1). The compiler errors. Don't mix the two for the same parameter count.
  1. Pass-by-reference is the C++ idiom for output parameters. Java/C# don't have this — they use return values or wrapper objects. C++ out parameters via reference are idiomatic but be careful — they hide that the function modifies the caller's data.
  1. inline is more about linkage than performance. In modern C++, the keyword's main job is allowing the function to be defined in multiple translation units without violating the One Definition Rule. The compiler's inlining decision is mostly automatic.
  1. The compiler can inline non-inline functions. Modern compilers inline aggressively based on heuristics. The inline keyword is a hint and matters less than it once did.
  1. Function overloading + templates = powerful generic code. Combined with templates, overloading enables zero-cost abstractions — code that's as generic as Python but as fast as C.
PYQ pattern (very common): "What are default arguments? Explain with example. State its rules." — Define; show example (greet(name="Friend", greeting="Hello")); state 4 rules (right-to-left, declared once, evaluated at call, not in signature).
PYQ pattern: "Explain function overloading with example." — Define; show 3 overloads of add; state rules (parameter count/type/order can differ; return type alone cannot); explain name mangling briefly.
PYQ pattern: "Differentiate pass-by-value, pass-by-reference, and pass-by-pointer." — Tabulate the 5-6 differences; one short code example each.
PYQ pattern: "Explain inline functions. Differentiate inline functions and macros." — Define; show example; list when to use (small, frequent); when not (large, recursion); table 5 differences vs macros (type safety, side effects, etc.).