PPL Oops
PPL Oops
Languages
Let's dive into each of these topics with detailed explanations and examples in both C++ and Java.
1. Classes and Objects
Class
A class in OOP can be thought of as a blueprint or a template for creating objects. It defines the
properties (attributes) and behaviors (methods) that the objects created from the class will
have. For example, if we define a class Car, it may have attributes like make, model, and year
and methods like start() and stop().
Object
An object is an instance of a class. While a class defines the structure and behavior, an object is
the actual implementation. If the Car class is the blueprint, an object would be a specific car,
like a Toyota Corolla made in 2020. Each object has its own set of data, which are typically
referred to as the object’s state.
In C++, classes are defined with a focus on performance, allowing low-level control over
memory through constructors, destructors, and memory allocation mechanisms. Objects in C++
are created statically, automatically, or dynamically.
The language provides features such as function overloading and operator overloading, allowing
multiple methods or operations to share the same name but differ in implementation. Static
methods and variables are also supported, meaning they belong to the class rather than any
specific object instance.
Java, in contrast, has a stricter and more formal approach to OOP. Everything in Java is
considered an object, except for primitive types (like integers and Booleans), though even these
can be treated as objects through wrapper classes.
Java’s focus on portability and platform independence led to the design of classes with an
emphasis on automated memory management, which is handled via a built-in garbage collector.
Java classes are structured into packages, promoting modularity, and all objects are created
dynamically using the new keyword.
• Classes in C++: • Classes in java:
In the examples above, Car is the class in both C++ and Java, and myCar is an
object (instance) of the Car class.
• Prolog's Approach (Simulated Classes and Objects): Prolog is primarily a logic programming
language and does not follow OOP principles as directly as C++ or Java. However, it supports
the concept of object-oriented structures through libraries like Logtalk, which implements
classes and objects in Prolog.
In Logtalk (Prolog extension):
Abstraction and Encapsulation are two fundamental principles of OOP that help in hiding
complexity and controlling access to data.
Abstraction
Abstraction refers to the concept of hiding the unnecessary details and exposing only the
essential features of an object. In software development, abstraction allows us to focus on what
an object does rather than how it does it. For example, a car's driver does not need to know
how the engine works in detail; they only need to know how to start the car, accelerate, and
brake.
Abstraction is achieved through:
• Interfaces: These define the methods that a class must implement, without specifying how
they should be implemented.
• Abstract classes: These serve as templates for other classes and contain abstract methods
(i.e., methods without implementation).
In C++, abstraction is achieved through mechanisms like header files and interfaces (pure virtual
functions). A header file can hide implementation details by providing only the function
prototypes to users, while the actual implementation remains invisible. Pure virtual functions in
C++ serve as an interface for derived classes to provide specific functionality, abstracting away
the concrete implementation of the method in the base class.
In Java, abstraction is enforced through abstract classes and interfaces. An abstract class may
contain a mixture of implemented and unimplemented methods, providing a framework for
derived classes to extend. Interfaces, on the other hand, define a completely abstract set of
methods that any implementing class must provide. This ensures that different classes adhere to
the same blueprint without being tied to any specific implementation.
Encapsulation:
Encapsulation is the bundling of data (attributes) and methods (functions) within a class and
restricting access to some of the object's components. By making data private or protected, you
prevent direct access to the data and expose it only through well-defined interfaces (such as
getter and setter methods).
Encapsulation helps:
• Protect the internal state of the object.
• Reduce the complexity of interaction between different parts of a system.
• Maintain the integrity of the object’s data.
In C++, encapsulation is enforced through access specifiers: private, protected, and public. These
keywords control the visibility of class members (data and methods) outside the class. Private members
are not accessible outside the class, ensuring that the internal state is protected. Getter and setter
functions are often used to allow controlled access to private data.
In Java, encapsulation is also achieved through access modifiers: private, protected, default, and public.
Java emphasizes encapsulation as a means of building robust, maintainable systems where the internal
workings of objects are hidden from external interference. Java developers commonly use getter and
setter methods to manage access to private attributes while maintaining data validation or other logic
within these methods.
• In C++: • In Java:
In both examples, the attributes brand and year are private and are accessible only through
public methods (setBrand, setYear, displayInfo). This ensures data hiding and protects the
integrity of the object's state.
In Prolog, abstraction and encapsulation are not directly supported, but you can achieve some
degree of abstraction by creating higher-level predicates that hide internal details.
In Prolog, encapsulation in the OOP sense is not natively supported, but it can be simulated in
Logtalk. In Logtalk, predicates (methods) can be declared as private or public, determining
whether they can be accessed externally by other objects or predicates. This ensures that some
logic remains encapsulated within objects, enforcing modularity.
3. Inheritance
Inheritance is one of the cornerstones of OOP, allowing a class (derived class) to inherit
properties and behaviors from another class (base class). This promotes code reuse and the
hierarchical organization of classes, where common functionality is defined in base classes and
specialized behavior is added in derived classes.
In C++, inheritance is implemented using the : syntax to link a derived class to its base class.
C++ supports both single inheritance (a class inherits from one base class) and multiple
inheritance (a class can inherit from more than one base class). However, multiple inheritance
can introduce complexity and ambiguity, especially with the diamond problem, where multiple
paths lead to the same base class.
Java supports single inheritance (a class can inherit from only one superclass) but
addresses the limitation through interfaces, which a class can implement multiple times.
Java uses the extends keyword for inheritance and the implements keyword for interfaces.
The inability to inherit from more than one class avoids the complexity of multiple
inheritance, such as the diamond problem seen in C++.
Inheritance allows a new class (subclass or derived class) to inherit the properties and
behaviors (methods) of an existing class (superclass or base class). It promotes code reuse
and enables the creation of a hierarchy of classes.
• In C++: • In Java:
In both examples, the Car class inherits the brand attribute and honk method from the Vehicle class,
and extends it by adding its own year attribute and drive method. Inheritance allows the subclass to
reuse code from the superclass while also adding or overriding functionalities.
4. Polymorphism
Polymorphism allows objects of different classes to be treated as instances of the same class
through a common interface. It enables a single function or method to operate on objects of
different types, promoting flexibility and code reuse.
In Prolog, polymorphism can be simulated in Logtalk, where different objects can define
the same predicate, and the correct implementation is chosen based on the object
sending or receiving the message. This enables a form of dynamic dispatch, similar to
polymorphism in C++ and Java.
Polymorphism allows one interface or method to be used for different types of objects,
making it easier to add new functionality without changing existing code. Polymorphism
can be achieved through method overriding and method overloading.
Method Overloading • Using Java:
• Using C++:
In the examples above, the display method is overloaded to accept different types of arguments (int and string).
This allows polymorphism through method overloading.
Method Overriding • Using Java:
• Using C++:
In these examples, the Dog class overrides the sound method of the Animal class, demonstrating runtime
polymorphism. The method that is invoked depends on the actual object type, even if the reference is of the
parent class type.
5. Virtual Functions and Classes
Virtual functions enable dynamic binding, which means that the method that will be invoked is
determined at runtime, rather than at compile time. This feature is essential for achieving run-
time polymorphism.
In C++, virtual functions are declared using the virtual keyword in the base class. When a virtual
function is overridden in a derived class, C++ ensures that the appropriate version of the
function is invoked at runtime, based on the actual type of the object, even if the function is
being called through a pointer or reference to the base class.
In Java, all non-static methods are, by default, virtual functions. This means that Java supports
dynamic method dispatch inherently without requiring the virtual keyword. However, Java
developers can use the final keyword to prevent further overriding of a method in subclasses.
In C++, a virtual function is a member function in the base class that can be overridden in the derived
class. Virtual functions ensure that the correct method is called for an object, regardless of the type of
reference (or pointer) used for the function call.
Abstract classes provide a way to define a common interface for a group of subclasses without
providing the full implementation. An abstract class cannot be instantiated on its own; it must
be extended by a concrete subclass that provides implementations for its abstract methods.
In C++, an abstract class is defined by declaring at least one pure virtual function, which is a
virtual function with no implementation in the base class. Any class that contains a pure virtual
function is considered abstract and cannot be instantiated directly.
In Java, an abstract class is declared using the abstract keyword. It may contain both abstract
methods (methods without implementation) and non-abstract methods (with implementation).
Abstract classes are used to define a common template for subclasses, ensuring that certain
methods are implemented in all subclasses.
In Prolog, abstract classes are not natively supported, but Logtalk allows the declaration of abstract
predicates, which serve a similar purpose by defining a contract that subclasses must fulfill.
C++ Abstract Class Example: Java Abstract Class Example:
In both examples, Shape is an abstract class with an abstract method draw. The Circle class extends
Shape and provides the implementation of the draw method.