2.2 Function Overloading, Static Members, Friend & this Pointer
Function Overloading in Classes
Already introduced in Unit I — within a class, you can overload constructors and member functions:
class Calculator {
public:
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; }
};
Calculator c;
c.add(2, 3); // int version
c.add(2.5, 3.5); // double version
c.add(1, 2, 3); // 3-arg version
Common uses
- Multiple constructor signatures (default, parameterized, copy)
- Operations on different types
- Variants of
print/display/set
---
Static Data Members
A static data member belongs to the class itself, not to any object. All objects share the same copy.
class Counter {
private:
static int count; // declaration
public:
Counter() { count++; }
static int getCount() { return count; }
};
int Counter::count = 0; // definition — required outside the class
int main() {
Counter a, b, c; // 3 objects created
cout << Counter::getCount(); // 3
return 0;
}
Key rules
- Declared inside the class with
static - Defined outside the class with
ClassName::name - One copy per class, not per object
- Can be accessed via
ClassName::member(preferred) orobject.member - Initialised before
main()starts const staticintegral types can be initialised in-class:
class Config {
static const int MAX = 100; // OK for const static int
};
Common uses
- Counter — how many objects exist
- Shared resource — connection pool
- Configuration — max size, default values
- Singleton pattern — single instance
---
Static Member Functions
A static member function belongs to the class, not to any object. It can be called without an instance.
class Math {
public:
static int square(int x) { return x * x; }
static const double PI;
};
const double Math::PI = 3.14159;
int main() {
cout << Math::square(5); // 25 — no object needed
cout << Math::PI; // 3.14159
return 0;
}
Restrictions
- Cannot access non-static members (no
thispointer) - Cannot be virtual
- Cannot be
const(no object to be const)
class A {
int x; // non-static
static int y; // static
static void f() {
// x = 5; ERROR — no 'this'
y = 5; // OK — y is static
}
};
Use cases
- Utility / helper functions (
Math::sqrt) - Factory functions (
Student::create(...)) - Singleton accessor
---
this Pointer
The this pointer is an implicit pointer to the current object inside any non-static member function.
class Student {
private:
int id;
string name;
public:
void setData(int id, string name) {
this->id = id; // 'this->id' = data member; 'id' = parameter
this->name = name;
}
Student& self() {
return *this; // return reference to current object
}
};
Why this exists
Every non-static member function receives a hidden first parameter: a pointer to the object on which it was called. Inside the function, this is that pointer.
s.setData(101, "Rohit");
// Compiler treats it as: setData(&s, 101, "Rohit");
// Inside: this == &s
Common uses of this
1. Disambiguating parameters from data members
void Student::setId(int id) {
this->id = id; // 'this->' clarifies that left side is member
}
2. Method chaining (fluent interface)
class Builder {
public:
Builder& setName(string n) { name = n; return *this; }
Builder& setAge(int a) { age = a; return *this; }
private:
string name;
int age;
};
Builder b;
b.setName("Rohit").setAge(20); // chain
3. Returning self from operators
A& A::operator=(const A& other) {
// copy logic
return *this;
}
4. Passing self to a function
class A {
public:
void method() {
external_function(this); // pass own address
}
};
Inside static functions
this does not exist in static functions — they have no associated object.
---
Friend Functions
A friend function is a non-member function that has been granted access to a class's private and protected members.
class Distance {
private:
int feet;
double inches;
public:
Distance(int f, double i) : feet(f), inches(i) {}
friend void displayDistance(Distance d); // declaration
};
void displayDistance(Distance d) {
cout << d.feet << " ft " << d.inches << " in" << endl;
// 'd.feet' and 'd.inches' are private — but accessible because friend
}
int main() {
Distance d(5, 6.5);
displayDistance(d);
return 0;
}
Characteristics of friend functions
- Declared inside the class with
friendkeyword - Defined like a regular function (not a member function)
- Has no
thispointer - Accesses private/protected members of the friend class
- Called like a regular function —
f(d), notd.f() - Friendship is not inherited or transitive
When to use friend functions
- Operator overloading for asymmetric operations (e.g.,
int + Distance) - Helper functions that need access to internals but logically aren't members
- Bridging two classes that need shared access
Disadvantages
- Breaks encapsulation — friend functions see private internals
- Use sparingly — overuse defeats the purpose of OOP
---
Friend Class
An entire class can be declared a friend, granting all its member functions access:
class Account; // forward declaration
class BankManager {
public:
void audit(Account& a);
};
class Account {
private:
double balance;
friend class BankManager; // BankManager has access to private
};
void BankManager::audit(Account& a) {
cout << "Balance: " << a.balance; // OK
}
Properties of friendship
- Friendship is granted, not taken — A declares B as friend
- Not symmetric — A friend of B does not mean B friend of A
- Not transitive — friend of friend is not automatically friend
- Not inherited — derived classes don't inherit friend relationships
---
Friend Member Function (a single member, not whole class)
class B;
class A {
public:
void access(B& b); // wants to access B's privates
};
class B {
private:
int data;
friend void A::access(B& b); // only this one member is friend
};
void A::access(B& b) {
cout << b.data; // OK
}
---
Member Function vs Friend Function — exam table
| Aspect | Member Function | Friend Function |
|---|---|---|
| Declared inside class | Yes | Yes (with friend) |
| Member of class | Yes | No |
Has this pointer | Yes | No |
| Called as | obj.func() | func(obj) |
| Access private members | Yes | Yes |
| Inherited | Yes | No |
| Can be virtual | Yes | No |
| Defined inside class? | Often | No (just declared) |
---
Putting It All Together — Counter Class
class Counter {
private:
int value;
static int totalCounters; // static — shared count
public:
Counter() : value(0) {
totalCounters++;
}
~Counter() {
totalCounters--;
}
void increment() { value++; }
Counter& reset() {
value = 0;
return *this; // return self — chaining
}
int getValue() const { return value; }
static int getTotal() { // static — no object needed
return totalCounters;
}
friend ostream& operator<<(ostream& os, const Counter& c);
};
int Counter::totalCounters = 0; // definition
ostream& operator<<(ostream& os, const Counter& c) {
os << "Counter: " << c.value; // accesses private via friend
return os;
}
int main() {
Counter c1, c2;
c1.increment(); c1.increment();
cout << c1 << endl; // Counter: 2
cout << "Total: " << Counter::getTotal(); // 2
return 0;
}
---
Study deep
- Static members live in the data segment, not on the heap or stack. They're initialised before
main()and destroyed after. The single definition outside the class allocates the storage.
thispointer is the difference between member and free function. In a sense,obj.f()is just syntactic sugar forf(&obj). The dot syntax makes the receiver explicit and enables OO design.
- Friend functions trade encapsulation for convenience. They're useful — especially for operator overloading where the left operand isn't your class. But every
frienddeclaration is a hole in your encapsulation; use sparingly.
- Static + const + integral = compile-time constant.
static const int MAX = 100;inside a class is a compile-time constant the compiler can inline. Modern alternative:static constexpr int MAX = 100;.
- **Method chaining via
return this.* A common modern idiom — builders, configurations, custom streams. The "fluent" style is more readable than separate statements.
Key Terms — Lesson 2.2
The terms below cover function overloading inside classes, static members, friends, and the this pointer — the dense core of Unit II.
Function Overloading (in Classes) — As with free functions, classes can have multiple member functions with the same name but different parameter lists. The compiler picks the right overload at the call site. Operator overloading (Unit III) is a special case of function overloading.
Static Data Member — A data member declared with static that belongs to the class itself, not to any individual object — all objects share the same copy. Used for counters, configuration, shared resources. Must be defined outside the class (int Counter::totalCounters = 0;) — the in-class declaration is not a definition.
Static Member Function — A member function declared with static that belongs to the class itself. Called via the class name (ClassName::method()) without needing an object. Has no this pointer and therefore cannot access non-static members directly.
this Pointer — An implicit pointer available inside every non-static member function, pointing to the object on which the function was called. Lets the function reference the current object's members and disambiguate them from parameters with the same name (this->id = id;).
**Self-Reference (this) — Dereferencing the this pointer gives the current object itself*. return *this; returns a reference to the current object, enabling method chaining (obj.reset().increment().display()).
Method Chaining / Fluent Interface — A design idiom where each method returns a reference to the same object, letting calls be chained on one line. The builder pattern, jQuery, LINQ, and many testing libraries use fluent interfaces.
Friend Function — A non-member function declared with the friend keyword inside a class, gaining access to the class's private and protected members. Friend functions are not methods (no this pointer, called like ordinary functions, no implicit object) but bypass access restrictions. Common use: overloading binary operators where the left operand is not the class.
Friend Class — An entire class declared as friend of another. Every member function of the friend class gains access to the host class's private and protected members. Useful for tightly-coupled class pairs (LinkedList and Node, Iterator and Container).
Mutual Friendship — Two classes that friend each other can each access the other's private members. Useful but indicates tight coupling — usually a signal that the design might be cleaner with a single class or composition.
Encapsulation vs Friendship — Friend declarations are deliberate holes in encapsulation. They're not a violation per se — the class itself controls who is a friend — but every friend declaration should be defensible. Modern advice: prefer member functions or public interface where possible.
Static vs Non-Static Members — Two member categories with different lifetimes and semantics. Non-static members are per-object — each object has its own copy, accessed via the object (obj.field). Static members are per-class — one copy shared across all objects, accessed via the class (Class::field).
Friend Function Characteristics — A friend function (1) is declared inside the class with friend keyword, (2) is not a member of the class, (3) has no this pointer, (4) is called as a free function (not on an object), (5) can access private and protected members of the host class, (6) is not inherited by derived classes.
mutable Keyword — A modifier that lets a data member be modified even inside a const member function. Used for caches, lazy initialisation counters, mutexes — members that don't logically affect the object's externally-visible state.
Stream Insertion via Friend — The classic friend-function use case: overloading operator<< for a custom class. Because the left operand is ostream (not your class), operator<< cannot be a member of your class — making it a friend gives it access to private members.
static const / static constexpr Member — A static data member that is also const or constexpr. static const int (and constexpr) can be initialised in-class if integral; static constexpr can be initialised in-class for any literal type. Used for compile-time class-level constants (Class::MAX_SIZE).
Class-Level vs Instance-Level Methods — A categorisation borrowed from Java/Python vocabulary that maps to static vs non-static member functions. Class-level (static) methods don't need an object and serve as utility functions tied to the class. Instance-level (non-static) methods operate on a specific object.
Operator Overloading (Preview) — Friend functions are commonly used to overload binary operators where the left operand is not the user's class — operator<< (for cout), operator+ between built-in types and user types, etc. Detailed in Unit III.
---
PYQ pattern (very common): "What is thethispointer? Explain with example." — Define as implicit pointer to current object; show disambiguation example; show method chaining; mention that static functions don't havethis.
PYQ pattern: "What is a friend function? List its characteristics." — Define; 5-6 characteristics (declared inside class, not member, no this, called as function, can access private, not inherited); compare with member function.
PYQ pattern: "Differentiate static and non-static member functions / data members." — Static = belongs to class, shared across objects, no this, accessible via ClassName::; non-static = per-object.