Object-Oriented Programming (OOP) is a programming paradigm that organizes software design around data, or objects, rather than functions and logic. This approach is particularly effective for managing large and complex software systems, making it easier to develop, maintain, and scale applications.
An object is a self-contained entity that consists of both data (attributes) and procedures (methods) that operate on the data. Objects represent real-world entities and can interact with one another through well-defined interfaces.
A class serves as a blueprint for creating objects. It defines the properties and behaviors that the objects created from the class will have. For example, a Car class might define attributes like color and model, along with methods like drive() or stop().
Encapsulation is the principle of bundling data and methods that manipulate that data within a single unit or class. This restricts direct access to some of the object's components, which helps in protecting object integrity by preventing unintended interference and misuse of its internal state.
Abstraction involves hiding the complex reality while exposing only the necessary parts of an object. It simplifies interactions with objects by providing a clear interface while hiding implementation details.
Inheritance allows one class (the derived class) to inherit attributes and methods from another class (the base class). This promotes code reusability and establishes a hierarchical relationship between classes. For instance, if you have a Vehicle class, you could create a Car class that inherits from it.
Polymorphism enables methods to do different things based on the object it is acting upon, even though they share the same name. This can be achieved through method overriding (in derived classes) or method overloading (same method name with different parameters).
Reusability: Code can be reused across different programs through inheritance.
Modularity: Programs can be divided into smaller, manageable pieces.
Maintainability: Changes in one part of the code do not significantly affect other parts due to encapsulation.
Scalability: OOP supports larger codebases by organizing code into classes and objects.
A class in C++ is a user-defined data type that serves as a blueprint for creating objects. It encapsulates data and functions that operate on that data, enabling the organization of code in a modular way. Here’s a breakdown of the syntax and structure of a class in C++.
To define a class, you use the class keyword followed by the class name. The body of the class is enclosed in curly braces and ends with a semicolon. Here's the basic syntax:
class ClassName {
// Access specifiers
public:
// Attributes (data members)
dataType attributeName;
// Member functions (methods)
returnType functionName(parameters) {
// Function body
}
};
Let's consider an example of a simple class called Rectangle:
#include <iostream>
using namespace std;
class Rectangle {
public:
double length; // Attribute for length
double width; // Attribute for width
// Method to calculate area
double calculateArea() {
return length * width;
}
};
Once you have defined a class, you can create objects from it. An object is an instance of the class and can access its members using the dot (.) operator.
int main() {
Rectangle rect; // Create an object of Rectangle
rect.length = 5.0; // Set length
rect.width = 3.0; // Set width
cout << "Area of rectangle: " << rect.calculateArea() << endl; // Call method to calculate area
return 0;
}
Constructor
In C++, a constructor is a special member function that is automatically called when an object of a class is created. Its primary purpose is to initialize the object's data members. Constructors have the same name as the class and do not have a return type, not even void.
Same Name as Class: The constructor must have the same name as the class it belongs to.
No Return Type: Constructors do not return values.
Automatic Invocation: They are called automatically when an object is instantiated.
Initialization: Used to set initial values for the object's attributes.
A default constructor is one that does not take any parameters. If no constructor is defined, C++ automatically provides a default constructor.
Example:
class MyClass {
public:
MyClass() { // Default constructor
std::cout << "Default Constructor Called!" << std::endl;
}
};
int main() {
MyClass obj; // Calls the default constructor
return 0;
}
A parameterized constructor takes arguments that can be used to initialize attributes with specific values when an object is created.
Example:
class Car {
public:
std::string brand;
std::string model;
int year;
Car(std::string b, std::string m, int y) { // Parameterized constructor
brand = b;
model = m;
year = y;
}
};
int main() {
Car car1("Toyota", "Camry", 2020); // Calls parameterized constructor
std::cout << car1.brand << " " << car1.model << " " << car1.year << std::endl;
return 0;
}
A copy constructor initializes an object using another object of the same class. It is called when an object is passed by value or returned from a function.
Example:
class Point {
public:
int x, y;
Point(int xVal, int yVal) : x(xVal), y(yVal) {} // Parameterized constructor
Point(const Point &p) { // Copy constructor
x = p.x;
y = p.y;
}
};
int main() {
Point p1(10, 20); // Calls parameterized constructor
Point p2 = p1; // Calls copy constructor
std::cout << p2.x << ", " << p2.y << std::endl; // Outputs: 10, 20
return 0;
}
C++ allows multiple constructors in a class with different parameters (constructor overloading). This enables creating objects in various ways.
Example:
class Box {
public:
int length, width, height;
Box() { // Default constructor
length = width = height = 0;
}
Box(int l, int w, int h) { // Parameterized constructor
length = l;
width = w;
height = h;
}
};
int main() {
Box box1; // Calls default constructor
Box box2(5, 10, 15); // Calls parameterized constructor
return 0;
}
Create a Book class that contains the following attributes:
Title (string)
Author (string)
Price (float)
Implement both a default constructor and a parameterized constructor. Then, create a main function to demonstrate the use of these constructors.
Define the Book Class:
Create a class named Book.
Add private attributes for title, author, and price.
Implement a default constructor that initializes these attributes to default values (e.g., empty strings for title and author, and 0.0 for price).
Implement a parameterized constructor that allows you to set the title, author, and price when creating an object.
Add Member Functions:
Add a member function to display the book's details.
Create Objects in the Main Function:
In the main function, create at least one object using the default constructor and one using the parameterized constructor.
Call the display function for each object to show their details.
#include <iostream>
#include <string>
class Book {
private:
std::string title;
std::string author;
float price;
public:
// Default constructor
Book() {
title = "Unknown Title";
author = "Unknown Author";
price = 0.0;
}
// Parameterized constructor
Book(std::string t, std::string a, float p) {
title = t;
author = a;
price = p;
}
// Member function to display book details
void display() {
std::cout << "Title: " << title << std::endl;
std::cout << "Author: " << author << std::endl;
std::cout << "Price: $" << price << std::endl;
}
};
int main() {
// Create an object using the default constructor
Book book1;
std::cout << "Book 1 Details (Default Constructor):" << std::endl;
book1.display();
std::cout << std::endl;
// Create an object using the parameterized constructor
Book book2("1984", "George Orwell", 9.99);
std::cout << "Book 2 Details (Parameterized Constructor):" << std::endl;
book2.display();
return 0;
}
Multiple inheritance
Multiple inheritance in C++ allows a class to inherit from more than one base class. This feature enables a derived class to combine the functionalities of multiple base classes, promoting code reusability. However, it can also introduce complexity, such as ambiguity when two base classes have members with the same name.
Here’s a simple example demonstrating multiple inheritance in C++. We'll create two base classes, Mammal and WingedAnimal, and a derived class Bat that inherits from both.
#include <iostream>
using namespace std;
// Base class 1
class Mammal {
public:
Mammal() {
cout << "Mammals can give direct birth." << endl;
}
};
// Base class 2
class WingedAnimal {
public:
WingedAnimal() {
cout << "Winged animals can flap." << endl;
}
};
// Derived class
class Bat : public Mammal, public WingedAnimal {
public:
Bat() {
cout << "Bat is a unique animal." << endl;
}
};
int main() {
Bat b1; // Creating an object of the derived class
return 0;
}
When you run the above code, the output will be:
Mammals can give direct birth.
Winged animals can flap.
Bat is a unique animal.
If both base classes have members (functions or attributes) with the same name, it creates ambiguity. To resolve this, you can use scope resolution to specify which base class member you want to access.
#include <iostream>
using namespace std;
// Base class 1
class A {
public:
void show() {
cout << "Show from Class A" << endl;
}
};
// Base class 2
class B {
public:
void show() {
cout << "Show from Class B" << endl;
}
};
// Derived class
class C : public A, public B {
public:
void display() {
// Resolving ambiguity using scope resolution
A::show(); // Calls show() from Class A
B::show(); // Calls show() from Class B
}
};
int main() {
C obj;
obj.display(); // Calls display method
return 0;
}
When you run this code, the output will be:
Show from Class A
Show from Class B
Inheritance with constructors
To implement inheritance in C++ with constructors, particularly parameterized constructors, it is essential to understand how constructors are called in the context of class inheritance. Below is a detailed explanation along with code examples to illustrate these concepts.
In C++, when a derived class is instantiated, the constructors of both the base and derived classes are called. The base class constructor is invoked first, followed by the derived class constructor. This order ensures that the base part of the object is fully initialized before the derived part is constructed.
Default Constructor: A constructor that does not take any parameters.
Parameterized Constructor: A constructor that takes parameters to initialize an object.
When using parameterized constructors in inheritance, the derived class must explicitly call the base class's parameterized constructor.
If the base class has only a parameterized constructor and no default constructor, you must provide arguments in the derived class constructor's initializer list.
Here’s an example demonstrating both default and parameterized constructors in inheritance:
#include <iostream>
using namespace std;
class Base {
public:
// Default constructor
Base() {
cout << "Base default constructor\n";
}
// Parameterized constructor
Base(int n) {
cout << "Base parameterized constructor with value: " << n << "\n";
}
};
class Derived : public Base {
public:
// Default constructor
Derived() : Base() { // Calls Base's default constructor
cout << "Derived default constructor\n";
}
// Parameterized constructor
Derived(int x) : Base(x) { // Calls Base's parameterized constructor
cout << "Derived parameterized constructor with value: " << x << "\n";
}
};
int main() {
cout << "Creating Derived object with default constructor:\n";
Derived d1; // Calls Base's default then Derived's default
cout << "\nCreating Derived object with parameterized constructor:\n";
Derived d2(10); // Calls Base's parameterized then Derived's parameterized
return 0;
}
When you run this program, you will see the following output:
Creating Derived object with default constructor:
Base default constructor
Derived default constructor
Creating Derived object with parameterized constructor:
Base parameterized constructor with value: 10
Derived parameterized constructor with value: 10
This output illustrates that:
When d1 is created, the Base class's default constructor is called first, followed by the Derived class's default constructor.
When d2 is created using a parameter, the Base class's parameterized constructor is called first, followed by the Derived class's parameterized constructor.
Access Specifiers (Encapsulation)
In C++, access specifiers are keywords that determine the visibility and accessibility of class members (attributes and methods). They play a crucial role in implementing encapsulation, which is a fundamental principle of Object-Oriented Programming (OOP). There are three primary access specifiers in C++: public, private, and protected.
Members declared as public are accessible from anywhere in the program, including outside the class.
This is typically used for methods and attributes that need to be accessed by other classes or functions.
Example:
class MyClass {
public:
int publicVar; // Public variable
void display() { // Public method
std::cout << "Public Variable: " << publicVar << std::endl;
}
};
Members declared as private can only be accessed from within the same class. They cannot be accessed directly from outside the class or from derived classes.
This is used to protect sensitive data and implementation details.
Example:
class MyClass {
private:
int privateVar; // Private variable
public:
void setPrivateVar(int value) { // Public method to set private variable
privateVar = value;
}
void display() { // Public method to display private variable
std::cout << "Private Variable: " << privateVar << std::endl;
}
};
Members declared as protected can be accessed within the same class and by derived classes. However, they cannot be accessed from outside the class hierarchy.
This is useful for inheritance, allowing derived classes to access base class members while keeping them hidden from other parts of the program.
Example:
class Base {
protected:
int protectedVar; // Protected variable
public:
void setProtectedVar(int value) { // Public method to set protected variable
protectedVar = value;
}
};
class Derived : public Base {
public:
void display() { // Derived class can access protected member
std::cout << "Protected Variable: " << protectedVar << std::endl;
}
};
Virtual Functions
In C++, a virtual function is a member function in a base class that can be overridden in a derived class. It allows for runtime polymorphism, meaning that the function to be called is determined during program execution, rather than at compile time. This is achieved using a vtable (virtual table).
Declared using the virtual keyword in the base class.
When a base class pointer points to a derived class object, the derived class's version of the function is called if it is overridden.
Virtual functions make use of the concept of dynamic dispatch.
Here is the syntax for declaring and using virtual functions in C++:
A virtual function is declared using the virtual keyword in the base class.
class Base {
public:
virtual void functionName() {
// Base class implementation
}
};
The derived class overrides the virtual function to provide its specific implementation.
class Derived : public Base {
public:
void functionName() override { // `override` is optional but recommended
// Derived class implementation
}
};
To achieve runtime polymorphism, use a pointer to the base class to call the function.
int main() {
Base* basePtr; // Base class pointer
Derived derivedObj;
basePtr = &derivedObj;
basePtr->functionName(); // Calls the derived class's implementation
return 0;
}
#include <iostream>
using namespace std;
class Base {
public:
virtual void display() { // Virtual function
cout << "Base class display function" << endl;
}
};
class Derived : public Base {
public:
void display() override { // Override the virtual function
cout << "Derived class display function" << endl;
}
};
int main() {
Base* basePtr;
Derived derivedObj;
basePtr = &derivedObj;
basePtr->display(); // Calls Derived's display function due to virtual mechanism
return 0;
}
Use virtual keyword in the base class to make the function virtual.
Use override in the derived class for better readability (optional but helps catch errors).
Virtual functions enable runtime polymorphism, where the function to execute is determined at runtime.
Create a class hierarchy for different types of shapes. Implement a base class called Shape and derived classes Circle and Rectangle. Each class should have constructors, methods to calculate area, and display information about the shape.
Base Class: Shape
Create a base class named Shape.
Include a constructor that initializes the shape type (e.g., "Shape").
Provide a virtual method area() that returns the area of the shape. This method should be overridden in derived classes.
Provide a virtual method display() to show the shape type.
Derived Class: Circle
Create a derived class named Circle that inherits from Shape.
Include a constructor that takes the radius as a parameter and calls the base class constructor with the shape type set to "Circle".
Implement the area() method to calculate the area of the circle using the formula πr^2
Override the display() method to show details about the circle, including its radius and area.
Derived Class: Rectangle
Create another derived class named Rectangle that inherits from Shape.
Include a constructor that takes width and height as parameters and calls the base class constructor with the shape type set to "Rectangle".
Implement the area() method to calculate the area of the rectangle using the formula width×height
Override the display() method to show details about the rectangle, including its width, height, and area.
Main Function
In your main function, create instances of both Circle and Rectangle.
Call their display() methods to show their details.
Print out their areas by calling the area() method.
#include <iostream>
#include <cmath> // For M_PI
using namespace std;
class Shape{
public:
string shapeType;
Shape(const string &type) : shapeType(type) {}
virtual double area() const = 0; // Pure virtual function
virtual void display() const{
cout << "Shape Type: " << shapeType << endl;
}
};
class Circle : public Shape{
public:
double radius;
Circle(double r) : Shape("Circle"), radius(r) {}
double area() const override{
return M_PI * radius * radius; // Area of circle
}
void display() const override{
Shape::display();
cout << "Radius: " << radius << endl;
cout << "Area: " << area() << endl;
}
};
class Rectangle : public Shape{
public:
double width;
double height;
Rectangle(double w, double h) : Shape("Rectangle"), width(w), height(h) {}
double area() const override{
return width * height; // Area of rectangle
}
void display() const override{
Shape::display();
cout << "Width: " << width << endl;
cout << "Height: " << height << endl;
cout << "Area: " << area() << endl;
}
};
int main(){
Circle circle(5);
circle.display();
cout << endl; // For spacing
Rectangle rectangle(4, 6);
rectangle.display();
return 0;
}
Object-Oriented Programming (OOP) is a programming paradigm that utilizes "objects" to model real-world entities. In C++, OOP enhances code organization, reusability, and maintainability by encapsulating data and behavior within classes. The core concepts of OOP in C++ include Encapsulation, Abstraction, Inheritance, and Polymorphism.
Encapsulation
Encapsulation involves bundling data (attributes) and methods (functions) that operate on the data into a single unit, known as a class. It restricts direct access to some components, which is a means of data hiding.
Example:
#include <iostream>
#include <string>
using namespace std;
class Book {
private:
string title; // Encapsulated property
public:
void setTitle(string t) { title = t; } // Setter method
string getTitle() { return title; } // Getter method
};
int main() {
Book book;
book.setTitle("C++ Encapsulation");
cout << book.getTitle() << endl; // Accessing value securely
return 0;
}
Abstraction
Abstraction focuses on exposing only the relevant attributes and behaviors while hiding the complex implementation details from the user.
Example:
class Car {
private:
int speed;
public:
void showStatus() {
if (speed != 0)
cout << "The car is being driven." << endl;
else
cout << "The car is stationary." << endl;
}
};
Inheritance
Inheritance allows a new class (derived class) to inherit properties and methods from an existing class (base class). This promotes code reuse.
Example:
#include <iostream>
using namespace std;
class Vehicle {
public:
string brand;
void showBrand() { cout << "Brand: " << brand << endl; }
};
class Car : public Vehicle {
public:
string model;
void showModel() { cout << "Model: " << model << endl; }
};
int main() {
Car myCar;
myCar.brand = "Honda";
myCar.model = "Accord";
myCar.showBrand();
myCar.showModel();
return 0;
}
Polymorphism
Polymorphism allows methods to do different things based on the object it is acting upon, even if they share the same name. This can be achieved through function overloading and overriding.
Example:
#include <iostream>
using namespace std;
class MangoTree {
public:
void respire() { cout << "Mango trees do respiration at night." << endl; }
};
class NeemTree : public MangoTree {
public:
void respire() { cout << "Respiration in neem trees occurs mainly through stomata." << endl; }
};
int main() {
MangoTree myMangoTree;
NeemTree myNeemTree;
myMangoTree.respire();
myNeemTree.respire();
return 0;
}
C++'s OOP features facilitate better software design by promoting modularity and reusability. By leveraging encapsulation, abstraction, inheritance, and polymorphism, developers can create more efficient and manageable code structures that mirror real-world interactions.