Skip to Content
CSE332SObject-Oriented Programming Lab (Lecture 16)

CSE332S Object-Oriented Programming in C++ (Lecture 16)

Intro to OOP design and principles

Review: Class Design

Designing a class to work well with the STL:

  • What operators are required of our class?
    • operator< for ordered associative containers, operator== for unordered associative containers
    • operator<< and operator>> for interacting with iostreams
    • Algorithms require particular operators as well

Designing a class that manages dynamic resources:

  • Must think about copy control
    • Shallow copy or deep copy?
    • When should the dynamic resources be cleaned up?
    • Move semantics for efficiency

OOP Design: How do we combine objects to create complex software?

Goals - Software should be:

  • Flexible
  • Extensible
  • Reusable

Today: 4 Principles of object-oriented programming

  1. Encapsulation
  2. Abstraction
  3. Inheritance
  4. Polymorphism

Review: Client Code, interface vs. implementation

Today we will focus on a single class or family of classes related via a common base class and client code that interacts with it.

Next time: Combining objects to create more powerful and complex objects

Client code: code that has access to an object (via the object directly, a reference to the object, or a pointer/smart pointer to the object).

  • Knows an object’s public interface only, not its implementation.

Interface: The set of all functions/operators (public member variables in C++ as well) a client can request of an object

Implementation: The definition of an object’s interface. State (member variables) and definitions of member functions/operators

Principle 1: Encapsulation

Data and behaviors are encapsulated together behind an interface

  1. Member functions have direct access to the member variables of the object via “this”
  2. Benefit: Simplifies function calls (much smaller argument lists)

Proper encapsulation:

  1. Data of a class remains internal (not enforced in C++)
  2. Client can only interact with the data of an object via its interface

Benefit:

(Flexible) Reduces impact of change - Easy to change how an object is stored without needing to modify client code that uses the object.

Principle 2: Abstraction

An object presents only the necessary interface to client code

  1. Hides unnecessary implementation details from the client
    a. Member functions that client code does not need should be private or protected

We see abstraction everyday:

  • TV
  • Cell phone
  • Coffee machine

Benefits:

  1. Reduces code complexity, makes an object easier to use
  2. (Flexible) Reduces impact of change - internal implementation details can be modified without modification to client code

Principle 3: Inheritance (public inheritance in C++)

“Implementation” inheritance - class inherits interface and implementation of its base class

Benefits:

  • Remove redundant code by placing it in a common base class.
  • (Reusable) Easily extend a class to add new functionality.

“Interface” inheritance - inherit the interface of the base class only (abstract base class in C++, pure virtual functions)

Benefits:

  • Reduce dependencies between base/derived class
  • (Flexible, Extensible, Reusable) Program a client to depend on an interface rather than a specific implementation (more on this later)

One More Useful C++ Construct: Multiple Inheritance

C++ allows a class to inherit from more than one base class

class Bear: public ZooAnimal {/*...*/}; class Panda: public Bear, public Endangered {/*...*/};

Construction order - all base classes are constructed first:

  • all base classes -> derived classes member variables -> constructor body

Destruction order - opposite of construction order:

  • Destructor body -> derived classes member variables -> all base class destructors

Rule of thumb: When using multiple inheritance, a class should inherit implementation from a single base class only. Any number of interfaces may be inherited (this is enforced in Java)

Principle 4: Polymorphism

A single interface may have many different implementations (virtual functions and function overriding in C++)

Benefits:

  1. Avoid nasty switch statements (function calls resolved dynamically)
  2. (Flexible) Allows the implementation of an interface to change at run-time

Program to an interface

Client should restrict variables to an interface only, not a specific implementation

  • Extensible, reusable: New subclasses that define the interface can be created and used without modification to the client. Easy to add new functionality. Easy to reuse client.
  • Reduce impact of change: Decouples client from concrete classes it uses.
  • Flexible: The implementation of an interface used by the client can change at run-time.

In C++:

  • Abstract base class using pure virtual functions to declare the interface
  • Implement the interface in subclasses via public inheritance
  • Client maintains reference or pointer to the base class
  • Calls through the reference or pointer are polymorphic
// declare printable interface class printable { public: virtual void print(ostream &o) = 0; }; // derived classes defines printable // interface class smiley : public printable { public: virtual void print(ostream &o) { o << ":)" ; }; }; class frown : public printable { public: virtual void print(ostream &o) { o << ":("; }; }; int main(int argc, char * argv[]) { smiley s; // s restricted to // a smiley object s.print(); // p may point to an object // of any class that defines // the printable interface printable * p = generateOutput(); // Client unaware of the // implementation of print() p->print(); return 0; }

Program to an interface Allows easily extensible designs: anything that defines the printable interface can be used with our client

class Book : public printable { vector<string> pages; public: virtual void print(ostream &o) { for(unsigned int page = 0; page < pages.size(); ++page){ o << "page: " << page << endl; o << pages[i] << endl; }; };
Last updated on