The OOP features provided by languages varies. Below are some common features of OOP languages. Comparing OOP with other styles, like
relational programming, is difficult because there isn't a clear, agreed-upon definition of OOP.
Encapsulation and information hiding Information hiding and
encapsulation can refer to several related concepts: •
Cohesion, keeping related
fields and
methods together. A field (a.k.a. attribute or property) contains information (a.k.a. state) as a
variable. A method (a.k.a.
function or action) defines behavior via logic code. •
Decoupling, organizing code so that only certain parts of the data are used by related functions. Decoupling makes it easier to change how an object works on the inside without affecting other parts of the
codebase, such as in
code refactoring. Objects act as a boundary between their internal workings and external, consuming code. •
Data hiding, keeping the internal details of an object hidden from outside code. Consuming code can only interact with an object via its public members, due to the language providing
access modifiers that control visibility. Some programming languages, like Java, provide information hiding via visibility key words ( and ). Some languages like Python don't provide a visibility feature, but developers might follow a convention such as starting a private member name with an underscore. Intermediate levels of access also exist, such as Java's keyword, (which allows access from the same class and its subclasses, but not objects of a different class), and the keyword in C#, Swift, and Kotlin, which restricts access to files within the same module. Supporters of information hiding and data abstraction say it makes code easier to reuse and intuitively represents real-world situations. However, others argue that OOP does not enhance readability or modularity. Raymond compares this unfavourably to the approach taken with
Unix and the
C language. Leo Brodie says that information hiding can lead to
duplicate code, which goes against the
don't repeat yourself rule of software development.
Inheritance Inheritance can be supported via the
class or the
prototype, which have differences but use similar terms like object and
instance.
Class-based In
class-based programming, the most common type of OOP, an object is an instance of a class. The class defines the data (variables) and methods (logic). An object is created via the
constructor. Every instance of the class has the same set of variables and methods. Elements may include: •
Class variable – belongs to the class itself; all objects of the class share one copy •
Instance variable – belongs to an object; every object has its own version of these variables •
Member variable – refers to both the class and instance variables of a class • Class method – can only use class variables • Instance method – belongs to an object; can use both instance and class variables Classes may inherit from other classes, creating a hierarchy of classes: a case of a subclass inheriting from a super-class. For example, an class might inherit from a class which endows the Employee object with the variables from . The subclass may add variables and methods that do not affect the super-class. Most languages also allow the subclass to override super-class methods. Some languages support
multiple inheritance, where a class can inherit from more than one class, and other languages similarly support
mixins or
traits. For example, a mixin called UnicodeConversionMixin might add a method unicode_to_ascii() to both a FileReader and a WebPageScraper class. An
abstract class cannot be directly instantiated as an object. It is only used as a super-class. Other classes are utility classes which contain only class variables and methods and are not meant to be instantiated or subclassed.
Prototype-based Instead of providing a class concept, in
prototype-based programming, an object is linked to another object, called its
prototype or
parent. In Self, an object may have multiple or no parents, but in the most popular prototype-based language,
JavaScript, an object has exactly one prototype link, up to the base object whose prototype is null. A prototype acts as a model for new objects. For example, if you have an object , you can make two objects and that share traits of the prototype. Prototype-based languages also allow objects to have their own unique properties, so the object might have an attribute , while the or objects do not.
No inheritance In all OOP languages, via
object composition, an object can contain other objects. For example, an object might contain an object, along with other information like and . Composition is a "has-a" relationships, like "an employee has an address". Some languages, like
Go, don't support inheritance. Instead, they encourage "
composition over inheritance", where objects are built using smaller parts instead of parent-child relationships. For example, instead of inheriting from class Person, the Employee class could simply contain a Person object. This lets the Employee class control how much of Person it exposes to other parts of the program.
Delegation is another language feature that can be used as an alternative to inheritance. Programmers have different opinions on inheritance. Bjarne Stroustrup, author of C++, has stated that it is possible to do OOP without inheritance.
Rob Pike has criticized inheritance for creating complex hierarchies instead of simpler solutions.
Inheritance and behavioral subtyping People often think that if one class inherits from another, it means the subclass "
is a" more specific version of the original class. This presumes the
program semantics are that objects from the subclass can always replace objects from the original class without problems. This concept is known as
behavioral subtyping, more specifically the
Liskov substitution principle. However, this is often not true, especially in programming languages that allow
mutable objects, objects that change after they are created. In fact,
subtype polymorphism as enforced by the
type checker in OOP languages cannot guarantee behavioral subtyping in most if not all contexts. For example, the
circle-ellipse problem is notoriously difficult to handle using OOP's concept of inheritance. Behavioral subtyping is undecidable in general, so it cannot be easily implemented by a compiler. Because of this, programmers must carefully design class hierarchies to avoid mistakes that the programming language itself cannot catch.
Dynamic dispatch A method may be invoked via
dynamic dispatch such that the method is selected at runtime instead of compile time. If the method choice depends on more than one type of object (such as other objects passed as parameters), it's called
multiple dispatch. In this context, a method call is also known as
message passing, meaning the method name and its inputs are like a message sent to the object for it to act on. Dynamic dispatch works together with inheritance: if an object doesn't have the requested method, it looks up to its parent class (
delegation), and continues up the chain to find a matching method.
Polymorphism Polymorphism in OOP refers to
subtyping or subtype polymorphism, where a function can work with a specific
interface and thus manipulate entities of different classes in a uniform manner. For example, imagine a program has two shapes: a circle and a square. Both come from a common class called "Shape." Each shape has its own way of drawing itself. With subtype polymorphism, the program doesn't need to know the type of each shape, and can simply call the "Draw" method for each shape. The programming language runtime will ensure the correct version of the "Draw" method runs for each shape. Because the details of each shape are handled inside their own classes, this makes the code simpler and more organized, enabling strong
separation of concerns.
Open recursion An object's methods can access the object's data. Many programming languages use a special word, like this (computer programming)| or , to refer to the current object. In languages that support
open recursion, a method in an object can call other methods in the same object, including itself, using this special word. This allows a method in one class to call another method defined later in a subclass, a feature known as
late binding. ==Design patterns==