0% found this document useful (0 votes)
54 views49 pages

OOPConcepts

best pdfs

Uploaded by

midhundev108
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
54 views49 pages

OOPConcepts

best pdfs

Uploaded by

midhundev108
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 49

Concepts of Object-Oriented

Programming
Richard Berger
richard.berger@jku.at
Johannes Kepler University Linz
What this talk is about
• Introduction to Objects & Classes
• Building objects
• Composition
• Encapsulation
• Inheritance
• Polymorphism
• Best practices
• Recommendations
• Design Patterns
• Conclusion
• Pro & Cons of OOP
What is Object-Oriented Programming?
• OOP started in 1960s (Simula, SmallTalk)
• Using objects as basic unit of computation message Object

• Allows to extend type system


Object message
• Usage: just like basic types (int, double, float, char, …)
• But with own structure and behavior
message
• Static Languages (C++) Object

Types are known at compile time


• Dynamic Languages (Python)
Types can be manipulated at runtime
I. Objects & Classes
Defining new objects, object lifetime
Where are these “objects”?
• Objects exist in memory at runtime
• Just like objects of primitive types (integers, floating-point numbers)
• We can interpret 4 bytes of data as integer number
• We can interpret 8 bytes of data as floating point number
• In C we have structs to create composite types containing multiple
primitive types
• In C++ and other OOP languages this is further extended by
associating behavior to a chunk of data through specifying methods
to manipulate that data.
Object
• State
• all properties of an object
• Behavior
• How an object reacts to interactions, such as calling a certain method
• In OOP speak: Response of an object when sending it messages
• Identity
• Multiple objects can have the same state and behavior, but each one is a
unique entity

Structure and Behavior of similar objects is defined by their class.


An object is also called an instance of a class.
Classes
Class
• defines memory structure of objects
class Vector2D • how we can interact with objects
• how it reacts to interactions
{
public:
double x; Member Variable
• A variable in the scope of a class
double y; • All instances allocate memory for their variables

double length() Member Method


{ • A method which can be called for an object of the class.
return sqrt(x*x + y*y) • Can access and modify the object state by manipulating
} member variables.
}; Interface
• All methods which can be called on an object from
outside.
Lifetime of an Object Allocation

• Allocation
• Allocate enough memory to store object data/state Initialization
• Initialization
• Set an initial object state
• Usage Usage
• Interact with objects through methods
• Access and modify object data
• Cleanup Cleanup
• Make sure that everything is in order before deletion
• Deletion
• Memory is freed, object ceases to exist Deletion
Allocation

Allocation Initialization

Static / Stack Allocation


Usage
void foo(int param1, int param2) Stack
{ param1
double a = 30.0; param2 Cleanup
double b = 50.0;
a
Vector2D v; b
Deletion
… v
} x
y

+ Fast
+ Automatic cleanup
- Not persistent
- “Limited” storage
Allocation

Allocation Initialization

Dynamic / Heap Allocation


Usage
void foo(int param1, int param2) Stack Heap
{ param1
double a = 30.0; param2 Cleanup
double b = 50.0;
a
Vector2D * v = new Vector2D; b
Pointer Deletion
v
… x
}
y

+ Persistent
+ “Infinite” storage
- Slow
- Manual cleanup
Allocation

Initialization Initialization

class Vector2D {
public: Usage

Vector2D(){
Constructors
x = 0.0;
• special methods which Cleanup
y = 0.0;
initialize an instance of a class
}
Vector2D(double x1, double y1){
• multiple variants with Deletion

x = x1;
different parameters possible
y = y1;
• initialize member variables
}
}; Vector2D v1();
Vector2D v2(10.0, 20.0);

Vector2D * v3 = new Vector2D();


Vector2D * v3 = new Vector2D(10.0, 20.0);
Allocation

Usage Initialization

Usage
Stack Objects Heap Objects
Vector2D v; Vector2D * pv = new Vector2D();
Cleanup
// access members // access members
v.x = 10.0; pv->x = 10.0;
Deletion
v.y = 20.0; pv->y = 20.0;

// call member functions // call member functions


double len = v.length(); double len = pv->length();
Allocation

Cleanup Initialization

class MyVector {
Destructor Usage
double * data;
public:
• Cleanup before destruction
MyVector(int dim){ • Free any acquired resources
Cleanup
data = new double[dim]; (file handles, heap memory)
}
Deletion
~MyVector() {
delete [] data;
}
};
Allocation

Deletion Initialization

Static / Stack Objects


Usage
void foo(int param1, int param2) Stack
{ param1
double a = 30.0; param2 Cleanup
double b = 50.0;
a
Vector2D v; b
Deletion
v.x = 10.0;
v
v.y = 20.0;
x
… End of Scope y
}

