200 lines
6.1 KiB
Markdown
200 lines
6.1 KiB
Markdown
# 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”
|
||
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;
|
||
};
|
||
}; |