Files
NoteNextra-origin/content/CSE332S/CSE332S_L16.md
2025-09-17 14:27:46 -05:00

200 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 objects 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 objects 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”
1. 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
```cpp
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
```cpp
// 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
```cpp
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;
};
};