Unit 1: C++ Programming Basics and Functions
1. Executive Summary & Overview
C++ is a multi-paradigm, statically typed, compiled programming language originally conceived by Bjarne Stroustrup as "C with Classes" at Bell Laboratories. By marrying the raw hardware execution speed and memory manipulation capabilities of C with high-level object-oriented and generic abstractions, C++ serves as the bedrock for modern systems engineering, game engines, embedded systems, and high-performance financial infrastructure. This unit establishes the core computational foundations of C++: the transition from Procedural Oriented Programming (POP) to Object-Oriented Programming (OOP), the anatomy of classes and objects, access specifiers, static members, friendship relationships, stream-based input/output via <iostream> and <iomanip>, reference semantics, and advanced function mechanics including function overloading, default arguments, inline expansion, and recursion.
2. The Object-Oriented Paradigm vs. Procedural Programming
Before the emergence of OOP, software systems predominantly followed Procedural Oriented Programming (POP), as exemplified by C, Pascal, and Fortran.
CODE+--------------------------------------------------------------------------+ | PROCEDURAL ORIENTED (POP) OBJECT-ORIENTED (OOP) | +--------------------------------------------------------------------------+ | Focus: Algorithms & Actions Focus: Data Entities & State | | Structure: Monolithic functions Structure: Classes & Encapsulated | | operating on global data Objects | | Data Security: Vulnerable; functions Data Security: High; data hidden | | share global state via private access | | Approach: Top-Down design Approach: Bottom-Up composition | | Maintenance: High coupling causes Maintenance: Low coupling; modular | | cascading bug ripple polymorphic extension | +--------------------------------------------------------------------------+
The Four Pillars of Object-Oriented Programming:
- Encapsulation: The bundling of data attributes and the member functions that manipulate them into a single cohesive unit (
class), shielding internal representations from unauthorized external tampering. - Data Abstraction: Exposing only the essential interface mechanisms to the outside world while concealing low-level implementation complexities.
- Inheritance: The mechanism by which a derived child class inherits fields and behaviors from an existing base class, enabling hierarchical classification and code reuse.
- Polymorphism: The ability of a message, operator, or function call to exhibit different behaviors depending on the context or dynamic type of the target object (static/compile-time vs. dynamic/runtime polymorphism).
3. C++ Compilation Pipeline & Namespaces
A C++ source file (.cpp) undergoes four discrete transformation stages before becoming an executable binary:
CODE[ Source: .cpp ] ---> [ 1. Preprocessor: g++ -E ] ---> Expanded Code (macros expanded, headers included) | v [ 2. Compiler: g++ -S ] ---> Assembly Code (.s) | v [ 3. Assembler: g++ -c ] ---> Relocatable Object File (.o / .obj) | v [ 4. Linker: ld ] ---> Executable Binary (.exe / a.out) (Links external libs & symbols)
Namespaces and the std Scope
Namespaces prevent identifier collisions across large-scale software libraries.
cppnamespace MathEngine {
double calculateArea(double radius) { return 3.14159 * radius * radius; }
}
namespace GraphicEngine {
void calculateArea() { /* Renders screen area */ }
}
// Scope resolution operator (::) specifies exact symbol context:
double r = MathEngine::calculateArea(5.0);
Best Practice: Avoid placing using namespace std; in header files (.h / .hpp), as it pollutes the global namespace for all translation units that include that header.
4. Classes, Objects, and Encapsulated Data Types
A class is a user-defined blueprint or user-defined type, whereas an object is an instantiated, concrete variable of that class occupying real memory in the runtime stack or heap.
cppclass BankAccount {
private:
std::string accountNumber; // Private data member (hidden)
double balance;
public:
// Member function declared inside, defined inside (implicit inline)
void deposit(double amount) {
if (amount > 0) balance += amount;
}
// Member function declared inside, defined outside via scope resolution
bool withdraw(double amount);
// Const-qualified getter: promises not to mutate object state
double getBalance() const { return balance; }
};
// Definition outside class using scope resolution operator (::)
bool BankAccount::withdraw(double amount) {
if (amount > 0 && balance >= amount) {
balance -= amount;
return true;
}
return false;
}
Member Access Specifiers:
private: Accessible only by member functions and declaredfriendfunctions/classes of the containing class. (Default specifier forclass).public: Accessible by any function anywhere in the program where the object is in scope.protected: Accessible within the containing class and any derived (subclassed) classes, but private to external clients.
Comparing class, struct, union, and enum class:
| Construct | Default Member Access | Default Inheritance Access | Memory Allocation Strategy | Primary Purpose |
|---|---|---|---|---|
class | private | private | Contiguous sum of all member fields (plus alignment padding) | Encapsulated OOP with state invariants |
struct | public | public | Contiguous sum of all member fields | Plain Data Aggregates (POD / DTOs) |
union | public | N/A (cannot inherit) | Overlapped storage; size equals largest member | Memory conservation; mutually exclusive variants |
enum class | N/A | N/A | Underlying integral type (e.g., int, uint8_t) | Strongly typed, scoped enumeration constants |
5. Advanced Class Mechanisms: Static Members and Friendship
A. Static Data Members and Member Functions
A static data member is a class-level variable shared by all instances of that class. It does not occupy space inside individual object instances; it resides in the static/global data segment.
cppclass ServerConnection {
private:
int socketId;
static int activeConnections; // Declaration only
public:
ServerConnection(int id) : socketId(id) { activeConnections++; }
~ServerConnection() { activeConnections--; }
// Static member function: lacks a 'this' pointer; can only touch static members
static int getActiveCount() {
return activeConnections;
}
};
// Mandatory external definition in file scope (prior to C++17 inline static)
int ServerConnection::activeConnections = 0;
// Invocation without creating an object instance:
int count = ServerConnection::getActiveCount();
B. Friend Functions and Friend Classes
The friend keyword allows external non-member functions or other classes to access the private and protected internals of a class.
cppclass Matrix; // Forward declaration
class Vector {
private:
float coordinates[4];
public:
// Declare external function as a friend
friend Vector multiply(const Matrix& m, const Vector& v);
// Declare an entire external class as a friend
friend class GraphicsPipeline;
};
Key Properties of Friendship:
- Not Symmetric: If class
Adeclares classBas a friend,Bcan accessA's privates, butAcannot accessB's privates unless explicitly granted. - Not Transitive: If
AfriendsB, andBfriendsC,Cdoes not automatically receive access toA. - Not Inherited: Friendship is not passed down to derived child classes.
6. Stream-Based Input/Output and Manipulators
C++ replaces C's weakly typed printf and scanf with strongly typed, type-safe streams defined in <iostream>.
CODE[ ios_base ] | [ ios ] / [ istream ] [ ostream ] \ / \ / [ iostream ]
Core Stream Objects:
std::cin: Standard input stream (buffered, tied to standard input).std::cout: Standard output stream (buffered, normal program output).std::cerr: Standard error stream (unbuffered, guarantees immediate flushing for critical crash/error diagnostics).std::clog: Standard logging stream (buffered, for general execution tracking).
Stream State Flags & Error Recovery:
Streams maintain internal bitmask state flags:
good(): Next operation may succeed; no error flags set.eof(): Reached End-of-File marker.fail(): Logical conversion error (e.g., trying to read alphabetic characters into anint).bad(): Irrecoverable hardware/stream integrity error.
cppint age;
std::cout << "Enter age: ";
if (!(std::cin >> age)) {
// Stream entered fail state
std::cin.clear(); // Reset state flags back to goodbit
std::cin.ignore(10000, '
'); // Purge faulty characters up to newline
std::cerr << "Invalid integer input. Stream cleared.
";
}
Stream Manipulators (<iomanip>):
Manipulators alter stream formatting states:
- Unparameterized:
std::endl(writesAND forces a stream flush),std::boolalpha(printstrue/false),std::hex,std::dec. - Parameterized (
<iomanip>):std::setw(int n)(applies only to the immediate next field),std::setprecision(int n),std::setfill(char c),std::fixed.
cpp#include <iomanip>
std::cout << std::fixed << std::setprecision(2);
std::cout << "$" << std::setw(8) << std::setfill('0') << 42.5;
// Output: $00042.50
7. Function Mechanics: Overloading, Defaults, References, and Inlining
A. Reference Variables
A reference (Type&) is an immutable alias or alternative name for an existing, initialized variable. Once bound at initialization, it cannot be reseated to point to another object.
- Pointers vs. References:
- References cannot be null (must bind to valid storage).
- References do not require dereferencing operators (
*or->). - References cannot be uninitialized.
cppint x = 100;
int& refX = x; // refX is an alias for x
refX = 250; // x becomes 250
const int& constRef = 500; // Const reference can bind to an rvalue temporary!
B. Parameter Passing Semantics: Value vs. Address vs. Reference
cpp// 1. Call by Value: Copies argument into new local variable; expensive for large structs
void mutateValue(int a) { a += 10; }
// 2. Call by Address (Pointer): Passes memory address; allows nullptr; requires explicit dereferencing
void mutatePointer(int* p) {
if (p) *p += 10;
}
// 3. Call by Reference: Passes alias to caller's object; zero copy overhead; clean syntax
void mutateReference(int& r) { r += 10; }
// 4. Pass by Const Reference: Idiomatic C++ for non-primitive inputs (zero copy + read-only safety)
void printData(const std::string& str) { std::cout << str << '
'; }
C. Function Overloading & Resolution Rules
C++ permits multiple functions to share the identical identifier within the same scope, provided their parameter lists differ in type, count, or order.
- Return Type Invariance: Changing only the return type cannot overload a function (e.g.,
int compute()anddouble compute()trigger a compiler collision). - Overload Resolution Steps:
- Exact match (trivial conversions like array-to-pointer or adding
const). - Promotion (e.g.,
char/shorttoint,floattodouble). - Standard conversion (e.g.,
inttodouble, derived-pointer to base-pointer). - User-defined conversions (constructors / conversion operators).
- Ellipsis (
...) match.
- Exact match (trivial conversions like array-to-pointer or adding
D. Default Arguments
Default parameter values are substituted by the compiler at the call site if omitted by the caller:
- Trailing Rule: Default parameters must be specified from right-to-left; once a parameter receives a default, all subsequent parameters to its right must also have defaults.
- Declaration Rule: Defaults must typically be specified in the function declaration (header file), not repeated in the definition.
cpp// Valid:
void configureNetwork(int port, int timeoutMs = 5000, bool enableSSL = true);
// Invalid (violates trailing rule):
// void configureNetwork(int port = 8080, int timeoutMs);
E. Inline Functions
Declared with the inline keyword, requesting that the compiler substitute the function's machine instructions directly at the call site rather than executing a traditional call jump instruction (avoiding stack frame setup and register saving).
- Compiler Authority: The compiler treats
inlineas a hint, not a command. It will ignore inlining for recursive functions, large functions, or functions containing complex loops/switches. - Advantage Over C Preprocessor Macros: Unlike
#define SQUARE(x) ((x)*(x)), inline functions adhere to proper C++ type safety, scoping rules, and evaluate arguments exactly once, avoiding dangerous side effects (e.g.,SQUARE(x++)).
8. Summary & Key Review Takeaways
- OOP organizes software around encapsulated data objects rather than decoupled procedural algorithms.
classmembers are private by default;structmembers are public by default.- Static member variables represent class-wide state and must be initialized outside the class body at file scope.
frienddeclarations grant external access, but violate strict encapsulation and are non-symmetric, non-transitive, and non-inherited.- Streams (
<iostream>) provide type-safe, extensible I/O;std::cerris unbuffered for immediate error reporting, whilestd::coutis buffered. - References act as permanent aliases; passing by
const Type&is the canonical C++ idiom for efficient, immutable object passing. - Function overloading requires distinct parameter signatures; return types are ignored during overload resolution.