Module 00: C++ Fundamentals
Key Concepts:
- Namespaces
- Classes and Objects
- Member Functions (methods)
- Access Specifiers (public/private)
- Constructors and Destructors
- iostream (cout, cin, cerr)
- std::string
- Initialization Lists
- static and const keywords
Understanding C++ Operators (For Complete Beginners)
Section titled “Understanding C++ Operators (For Complete Beginners)”Before diving into C++ code, let’s understand the operators you’ll see throughout this module:
The << Operator (Stream Insertion)
Section titled “The << Operator (Stream Insertion)”std::cout << "Hello" << 42 << std::endl;<<is called the “stream insertion operator” or “output operator”- It inserts data into an output stream (like
std::cout, which stands for “character output”) - Think of it as an arrow pointing in the direction of data flow: data flows FROM the variables TO the output
- You can chain multiple
<<operators together to output multiple values std::endlinserts a newline and flushes the buffer
The >> Operator (Stream Extraction)
Section titled “The >> Operator (Stream Extraction)”std::cin >> number;>>is called the “stream extraction operator” or “input operator”- It extracts data from an input stream (like
std::cin, which stands for “character input”) - Think of it as an arrow pointing in the direction of data flow: data flows FROM the input TO the variable
The :: Operator (Scope Resolution)
Section titled “The :: Operator (Scope Resolution)”std::cout // Access cout from the std namespaceClassName::method // Access method from ClassName::is the “scope resolution operator”- It tells the compiler WHERE to look for a name (variable, function, class)
std::coutmeans “use thecoutthat belongs to thestdnamespace”- This prevents naming conflicts when different libraries use the same names
The . Operator (Member Access)
Section titled “The . Operator (Member Access)”object.method() // Access method of an objectobject.attribute // Access attribute of an object.is the “member access operator” or “dot operator”- It accesses members (methods or attributes) of an object
- Use this when you have an actual object (not a pointer)
The -> Operator (Pointer Member Access)
Section titled “The -> Operator (Pointer Member Access)”pointer->method() // Same as (*pointer).method()pointer->attribute // Same as (*pointer).attribute->is the “arrow operator” or “pointer member access operator”- It’s a shortcut for dereferencing a pointer AND accessing a member
pointer->method()is exactly the same as(*pointer).method()- Use this when you have a pointer to an object
The & Operator (Address-of)
Section titled “The & Operator (Address-of)”int* ptr = &x; // ptr stores the memory address of x&before a variable gives you its memory address- This is how you get a pointer to a variable
- Don’t confuse this with
&in declarations (which creates a reference)
The * Operator (Dereference)
Section titled “The * Operator (Dereference)”*ptr = 42; // Store 42 at the address ptr points toint value = *ptr; // Get the value stored at ptr*before a pointer “dereferences” it (accesses the value at that address)- It follows the pointer to the actual data stored in memory
1. From C to C++: The Mindset Shift
Section titled “1. From C to C++: The Mindset Shift”What Changes?
Section titled “What Changes?”| C | C++ |
|---|---|
printf() | std::cout << |
scanf() | std::cin >> |
malloc()/free() | new/delete |
struct (data only) | class (data + behavior) |
| Functions operate on data | Objects have methods |
The Forbidden List (42 Rules)
Section titled “The Forbidden List (42 Rules)”// FORBIDDEN - will get you 0printf("Hello"); // Use std::cout insteadmalloc(sizeof(int)); // Use new insteadfree(ptr); // Use delete instead
// FORBIDDEN - will get you -42using namespace std; // Must prefix with std::2. Namespaces
Section titled “2. Namespaces”Why Namespaces Exist
Section titled “Why Namespaces Exist”Namespaces solve two problems:
1. Name collisions: In large projects, two libraries might define a function with the same name.
// Without namespaces - collision!void print(); // Library Avoid print(); // Library B - ERROR!
// With namespaces - no collisionnamespace LibraryA { void print();}namespace LibraryB { void print();}
// UsageLibraryA::print();LibraryB::print();2. Code organization: Namespaces let you group related symbols semantically across multiple files. Unlike C where organization is file-based, namespaces let you organize by meaning. A namespace can span many files, and related functions stay together logically even when physically separated.
The std Namespace
Section titled “The std Namespace”Everything from the C++ standard library lives in std:
std::cout // output streamstd::cin // input streamstd::cerr // error streamstd::string // string classstd::endl // newline + flushThe :: Operator (Scope Resolution)
Section titled “The :: Operator (Scope Resolution)”std::cout // cout from std namespace::globalFunction() // function from global namespace (no namespace)ClassName::method // method from ClassName3. iostream: Input/Output Streams
Section titled “3. iostream: Input/Output Streams”Basic Output with cout
Section titled “Basic Output with cout”#include <iostream>
int main() { std::cout << "Hello, World!" << std::endl;
int x = 42; std::cout << "The answer is " << x << std::endl;
// Chaining multiple values std::cout << "a=" << 1 << ", b=" << 2 << std::endl;
return 0;}Basic Input with cin
Section titled “Basic Input with cin”#include <iostream>#include <string>
int main() { int number; std::cout << "Enter a number: "; std::cin >> number;
std::string name; std::cout << "Enter your name: "; std::cin >> name; // Only reads until whitespace!
// For full line input: std::getline(std::cin, name);
return 0;}Important: cin quirks
Section titled “Important: cin quirks”// PROBLEM: mixing cin >> and getlineint age;std::string name;
std::cin >> age; // Leaves '\n' in bufferstd::getline(std::cin, name); // Reads empty line!
// SOLUTION: clear the bufferstd::cin >> age;std::cin.ignore(); // Ignore the leftover '\n'std::getline(std::cin, name);Output Formatting with iomanip
Section titled “Output Formatting with iomanip”#include <iostream>#include <iomanip>
int main() { // Set field width std::cout << std::setw(10) << "Hello" << std::endl; // " Hello"
// Right/left alignment std::cout << std::right << std::setw(10) << "Hi" << std::endl; // " Hi" std::cout << std::left << std::setw(10) << "Hi" << std::endl; // "Hi "
// Fill character std::cout << std::setfill('.') << std::setw(10) << "Hi" << std::endl; // "........Hi"
return 0;}4. std::string
Section titled “4. std::string”Why std::string over char*?
Section titled “Why std::string over char*?”// C-style (dangerous, manual memory)char* str = (char*)malloc(100);strcpy(str, "Hello");// Must remember to free!
// C++ style (safe, automatic)std::string str = "Hello";// Memory managed automaticallyBasic Operations
Section titled “Basic Operations”#include <string>
std::string s = "Hello";
// Lengths.length(); // 5s.size(); // 5 (same thing)
// Access characterss[0]; // 'H's.at(0); // 'H' (with bounds checking)
// Concatenations + " World"; // "Hello World"s.append(" World"); // Modifies s
// Comparisons == "Hello"; // trues < "World"; // true (lexicographic)
// Substringss.substr(0, 3); // "Hel"s.substr(2); // "llo"
// Finds.find("ll"); // 2 (index)s.find("xyz"); // std::string::npos (not found)
// Replace (but remember: forbidden in ex04!)s.replace(0, 2, "YY"); // "YYllo"
// Clears.empty(); // falses.clear(); // s is now ""Iteration
Section titled “Iteration”std::string s = "Hello";
// Index-basedfor (size_t i = 0; i < s.length(); i++) { std::cout << s[i];}
// C++98 doesn't have range-based for loops!// This is C++11: for (char c : s) { } // FORBIDDEN5. Classes and Objects
Section titled “5. Classes and Objects”Class vs Struct: What’s the Difference?
Section titled “Class vs Struct: What’s the Difference?”In C++, both class and struct can have member variables and functions. The only difference is the default access specifier:
| Feature | class | struct |
|---|---|---|
| Default access | private | public |
| Default inheritance | private | public |
| Members accessible? | Only inside class | From anywhere |
Practical Example:
class MyClass { int x; // PRIVATE by default - only accessible inside class void foo(); // PRIVATE by default};
struct MyStruct { int x; // PUBLIC by default - accessible from anywhere void foo(); // PUBLIC by default};
MyClass c;c.x = 5; // ERROR: x is private!
MyStruct s;s.x = 5; // OK: x is publicWhen to use each:
- Use
classwhen you need encapsulation (hide implementation) - Use
structfor simple data structures (like C structs) - In practice, both work the same - it’s about convention
Visual Memory Layout:
MyClass object: MyStruct object:+-------------+ +-------------+| _firstName | | _firstName | <-- All members| _lastName | | _lastName | are accessible| _phone | | _phone |+-------------+ +-------------+ (private) (public)Basic Class Structure
Section titled “Basic Class Structure”#ifndef CONTACT_HPP#define CONTACT_HPP
#include <string>
class Contact {private: // Attributes (data members) std::string _firstName; std::string _lastName; std::string _phoneNumber;
public: // Constructor Contact();
// Destructor ~Contact();
// Member functions (methods) void setFirstName(std::string name); std::string getFirstName() const; void display() const;};
#endif#include "Contact.hpp"#include <iostream>
// Constructor implementationContact::Contact() { std::cout << "Contact created" << std::endl;}
// Destructor implementationContact::~Contact() { std::cout << "Contact destroyed" << std::endl;}
// Settervoid Contact::setFirstName(std::string name) { this->_firstName = name;}
// Getter (const - doesn't modify object)std::string Contact::getFirstName() const { return this->_firstName;}
// Display methodvoid Contact::display() const { std::cout << "Name: " << _firstName << " " << _lastName << std::endl;}Access Specifiers
Section titled “Access Specifiers”| Specifier | Access |
|---|---|
private | Only accessible within the class |
public | Accessible from anywhere |
protected | Accessible in class and derived classes |
Rule of thumb: Make attributes private, provide public getters/setters.
The this Pointer
Section titled “The this Pointer”Every non-static member function has access to a special pointer called this. It points to the current instance - the object on which the method was called. This is how member functions know which object’s data to access.
class Example {private: int value;
public: void setValue(int value) { // 'value' refers to parameter // 'this->value' refers to member this->value = value; }
// this is implicit - these two are equivalent: int getValue() { return value; } int getValue() { return this->value; }};Why this matters: When you call obj.setValue(42), the compiler passes &obj as a hidden first argument. Inside the function, this == &obj.
const Member Functions
Section titled “const Member Functions”class Example {private: int _value;
public: // Can modify object void setValue(int v) { _value = v; }
// Cannot modify object (const at the end) int getValue() const { return _value; }};6. Constructors and Destructors
Section titled “6. Constructors and Destructors”Default Constructor
Section titled “Default Constructor”class MyClass {public: MyClass() { std::cout << "Default constructor called" << std::endl; }};
// UsageMyClass obj; // Calls default constructorParameterized Constructor
Section titled “Parameterized Constructor”class Contact {private: std::string _name; int _age;
public: Contact(std::string name, int age) { _name = name; _age = age; }};
// UsageContact c("John", 25);Initialization Lists (IMPORTANT!)
Section titled “Initialization Lists (IMPORTANT!)”class Contact {private: std::string _name; int _age;
public: // WITHOUT initialization list (assignment in body) Contact(std::string name, int age) { _name = name; // First default-constructed, then assigned _age = age; }
// WITH initialization list (direct initialization) Contact(std::string name, int age) : _name(name), _age(age) { // Members initialized before body executes }};Why use initialization lists?
-
More efficient: Without init list, members are default-constructed THEN assigned (2 operations). With init list, members are directly initialized (1 operation).
// WITHOUT init list - TWO operations per member:Contact(std::string name) {// 1. _name is default-constructed (empty string)// 2. _name is assigned the value of 'name'_name = name;}// WITH init list - ONE operation per member:Contact(std::string name) : _name(name) {// _name is directly constructed with 'name'} -
Required for
constmembers (can’t assign to const after construction) -
Required for reference members (must be bound at initialization)
-
Required for members without default constructors
class Example {private: const int _id; // MUST use init list std::string& _ref; // MUST use init list
public: // This is the ONLY way: Example(int id, std::string& ref) : _id(id), _ref(ref) {}};Destructor
Section titled “Destructor”class FileHandler {private: int* _data;
public: FileHandler() { _data = new int[100]; // Allocate }
~FileHandler() { delete[] _data; // Clean up std::cout << "FileHandler destroyed, memory freed" << std::endl; }};7. Static Members
Section titled “7. Static Members”Static Attributes
Section titled “Static Attributes”Shared across ALL instances of a class.
// Headerclass Counter {private: static int _count; // Declaration
public: Counter() { _count++; } ~Counter() { _count--; } static int getCount() { return _count; }};
// Source (MUST define outside class)int Counter::_count = 0; // Definition + initialization
// UsageCounter a;Counter b;Counter c;std::cout << Counter::getCount(); // 3Static Member Functions
Section titled “Static Member Functions”Can be called without an object. Cannot access non-static members.
class Math {public: static int add(int a, int b) { return a + b; }};
// Usage - no object neededint result = Math::add(5, 3);8. const Keyword
Section titled “8. const Keyword”Design Philosophy: const is more than a language feature - it’s a discipline for writing correct code. By marking everything that shouldn’t change as const, you:
- Catch bugs at compile time (accidental modifications)
- Document intent (readers know what won’t change)
- Enable compiler optimizations
- Make code easier to reason about in complex systems
Rule of thumb: Use const by default. Only remove it when you need to modify something.
const Variables
Section titled “const Variables”const int MAX = 100; // Cannot be modifiedMAX = 200; // ERROR!const Parameters
Section titled “const Parameters”void print(const std::string& s) { // s cannot be modified // Passed by reference (efficient, no copy) std::cout << s << std::endl;}const Member Functions
Section titled “const Member Functions”class Example {public: int getValue() const { // Promises not to modify object return _value; }};const Return Values
Section titled “const Return Values”class Example {private: std::string _name;
public: // Returns const reference - caller cannot modify const std::string& getName() const { return _name; }};9. Include Guards
Section titled “9. Include Guards”Every header file MUST have include guards to prevent double inclusion:
#ifndef CONTACT_HPP#define CONTACT_HPP
class Contact { // ...};
#endifWhy?
// Without guards:#include "Contact.hpp"#include "Contact.hpp" // ERROR: Contact redefined!
// With guards:#include "Contact.hpp" // Defines CONTACT_HPP, includes class#include "Contact.hpp" // CONTACT_HPP already defined, skipped10. Compilation
Section titled “10. Compilation”Makefile Basics for C++
Section titled “Makefile Basics for C++”NAME = programCXX = c++CXXFLAGS = -Wall -Wextra -Werror -std=c++98
SRCS = main.cpp Contact.cpp PhoneBook.cppOBJS = $(SRCS:.cpp=.o)
all: $(NAME)
$(NAME): $(OBJS) $(CXX) $(CXXFLAGS) -o $(NAME) $(OBJS)
%.o: %.cpp $(CXX) $(CXXFLAGS) -c $< -o $@
clean: rm -f $(OBJS)
fclean: clean rm -f $(NAME)
re: fclean all
.PHONY: all clean fclean reQuick Reference: C to C++ Translation
Section titled “Quick Reference: C to C++ Translation”| Task | C | C++ |
|---|---|---|
printf("x=%d\n", x); | std::cout << "x=" << x << std::endl; | |
| Read int | scanf("%d", &x); | std::cin >> x; |
| Read line | fgets(buf, size, stdin); | std::getline(std::cin, str); |
| Allocate | malloc(n * sizeof(int)) | new int[n] |
| Free | free(ptr) | delete[] ptr |
| String | char str[100] | std::string str |
| String length | strlen(str) | str.length() |
| String copy | strcpy(dst, src) | dst = src |
| String compare | strcmp(a, b) == 0 | a == b |
11. EOF Handling with std::getline
Section titled “11. EOF Handling with std::getline”When reading input in a loop, you need to handle EOF (Ctrl+D on Unix, Ctrl+Z on Windows):
std::string line;
// std::getline returns the stream, which converts to false on EOFwhile (std::getline(std::cin, line)) { // Process line std::cout << "Got: " << line << std::endl;}// Loop exits when EOF is reached
// You can also check explicitly:if (std::cin.eof()) { std::cout << "End of input reached" << std::endl;}Graceful Exit on EOF
Section titled “Graceful Exit on EOF”#include <cstdlib> // for std::exit
std::string input;std::cout << "Enter value: ";if (!std::getline(std::cin, input)) { std::cout << std::endl; // Print newline for clean output std::exit(0); // Exit program gracefully}12. Circular Buffer Pattern
Section titled “12. Circular Buffer Pattern”When you need a fixed-size collection where new items replace the oldest:
class PhoneBook {private: Contact _contacts[8]; // Fixed size array int _index; // Next position to write int _count; // Total contacts stored
public: PhoneBook() : _index(0), _count(0) {}
void addContact(const Contact& c) { _contacts[_index] = c;
// Wrap around using modulo _index = (_index + 1) % 8; // 0,1,2,3,4,5,6,7,0,1,2...
// Track count up to max if (_count < 8) _count++; }};How Modulo Wrapping Works
Section titled “How Modulo Wrapping Works”int index = 0;int size = 8;
index = (index + 1) % size; // 0 -> 1index = (index + 1) % size; // 1 -> 2// ... after 7:index = (index + 1) % size; // 7 -> 0 (wraps around!)13. Pointers to Members
Section titled “13. Pointers to Members”C++ extends the pointer concept to allow pointers to class members (both attributes and member functions). This is different from regular pointers.
Pointer to Member Attribute
Section titled “Pointer to Member Attribute”class Sample {public: int value;};
// Pointer to member attributeint Sample::*ptr = &Sample::value;
// Usage - need an instance to dereferenceSample s;s.value = 42;std::cout << s.*ptr << std::endl; // Prints 42
Sample* sp = &s;std::cout << sp->*ptr << std::endl; // Also prints 42Pointer to Member Function
Section titled “Pointer to Member Function”class Sample {public: void display() { std::cout << "Hello" << std::endl; } void greet(std::string name) { std::cout << "Hi " << name << std::endl; }};
// Pointer to member function (no parameters)void (Sample::*funcPtr)() = &Sample::display;
// UsageSample s;(s.*funcPtr)(); // Calls s.display()
Sample* sp = &s;(sp->*funcPtr)(); // Also calls display()
// Pointer to member function with parametersvoid (Sample::*greetPtr)(std::string) = &Sample::greet;(s.*greetPtr)("World"); // Calls s.greet("World")Why Pointers to Members?
Section titled “Why Pointers to Members?”- Callbacks: Select which member function to call at runtime
- Data-driven design: Access different attributes based on configuration
- Generic algorithms: Write functions that work on any member
Common Mistakes to Avoid
Section titled “Common Mistakes to Avoid”- Using
using namespace std;- Forbidden at 42 - Forgetting include guards - Causes compilation errors
- Putting implementation in headers - Grade 0 (except templates)
- Not ending output with newline - Required by subject
- Using printf/scanf - Forbidden at 42
- Forgetting
conston getters - Bad practice - Not initializing members - Undefined behavior
- Memory leaks - Always pair
newwithdelete