objects on stack are automatically deleted


at end of scope
Allocation

Deletion Initialization

Dynamic / Heap Objects


Usage
void foo(int param1, int param2) Stack Heap
{ param1
double a = 30.0; param2 Cleanup
double b = 50.0;
a
Vector2D * v = new Vector2D; b
Pointer Deletion
v->x = 10.0;
v
v->y = 20.0; x
… y

delete v;
} objects on heap must be deleted explicitly
Static class members
Static Member Variable
• Only a single instance of this variables exists
class Point2D • Much like a global variable
{ • Can be accessed by all instances
static int numPoints = 0; • Access by class name using ::, not instance
public:
int identifier; // Definition in a single .cpp file
double x; int Point2D::numPoints = 0;
double y;
// access without having an instance
cout << Point2D::numPoints << endl;
Point2D(double x1, double y1) {
identifier = numPoints++;
x = x1; Static Method
y = y1; • A method which is not applied on a class instance, but on
} the class itself
• Much like a global function
static void reset_count() { • Can only access and modify static member variables
numPoints = 0;
} // call static method, no instance required
Point2D::reset_count();
};
II. Building objects
Composition, Encapsulation, Inheritance, Polymorphism
Low-Level Model of an Airplane

Abstractions Engine 1

model domain concepts as classes Flaps


Engine 2
Aileron
High-Level Model of an Airplane
Elevator
Heading, Speed, Height
Latitude

Engine 3

Engine 4

Rudder

Longitude

Gear
Composition
• natural way of creating new
class Boeing747 objects is by building them out
{ of existing objects.
Engine engine1;
• Complex systems are composed
Engine engine2;
out of simpler sub-systems
Engine engine3;
Engine engine4;
Gear frontGear;
Gear backGear; Engine Engine Engine Engine Gear Gear …

};

Boing747
Encapsulation gearUp

Boeing747
speed

gearDown altitude
class Boeing747{
private:
hidden
Gear gear;
• View objects as black box
public:
void gearUp() { • Don’t operate directly on internal data
// update physics of an object
… • Implementation details are hidden behind
gear.up();
interface
} • make member variables private
visible
void gearDown() { • Use methods of the interface to perform
// update physics
certain actions
… • Some languages, e.g. C++ and Java, help
gear.down(); enforce this through specifiers: public,
} private, protected
};
Problems without Encapsulation
void Boeing747::gearDown() {
class Boeing747{ if(gear.isUp()) {
public: totalAirFriction += 20.0;
double totalAirFriction; gear.down();
Gear gear; }
void gearUp(); }
void gearDown(); void Boeing747::gearUp() {
double speed(); if(gear.isDown()) {
}; totalAirFriction -= 20.0;
gear.down();
Boeing747 * a = new Boing747(); }
}

a->gearDown(); ≠ a->gear.down(); void Boeing747::speed() {


// function of thrust & friction
Encapsulation ensures that side effects and domain knowledge return …
are kept inside the class which is responsible for them.
}
Type hierarchies and Inheritance
Base Class

• Smalltalk first added the concept of inheritance


• Objects of a class can inherit state and behavior of
a base class and make adjustments.
• Usages: Derived Class
• Extend classes with new functionality
• Make minor modifications
• Extract common functionality.
Type hierarchies and Inheritance
Airplane

Boeing747 Cessna206h
Type hierarchies and Inheritance
class Boeing747 { class Cessna206h {
float longitude, latitude; float longitude, latitude;
float heading, speed; float heading, speed;
float altitude; float altitude;
... ...
public: public:
void fullThrottle() { void fullThrottle() {
engine1.maxThrottle(); engine1.maxThrottle();
engine2.maxThrottle(); speed = …;
engine3.maxThrottle(); }
engine4.maxThrottle(); }
speed = …;
}
}
class Airplane {

Inheritance public:
float longitude, latitude;
float heading, speed; Common structure
float altitude;

};

class Boeing747 : Airplane { class Cessna206h : Airplane {


... ...
public: public:
void fullThrottle() { void fullThrottle() {
engine1.maxThrottle(); engine1.maxThrottle(); Derived classes
inherit structure
engine2.maxThrottle(); speed = …;
of Airplane
engine3.maxThrottle(); }
engine4.maxThrottle(); }
speed = …;
}
}
class Airplane {

Inheritance public:
float longitude, latitude;
float heading, speed;
float altitude;
virtual void fullThrottle(); Common interface
};

