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

237 lines
7.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 8)
## From procedural to object-oriented programming
Procedural programming
- Focused on **functions** and the call stack
- Data and functions treated as **separate** abstractions
- Data must be passed into/returned out of functions, functions work on any piece of data that can be passed in via parameters
Object-oriented programming
- Data and functions packaged **together** into a single abstraction
- Data becomes more interesting (adds behavior)
- Functions become more focused (restricts data scope)
## Object-oriented programming
- Data and functions packaged together into a single abstraction
- Data becomes more interesting (adds behavior)
- Functions become more focused (restricts data scope)
### Today:
- An introduction to classes and structs
- Member variables (state of an object)
- Constructors
- Member functions/operators (behaviors)
- Encapsulation
- Abstraction
At a later date:
- Inheritance (class 12)
- Polymorphism (12)
- Developing reusable OO designs (16-21)
## Class and struct
### From C++ Functions to C++ Structs/Classes
C++ functions encapsulate behavior
- Data used/modified by a function must be passed in via parameters
- Data produced by a function must be passed out via return type
Classes (and structs) encapsulate related data and behavior (**Encapsulation**)
- Member variables maintain each objects state
- Member functions (methods) and operators have direct access to member variables of the object on which they are called
- Access to state of an object is often restricted
- **Abstraction** - a class presents only the relevant details of an object, through its public interface.
### C++ Structs vs. C++ Classes?
Class members are **private** by default, struct members are **public** by default
When to use a struct
- Use a struct for things that are mostly about the data
- **Add constructors and operators to work with STL containers/algorithms**
When to use a class
- Use a class for things where the behavior is the most important part
- Prefer classes when dealing with encapsulation/polymorphism (later)
```cpp
// point2d.h - struct declaration
struct Point2D {
Point2D(int x, int y);
bool operator< (const Point2D &) const; // a const member function
int x_; // promise a member variable
int y_;
};
```
```cpp
// point2d.cpp - methods functions
#include "point2d.h"
Point2D::Point2D(int x, int y) :
x_(x), y_(y) {}
bool Point2D::operator< (const Point2D &other) const {
return x_ < other.x_ || (x_ == other.x_ && y_ < other.y_);
}
```
### Structure of a class
```cpp
class Date {
public: // public stores the member functions and variables accessible to the outside of class
Date(); // default constructor
Date (const Date &); // copy constructor
Date(int year, int month, int day); // constructor with parameters
virtual ~Date(); // (virtual) destructor
Date& operator= (const Date &); // assignment operator
int year() const; // accessor
int month() const; // accessor
int day() const; // accessor
void year(int year); // mutator
void month(int month); // mutator
void day(int day); // mutator
string yyymmdd() const; // generate a string representation of the date
private: // private stores the member variables that only the class can access
int year_;
int month_;
int day_;
};
```
#### Class constructor
- Same name as its class
- Establishes invariants for objects of the class
- **Base class/struct and member initialization list**
- Used to initialize member variables
- Used to construct base class when using inheritance
- Must initialize const and reference members there
- **Runs before the constructor body, object is fully initialized in constructor body**
```cpp
// date.h
class Date {
public:
Date();
Date(const Date &);
Date(int year, int month, int day);
~Date();
// ...
private:
int year_;
int month_;
int day_;
};
```
```cpp
// date.cpp
Date::Date() : year_(0), month_(0), day_(0) {} // initialize member variables, use pre-defined values as default values
Date::Date(const Date &other) : year_(other.year_), month_(other.month_), day_(other.day_) {} // copy constructor
Date::Date(int year, int month, int day) : year_(year), month_(month), day_(day) {} // constructor with parameters
// ...
```
#### More on constructors
Compiler defined constructors:
- Compiler only defines a default constructor if no other constructor is declared
- Compiler defined constructors simply construct each member variable using the same operation
Default constructor for **built-in types** does nothing (leaves the variable uninitialized)!
It is an error to read an uninitialized variable
## Access control and friend declarations
Declaring access control scopes within a class - where is the member visible?
- `private`: visible only within the class
- `protected`: also visible within derived classes (more later)
- `public`: visible everywhere
Access control in a **class** is `private` by default
- Its better style to label access control explicitly
A `struct` is the same as a `class`, except access control for a `struct` is `public` by default
- Usually used for things that are “mostly data”
### Issues with Encapsulation in C++
Encapsulation - state of an object is kept internally (private), state of an object can be changed via calls to its public interface (public member functions/operators)
Sometimes two classes are closely tied:
- One may need direct access to the others internal state
- But, other classes should not have the same direct access
- Containers and iterators are an example of this
We could:
1. Make the internal state public, but this violates **encapsulation**
2. Use an inheritance relationship and make the internal state protected, but the inheritance relationship doesnt make sense
3. Create fine-grained accessors and mutators, but this clutters the interface and violates **abstraction**
### Friend declarations
Offer a limited way to open up class encapsulation
C++ allows a class to declare its “friends”
- Give access to specific classes or functions
Properties of the friend relation in C++
- Friendship gives complete access
- Friend methods/functions behave like class members
- public, protected, private scopes are all accessible by friends
- Friendship is asymmetric and voluntary
- A class gets to say what friends it has (giving permission to them)
- But one cannot “force friendship” on a class from outside it
- Friendship is not inherited
- Specific friend relationships must be declared by each class
- “Your parents friends are not necessarily your friends”
```cpp
// in Foo.h
class Foo {
friend ostream &operator<< (ostream &out, const Foo &f); // declare a friend function, can be added at any line of the class declaration
public:
Foo(int x);
~Foo();
// ...
private:
int baz_;
};
ostream &operator<< (ostream &out, const Foo &f);
```
```cpp
// in Foo.cpp
ostream &operator<< (ostream &out, const Foo &f) {
out << f.baz_; // access private member variable via friend declaration
return out;
}
```