C++ is a general-purpose programming language developed by Bjarne Stroustrup as an extension of C. It supports both procedural and object-oriented programming (OOP) paradigms, making it versatile.
Feature | C | C++ |
---|---|---|
Paradigm | Procedural | Procedural + OOP |
Data Security | No encapsulation | Encapsulation via classes |
Function Overloading | Not supported | Supported |
Polymorphism | Not supported | Supported |
// C: Procedural Programming
#include <stdio.h>
void printMessage() {
printf("Hello, World!");
}
// C++: Object-Oriented
#include <iostream>
using namespace std;
class Message {
public:
void printMessage() {
cout << "Hello, World!" << endl;
}
};
The four main OOP concepts in C++ are:
#include <iostream>
using namespace std;
class Animal {
public:
virtual void sound() { // Polymorphism (runtime)
cout << "Animal makes a sound" << endl;
}
};
class Dog : public Animal { // Inheritance
public:
void sound() override {
cout << "Dog barks" << endl;
}
};
int main() {
Animal* a = new Dog();
a->sound(); // Output: Dog barks
delete a;
}
In C++:
struct Point {
int x, y; // Public by default
};
class Circle {
private:
int radius; // Private by default
public:
Circle(int r) : radius(r) {}
int getRadius() { return radius; }
};
A virtual function is a member function in a base class that you expect to override in derived classes. It enables runtime polymorphism.
#include <iostream>
using namespace std;
class Base {
public:
virtual void show() { // Virtual function
cout << "Base class" << endl;
}
};
class Derived : public Base {
public:
void show() override { // Overrides base class function
cout << "Derived class" << endl;
}
};
int main() {
Base* b = new Derived();
b->show(); // Output: Derived class
delete b;
}
A friend function can access private and protected members of a class.
class Example {
private:
int x;
public:
Example(int value) : x(value) {}
friend void show(Example obj);
};
void show(Example obj) {
cout << "Value: " << obj.x << endl;
}
Smart pointers are classes that manage the lifetime of dynamically allocated objects. They help prevent memory leaks by automatically releasing memory when the object is no longer needed.
std::unique_ptr
: Single ownership.std::shared_ptr
: Shared ownership.std::weak_ptr
: Non-owning observer.
#include <iostream>
#include <memory>
using namespace std;
class Test {
public:
Test() { cout << "Test created" << endl; }
~Test() { cout << "Test destroyed" << endl; }
};
int main() {
shared_ptr<Test> ptr1 = make_shared<Test>(); // Shared ownership
{
shared_ptr<Test> ptr2 = ptr1; // Increases reference count
} // ptr2 goes out of scope
// ptr1 still manages the object
return 0;
}
// Output:
// Test created
// Test destroyed
The Rule of Three states that if a class defines one of the following special member functions, it should explicitly define all three:
This is because of resource management (e.g., dynamically allocated memory).
class MyClass {
int* data;
public:
MyClass(int value) { data = new int(value); }
~MyClass() { delete data; } // Destructor
MyClass(const MyClass& obj) { // Copy Constructor
data = new int(*obj.data);
}
MyClass& operator=(const MyClass& obj) { // Copy Assignment
if (this != &obj) {
delete data;
data = new int(*obj.data);
}
return *this;
}
};
#include <iostream>
using namespace std;
class Example {
int* data;
public:
Example(int value) {
data = new int(value);
}
~Example() {
delete data;
}
Example(const Example& obj) { // Deep Copy
data = new int(*obj.data);
}
};
int main() {
Example obj1(10);
Example obj2 = obj1; // Calls copy constructor
return 0;
}
Templates are used for generic programming, allowing functions or classes to work with any data type.
#include <iostream>
using namespace std;
template <typename T>
T add(T a, T b) {
return a + b;
}
int main() {
cout << add(3, 4) << endl; // Output: 7
cout << add(2.5, 3.1) << endl; // Output: 5.6
return 0;
}
A constructor is a special member function that initializes objects of a class. It has the same name as the class and no return type.
#include <iostream>
using namespace std;
class Example {
int x;
public:
Example(int value) : x(value) { // Parameterized Constructor
cout << "Constructor called, x = " << x << endl;
}
};
int main() {
Example obj(10); // Constructor initializes x with 10
return 0;
}
A destructor is a special member function that cleans up resources allocated to an object. It is called automatically when the object goes out of scope.
#include <iostream>
using namespace std;
class Example {
public:
~Example() {
cout << "Destructor called" << endl;
}
};
int main() {
Example obj; // Destructor is called automatically when obj goes out of scope
return 0;
}
Aspect | Overloading | Overriding |
---|---|---|
Definition | Same function name, different parameters. | Same function signature in base and derived class. |
Compile vs Runtime | Resolved at compile-time. | Resolved at runtime (polymorphism). |
Example Usage | Functions in the same class. | Functions across base and derived classes. |
#include <iostream>
using namespace std;
class Base {
public:
virtual void show() { cout << "Base class" << endl; } // Overriding
};
class Derived : public Base {
public:
void show() override { cout << "Derived class" << endl; }
};
int main() {
Derived obj;
obj.show(); // Output: Derived class
return 0;
}
Access specifiers define the accessibility of class members:
class Example {
private:
int x;
protected:
int y;
public:
int z;
};
Feature | new | malloc |
---|---|---|
Memory Type | Allocates and initializes memory. | Allocates uninitialized memory. |
Syntax | new ClassName() |
malloc(sizeof(ClassName)) |
Operator/Function | Operator | Function |
Move semantics allow the resources of a temporary object to be transferred to another object, avoiding deep copies.
class Example {
int* data;
public:
Example(int value) { data = new int(value); }
Example(Example&& obj) noexcept { // Move Constructor
data = obj.data;
obj.data = nullptr;
}
};
Lambdas are anonymous functions introduced in C++11.
#include <iostream>
using namespace std;
int main() {
auto sum = [](int a, int b) { return a + b; };
cout << sum(3, 5) << endl; // Output: 8
return 0;
}
std::vector
is a dynamic array that resizes itself automatically.
#include <vector>
#include <iostream>
using namespace std;
int main() {
vector<int> vec = {1, 2, 3};
vec.push_back(4);
for (int val : vec) {
cout << val << " ";
}
return 0;
}
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; }
Type | Description |
---|---|
Single | Derived class inherits from one base class. |
Multiple | Derived class inherits from multiple base classes. |
Multilevel | Inheritance forms a chain of classes. |
Hierarchical | Multiple derived classes inherit from a single base class. |
Hybrid | Combination of two or more inheritance types. |
Class | Description |
---|---|
Automatic | Default for local variables. |
Static | Retains value between function calls. |
External | Declared using extern . |
Register | Suggests storage in CPU registers. |
Aspect | Inline Function | Macro |
---|---|---|
Definition | A request to the compiler to insert function code at the call site. | A preprocessor directive. |
Type Checking | Supports type checking. | No type checking. |
Debugging | Easier to debug. | Difficult to debug. |
#define SQUARE(x) ((x) * (x)) // Macro
inline int square(int x) { return x * x; } // Inline Function
The Diamond Problem occurs in multiple inheritance when a class is derived from two classes that have a common base class. This causes ambiguity.
#include <iostream>
using namespace std;
class A {
public:
void display() { cout << "Class A" << endl; }
};
class B : virtual public A {}; // Virtual Inheritance
class C : virtual public A {};
class D : public B, public C {};
int main() {
D obj;
obj.display(); // No ambiguity
return 0;
}
The vtable is a table of function pointers used to implement runtime polymorphism in C++. Each class with virtual functions has its own vtable.
class Base {
public:
virtual void show() {}
};
class Derived : public Base {
public:
void show() override {}
};
Base
and Derived
classes will have a vtable for show()
.
RAII (Resource Acquisition Is Initialization) ensures that resources are acquired and released in a deterministic manner using constructors and destructors.
#include <iostream>
#include <fstream>
using namespace std;
class File {
fstream file;
public:
File(const string& filename) {
file.open(filename, ios::out);
}
~File() {
if (file.is_open()) file.close();
}
};
Aspect | throw | noexcept |
---|---|---|
Purpose | Used to throw exceptions. | Indicates that a function doesn't throw exceptions. |
Overhead | Adds overhead when throwing. | Optimized for performance. |
Aspect | std::list | std::vector |
---|---|---|
Structure | Doubly linked list. | Dynamic array. |
Random Access | Not supported. | Supported. |
Insertion/Deletion | Efficient at any position. | Efficient at the end only. |
The virtual
keyword allows for runtime polymorphism by enabling derived class methods to override base class methods.
Aspect | delete | delete[] |
---|---|---|
Purpose | Deletes a single object. | Deletes an array of objects. |
Usage | delete ptr; |
delete[] ptr; |
A function pointer stores the address of a function.
#include <iostream>
using namespace std;
void greet() { cout << "Hello!" << endl; }
int main() {
void (*funcPtr)() = greet; // Function pointer
funcPtr(); // Calls greet()
return 0;
}
Aspect | Pre-Increment (++i ) |
Post-Increment (i++ ) |
---|---|---|
Behavior | Increments first, then returns. | Returns first, then increments. |
int i = 5;
cout << ++i; // Output: 6
cout << i++; // Output: 6, then i becomes 7
Namespaces avoid name conflicts by grouping related entities under a unique name.
#include <iostream>
namespace Math {
int add(int a, int b) { return a + b; }
}
int main() {
cout << Math::add(3, 4) << endl;
return 0;
}
A pure virtual function is declared by assigning = 0
in the base class. It makes a class abstract.
class Shape {
public:
virtual void draw() = 0; // Pure virtual function
};
Aspect | std::set | std::map |
---|---|---|
Key-Value Pair | Stores only keys. | Stores key-value pairs. |
Sorting | Sorted automatically. | Sorted by keys. |
The mutable
keyword allows modification of a member variable even in const
objects.
class Example {
mutable int x;
public:
Example(int value) : x(value) {}
void modify() const { x++; }
};
Aspect | Shallow Copy | Deep Copy |
---|---|---|
Copy | Copies the address of the object. | Copies the actual content. |
std::unique_ptr
is a smart pointer that ensures single ownership of a resource.
#include <memory>
int main() {
unique_ptr<int> ptr = make_unique<int>(5);
cout << *ptr << endl;
return 0;
}
Aspect | Compile-Time | Runtime |
---|---|---|
Mechanism | Function overloading. | Virtual functions. |
The Singleton pattern restricts instantiation of a class to one object.
class Singleton {
static Singleton* instance;
Singleton() {}
public:
static Singleton* getInstance() {
if (!instance) instance = new Singleton();
return instance;
}
};
Singleton* Singleton::instance = nullptr;
std::move
enables move semantics, transferring resources from one object to another.
Cast | Description |
---|---|
static_cast |
Performs compile-time type conversion. |
dynamic_cast |
Used for runtime type conversion with polymorphic classes. |
const_cast |
Removes const or volatile qualifiers. |
reinterpret_cast |
Converts between unrelated types. |
Aspect | Queue | Stack |
---|---|---|
Structure | FIFO (First-In-First-Out). | LIFO (Last-In-First-Out). |
A static member belongs to the class rather than an object. It is shared among all objects of the class.
#include <iostream>
using namespace std;
class Counter {
static int count; // Declaration
public:
Counter() { count++; }
static int getCount() { return count; }
};
int Counter::count = 0; // Definition
int main() {
Counter c1, c2;
cout << Counter::getCount() << endl; // Output: 2
return 0;
}
Type casting converts one data type to another. Types include:
static_cast
.A functor is a class or struct that overloads the ()
operator.
#include <iostream>
using namespace std;
class Multiply {
int factor;
public:
Multiply(int f) : factor(f) {}
int operator()(int value) { return value * factor; }
};
int main() {
Multiply multiplyBy3(3);
cout << multiplyBy3(10); // Output: 30
return 0;
}
Aspect | std::vector | std::deque |
---|---|---|
Structure | Dynamic array. | Double-ended queue. |
Access Time | Fast for random access. | Slightly slower. |
std::pair
is used to store two heterogeneous objects.
#include <iostream>
#include <utility>
using namespace std;
int main() {
pair<int, string> p = {1, "Alice"};
cout << p.first << ", " << p.second;
return 0;
}
Aspect | Priority Queue | Queue |
---|---|---|
Order | Elements sorted by priority. | FIFO order. |
Aspect | L-value | R-value |
---|---|---|
Definition | Refers to a persistent object. | Refers to temporary data. |
Copy elision is a compiler optimization that eliminates unnecessary copying.