class Boeing747 : Airplane { class Cessna206h : Airplane {


... ...
public: public:
void fullThrottle() { void fullThrottle() {
engine1.maxThrottle(); engine1.maxThrottle(); Derived classes
implement or
engine2.maxThrottle(); speed = …;
extend interface
engine3.maxThrottle(); } of Airplane
engine4.maxThrottle(); }
speed = …;
}
}
Polymorphism
• Objects of derived classes can
Boeing747 * a = new Boeing747();
Airplane * b = new Boeing747();
Airplane * c = new Cessna206h();
be used as base class objects.
• Polymorphism allows us to
// as expected: will call Boeing747::fullThrottle modify the behavior of base
a->fullThrottle();
classes and replacing the
// NEW! will call Boeing747::fullThrottle
implementation of methods.
b->fullThrottle(); • Polymorphic methods must be
declared virtual (in C++)
// NEW! will call Cessna206h::fullThrottle
c->fullThrottle();
Polymorphism
// store objects of different types in a • Use base class to implement
// datastructure using its base class
Airplane ** airplanes = new Airplane*[10];
general algorithms and data
... structures which work with
for(int i = 0; i < 10; i++) {
// will choose correct implementation any derived type
• Dynamic dispatch determines
// dynamically at runtime
airplanes[i]->fullThrottle();
} the type of an object at
runtime and executes the
void foo(Airplane & a) {
// this function will work with
correct method
// any class derived from Airplane
}
Abstract classes
class Airplane {
public:
float longitude, latitude;
• Virtual functions without
implementation are called
float heading, speed;
pure-virtual functions.
float altitude;
virtual void fullThrottle() = 0; • Classes containing pure-
}; virtual functions can not be
instantiated and are called
abstract classes
• Their behavior must be
defined in derived classes
Is-A vs. Has-A Relationship
• Use composition to manage complexity
• Use inheritance to extract common functionality
• Use polymorphism to implement general algorithms
which are independent of specific types
• Composition = Has-A Relationship
E.g. A Boeing 747 has four jet engines.
• Inheritance = Is-A Relationship:
E.g. A Cessna is an airplane. So is a Boeing 747.
III. Best Practices
Recommendations, Design Patterns
Keep your interfaces simple, clean and
consistent
• Methods in a class should be as orthogonal as possible
 avoid method that do almost the same
• Methods with the same name should do similar things
• Use encapsulation
• This reduces coupling
• Changing your implementation internals becomes easier
• Access data with getter / setter methods
• Use const to limit what methods can do with your data
• This lets the compiler help you enforce who can manipulate data
• Compiler Optimization hint
• Consider using lazy-initialization for costly object properties
Getters & Setters
class SomeClass {
const method does not modify data
int propertyA;
public:
int getPropertyA() const { Getter function
return propertyA;
}

void setPropertyA(int value) { Setter function


// setters allow you to validate data
// before accepting it
if (value > 0 && value < 100) {
propertyA = value;
}
}
}
Lazy Initialization
class SomeClass {
LargeDataSet * dataSet;
public:
SomeClass() : dataSet(nullptr) Don’t create data set during construction
{
}

~SomeClass() {
delete dataSet; Won’t do anything if data set is never created
}

int getDataSet() {
if (!dataSet) {
dataSet = new LargeDataSet(); Create data set set on-demand
}
return dataSet;
}
}
Base class destructors should be virtual
• If you want to allow deletion of objects by using their base class,
make sure their destructor is virtual
class Base { class Base2 {
public: public:
~Base(); virtual ~Base2(){}
} }

class Derived : public Base { class Derived2 : public Base2 {


public: public:
~Derived(); virtual ~Derived2(){}
} }

Base * object = new Derived(); Base * object = new Derived();


delete object; // undefined behavior!!! delete object;
// best case: only ~Base() is called // first ~Derived() is called,
// potential memory leak // then ~Base()
Don’t use virtual functions during
construction and destruction
• It’s a bad idea. Even if you think you could use it, you will not get what
you want. dynamic dispatch
is disabled during
class Base { construction & class Derived : public Base {
public: public:
destruction. These
Base() { Derived() : Base() {}
callVirtual(); will always call the virtual ~Derived() {
} base class version! cout << “~Derived()” << endl;
virtual ~Base() { }
cout << “~Base()” << endl; virtual void callVirtual() {
callVirtual(); cout << “Derived ::callVirtual” << endl;
} }
virtual void callVirtual() { }
cout << “Base::callVirtual” << endl;
}
}
Don’t reinvent the wheel
• Learn about available libraries
• C++
• STL  we‘ll have a look at it later this week
• Boost
• GUI toolkits if you need them (e.g. Qt)
• Python
• Modules
• pip, setuptools
• OOP is all about writing reusable code, so use code that‘s already
there and has been tested by other people
• Learn about design patterns
Design Patterns
• Term was made popular by the book “Design Patterns: Elements of
Reusable Object-Oriented Software”, aka. The Gang of Four book
(1994)
• Collection of generic solutions of common problems in OOP software
• Often used in libraries
• Part of the vocabulary computer scientists use to simplify
communication
Design Patterns: Main categories

