Skip to content

Module 00: C++ Fundamentals

Download Official Subject PDF

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

CC++
printf()std::cout <<
scanf()std::cin >>
malloc()/free()new/delete
struct (data only)class (data + behavior)
Functions operate on dataObjects have methods
// FORBIDDEN - will get you 0
printf("Hello"); // Use std::cout instead
malloc(sizeof(int)); // Use new instead
free(ptr); // Use delete instead
// FORBIDDEN - will get you -42
using namespace std; // Must prefix with std::

Namespaces prevent naming collisions. In large projects, two libraries might define a function with the same name.

// Without namespaces - collision!
void print(); // Library A
void print(); // Library B - ERROR!
// With namespaces - no collision
namespace LibraryA {
void print();
}
namespace LibraryB {
void print();
}
// Usage
LibraryA::print();
LibraryB::print();

Everything from the C++ standard library lives in std:

std::cout // output stream
std::cin // input stream
std::cerr // error stream
std::string // string class
std::endl // newline + flush
std::cout // cout from std namespace
::globalFunction() // function from global namespace (no namespace)
ClassName::method // method from ClassName

#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;
}
#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;
}
// PROBLEM: mixing cin >> and getline
int age;
std::string name;
std::cin >> age; // Leaves '\n' in buffer
std::getline(std::cin, name); // Reads empty line!
// SOLUTION: clear the buffer
std::cin >> age;
std::cin.ignore(); // Ignore the leftover '\n'
std::getline(std::cin, name);
#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;
}

// 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 automatically
#include <string>
std::string s = "Hello";
// Length
s.length(); // 5
s.size(); // 5 (same thing)
// Access characters
s[0]; // 'H'
s.at(0); // 'H' (with bounds checking)
// Concatenation
s + " World"; // "Hello World"
s.append(" World"); // Modifies s
// Comparison
s == "Hello"; // true
s < "World"; // true (lexicographic)
// Substrings
s.substr(0, 3); // "Hel"
s.substr(2); // "llo"
// Find
s.find("ll"); // 2 (index)
s.find("xyz"); // std::string::npos (not found)
// Replace (but remember: forbidden in ex04!)
s.replace(0, 2, "YY"); // "YYllo"
// Clear
s.empty(); // false
s.clear(); // s is now ""
std::string s = "Hello";
// Index-based
for (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) { } // FORBIDDEN

Contact.hpp
#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
Contact.cpp
#include "Contact.hpp"
#include <iostream>
// Constructor implementation
Contact::Contact() {
std::cout << "Contact created" << std::endl;
}
// Destructor implementation
Contact::~Contact() {
std::cout << "Contact destroyed" << std::endl;
}
// Setter
void Contact::setFirstName(std::string name) {
this->_firstName = name;
}
// Getter (const - doesn't modify object)
std::string Contact::getFirstName() const {
return this->_firstName;
}
// Display method
void Contact::display() const {
std::cout << "Name: " << _firstName << " " << _lastName << std::endl;
}
SpecifierAccess
privateOnly accessible within the class
publicAccessible from anywhere
protectedAccessible in class and derived classes

Rule of thumb: Make attributes private, provide public getters/setters.

class Example {
private:
int value;
public:
void setValue(int value) {
// 'value' refers to parameter
// 'this->value' refers to member
this->value = value;
}
};
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; }
};

class MyClass {
public:
MyClass() {
std::cout << "Default constructor called" << std::endl;
}
};
// Usage
MyClass obj; // Calls default constructor
class Contact {
private:
std::string _name;
int _age;
public:
Contact(std::string name, int age) {
_name = name;
_age = age;
}
};
// Usage
Contact c("John", 25);
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?

  1. More efficient (no default construction + assignment)
  2. Required for const members
  3. Required for reference members
  4. 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) {}
};
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;
}
};

Shared across ALL instances of a class.

// Header
class 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
// Usage
Counter a;
Counter b;
Counter c;
std::cout << Counter::getCount(); // 3

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 needed
int result = Math::add(5, 3);

const int MAX = 100; // Cannot be modified
MAX = 200; // ERROR!
void print(const std::string& s) {
// s cannot be modified
// Passed by reference (efficient, no copy)
std::cout << s << std::endl;
}
class Example {
public:
int getValue() const { // Promises not to modify object
return _value;
}
};
class Example {
private:
std::string _name;
public:
// Returns const reference - caller cannot modify
const std::string& getName() const {
return _name;
}
};

Every header file MUST have include guards to prevent double inclusion:

Contact.hpp
#ifndef CONTACT_HPP
#define CONTACT_HPP
class Contact {
// ...
};
#endif

Why?

// 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, skipped

NAME = program
CXX = c++
CXXFLAGS = -Wall -Wextra -Werror -std=c++98
SRCS = main.cpp Contact.cpp PhoneBook.cpp
OBJS = $(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 re

TaskCC++
Printprintf("x=%d\n", x);std::cout << "x=" << x << std::endl;
Read intscanf("%d", &x);std::cin >> x;
Read linefgets(buf, size, stdin);std::getline(std::cin, str);
Allocatemalloc(n * sizeof(int))new int[n]
Freefree(ptr)delete[] ptr
Stringchar str[100]std::string str
String lengthstrlen(str)str.length()
String copystrcpy(dst, src)dst = src
String comparestrcmp(a, b) == 0a == b

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 EOF
while (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;
}
#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
}

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++;
}
};
int index = 0;
int size = 8;
index = (index + 1) % size; // 0 -> 1
index = (index + 1) % size; // 1 -> 2
// ... after 7:
index = (index + 1) % size; // 7 -> 0 (wraps around!)

  1. Using using namespace std; - Forbidden at 42
  2. Forgetting include guards - Causes compilation errors
  3. Putting implementation in headers - Grade 0 (except templates)
  4. Not ending output with newline - Required by subject
  5. Using printf/scanf - Forbidden at 42
  6. Forgetting const on getters - Bad practice
  7. Not initializing members - Undefined behavior
  8. Memory leaks - Always pair new with delete