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

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 object’s 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)
// 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_; };
// 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

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
// date.h class Date { public: Date(); Date(const Date &); Date(int year, int month, int day); ~Date(); // ... private: int year_; int month_; int day_; };
// 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

  • It’s 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 other’s 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 doesn’t 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”
// 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);
// in Foo.cpp ostream &operator<< (ostream &out, const Foo &f) { out << f.baz_; // access private member variable via friend declaration return out; }
Last updated on