Creational Patterns Structural Patterns Behavioral Patterns

• Abstract Factory • Adapter • Chain of Responsibility


• Builder • Bridge • Command
• Factory Method • Composite • Interpreter
• Prototype • Decorator • Iterator
• Singleton • Façade • Mediator
• Flyweight • Memento
• Proxy • Observer
• State
• Strategy
• Template
• Visitor
Creational Patterns

Factory Methods
• Create objects without having to know specific language type
• Circumvent limitations of constructors
• No return result
only exceptions
• Constrained naming
e.g. can’t have two constructors with same parameter types
• Statically bound creation
there is no dynamic binding for constructors, you have to know which type you want
to instantiate
• No virtual constructors
• Factory methods can range from very simple implementations to complex
selection schemes
Creational Patterns

Factory Methods – Simple Example


class IShape { IShape * createShape(const std::string & name)
public: {
virtual void draw(); if (name == "rectangle") {
}; return new Rectangle();
}
class Rectangle : IShape;
class Circle : IShape; if (name == "circle") {
class Triangle : IShape; return new Circle();
}
class ShapeFactory {
public: if (name == "triangle") {
IShape * createShape(const std::string & name); return new Triangle();
} }

return nullptr;
}
// parse user input This factory
ShapeFactory factory;
string selectedShape = getUserInput(); implementation is hard
coded. But you can easily
// create object at runtime write an extensible
IShape * new_object = factory.createShape(selectedShape);
factory.
Structural Patterns

Adapter
• Used to make an object of one type compatible to another
• Typical use case:
• You defined your own types of objects with a certain interface
• You want to use an external library to manipulate your objects
• However the interface expected by library is different to the one you used
• Instead of rewriting you code, you can create an Adapter class, which
maps one interface to another.
Structural Patterns

Adapter – Example
class ForceComputation { class LegacyClass {
public: public:
virtual void compute_force(Vector3D & force); virtual void compute_force(double * force);
}; };

class ForceComputationAdapter : public ForceComputation {


LegacyClass * legacy;
public:
ForceComputationAdapter(LegacyClass * src) : legacy(src) {
}

virtual void compute_force(Vector3D & force) {


double f[3];
legacy->compute_force(&f[0]);
force.x = f[0];
force.y = f[1];
force.z = f[2];
}
};
Behavioral Patterns

Strategy
• Used to keep parts of a larger implementations replacable
• You define a common interface to do a certain task
• Any class which implements that interface can be used in larger
implementation
• Allows you to exchange object of that interface during runtime
• Typical use case:
• Define a common interface to get data
• Interface can be implemented by classes which use files, databases, web
services, etc.
Behavioral Patterns

Strategy - Example
class IRandomNumberGenerator { class DiceRoll : public IRandomNumberGenerator {
public: public:
double getNextDouble() = 0; double getNextDouble() {
} // guaranteed to be random,
// determined with a fair dice roll
return 4;
class MyUncrackableEncryption { }
IRandomNumberGenerator * random; }

void setRandomNumberGenerator(IRandomNumberGenerator * r) {
random = r;
}

void encrypt(char * data, size_t length) {


double r = random->getNextDouble(); MyUncrackableEncryption e;
... DiceRoll d;
}
e.setRandomNumberGenerator(d);
void decrypt(char * data, size_t length) { e.encrypt(…)
...
}
}
IV. Conclusion
Pro and Cons of Object-Orientated Programming
Benefits of OOP
• OOP encourages modularity and consistency
• Side effects from changing data are controlled
• Separate interface and implementation
• Control visibility and read/write access to data, violations can be
found be the compiler
• Top level code becomes terse (-> less errors)
• Natural semantics for stateful items
• More compile time checking of correct use
Problems of OOP
• Designing good class hierarchies is hard and takes experience
• Bad design is easy
• Objects get bloated by unneeded members
• Inconsistent implementations (methods that have the same name don't do the
same thing)
• Overhead of dynamic dispatch
• Inefficient data access for caching, vectorization
• Flow of control scattered across classes, especially with very deep class
hierarchies
• Implicit actions (copy constructor, assignment operator) can become very
expensive
Final Recommendations
• Use OOP in moderation
• use OOP where it helps modularity
• but not everything that can be an object needs to be
• At the upper level(s) imperative programming (using collections of
objects) is often cleaner
• Use abstraction where details need not to be known, but do not hide
what is important
• Object oriented programming is not bound to a specific programming
language; some require less code to be written; the important part is
sticking to the established conventions

You might also like