100% found this document useful (1 vote)
71 views

Classes and Structs in C++: Based On Materials by Bjarne Stroustrup

Classes and structs are user-defined types that can encapsulate both data and functions together. The main differences are that class members are private by default while struct members are public. Classes are generally used when the members need access control to maintain an invariant, while structs are used for plain data structures. Well-designed classes control access to their members through public member functions to provide a clean interface and make debugging and maintenance easier.

Uploaded by

john albert
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (1 vote)
71 views

Classes and Structs in C++: Based On Materials by Bjarne Stroustrup

Classes and structs are user-defined types that can encapsulate both data and functions together. The main differences are that class members are private by default while struct members are public. Classes are generally used when the members need access control to maintain an invariant, while structs are used for plain data structures. Well-designed classes control access to their members through public member functions to provide a clean interface and make debugging and maintenance easier.

Uploaded by

john albert
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 29

Classes and Structs in C++

Based on materials by Bjarne Stroustrup


www.stroustrup.com/Programming
Overview
•  Classes
–  Implementation and interface
–  Constructors
–  Member functions
•  Enumerations
•  Operator overloading

2
Classes
•  The idea:
–  A class directly represents a concept in a program
•  If you can think of “it” as a separate entity, it is plausible that
it could be a class or an object of a class
•  Examples: vector, matrix, input stream, string, FFT, valve
controller, robot arm, device driver, picture on screen, dialog
box, graph, window, temperature reading, clock
–  A class is a (user-defined) type that specifies how
objects of its type can be created and used
–  In C++ (as in most modern languages), a class is the
key building block for large programs
•  And very useful for small ones also
–  The concept was originally introduced in Simula67
3
Members and member access
•  One way of looking at a class;
class X { // this class’ name is X
// data members (they store information)
// function members (they do things, using the information)
};

•  Example
class X {
public:
int m; // data member
int mf(int v) { int old = m; m=v; return old; } // function member
};
X var; // var is a variable of type X
var.m = 7; // access var’s data member m
int x = var.mf(9); // call var’s member function mf()
4
Classes

•  A class is a user-defined type


class X { // this class’ name is X
public: // public members -- that’s the interface to users
// (accessible by all)
// functions
// types
// data (often best kept private)
private: // private members -- that’s the implementation details
// (accessible by members of this class only)
// functions
// types
// data
};
5
Struct and class
•  Class members are private by default:
class X {
int mf();
// …
};
•  Means
class X {
private:
int mf();
// …
};
•  So
X x; // variable x of type X
int y = x.mf(); // error: mf is private (i.e., inaccessible)

6
Struct and class
•  A struct is a class where members are public by default:
struct X {
int m;
// …
};

•  Means
class X {
public:
int m;
// …
};

•  structs are primarily used for data structures where the


members can take any value
7
Date:
Structs my_birthday: y
m

// simplest Date (just data) d


struct Date {
int y,m,d; // year, month, day
};

Date my_birthday; // a Date variable (object)

my_birthday.y = 12;
my_birthday.m = 30;
my_birthday.d = 1950; // oops! (no day 1950 in month 30)
// later in the program, we’ll have a problem

8
Date:
Structs my_birthday: y
m
// simple Date (with a few helper functions for convenience) d
struct Date {
int y,m,d; // year, month, day
};

Date my_birthday; // a Date variable (object)

// helper functions:
void init_day(Date& dd, int y, int m, int d); // check for valid date and initialize

void add_day(Date&, int n); // increase the Date by n days


// …

init_day(my_birthday, 12, 30, 1950); // run time error: no day 1950 in month 30
9
Date:
Structs my_birthday: y 1950
m 12
// simple Date d
30
// guarantee initialization with constructor
// provide some notational convenience
struct Date {
int y,m,d; // year, month, day
Date(int y, int m, int d); // constructor: check for valid date and initialize
void add_day(int n); // increase the Date by n days
};
// …
Date my_birthday; // error: my_birthday not initialized
Date my_birthday(12, 30, 1950); // oops! Runtime error
Date my_day(1950, 12, 30); // ok
my_day.add_day(2); // January 1, 1951
my_day.m = 14; // ouch! (now my_day is a bad date)
10
Date:
Classes my_birthday: y 1950
m 12
// simple Date (control access) d 30
class Date {
int y,m,d; // year, month, day
public:
Date(int y, int m, int d); // constructor: check for valid date and initialize
// access functions:
void add_day(int n); // increase the Date by n days
int month() { return m; }
int day() { return d; }
int year() { return y; }
};
// …
Date my_birthday(1950, 12, 30); // ok
cout << my_birthday.month() << endl; // we can read
my_birthday.m = 14; // error: Date::m is private
11
Classes

•  The notion of a “valid Date” is an important special case of the


idea of a valid value
•  We try to design our types so that values are guaranteed to be valid
–  Or we have to check for validity all the time
•  A rule for what constitutes a valid value is called an “invariant”
–  The invariant for Date (“Date must represent a date in the past, present, or
future”) is unusually hard to state precisely
•  Remember February 28, leap years, etc.
•  If we can’t think of a good invariant, we are probably dealing with
plain data
–  If so, use a struct
–  Try hard to think of good invariants for your classes
•  that saves you from poor buggy code

12
Date:
Classes my_birthday: y 1950
m 12
// simple Date (some people prefer implementation details last) d 30
class Date {
public:
Date(int y, int m, int d); // constructor: check for valid date and initialize
void add_day(int n); // increase the Date by n days
int month();
// …
private:
int y,m,d; // year, month, day
};
Date::Date(int yy, int mm, int dd) // definition; note :: “member of”
:y(yy), m(mm), d(dd) { /* … */ }; // note: member initializers
void Date::add_day(int n) { /* … */ }; // definition

13
Date:
Classes my_birthday: y 1950
m 12
// simple Date (some people prefer implementation details last) d 30
class Date {
public:
Date(int y, int m, int d); // constructor: check for valid date and initialize
void add_day(int n); // increase the Date by n days
int month();
// …
private:
int y,m,d; // year, month, day
};

int month() { return m; } // error: forgot Date::


// this month() will be seen as a global function
// not the member function, can’t access members
int Date::season() { /* … */ } // error: no member called season
14
Classes
// simple Date (what can we do in case of an invalid date?)
class Date {
public:
class Invalid { }; // to be used as exception
Date(int y, int m, int d); // check for valid date and initialize
// …
private:
int y,m,d; // year, month, day
bool check(int y, int m, int d); // is (y,m,d) a valid date?
};
Date:: Date(int yy, int mm, int dd)
: y(yy), m(mm), d(dd) // initialize data members
{
if (!check(y,m,d)) throw Invalid(); // check for validity
}
15
Classes

•  Why bother with the public/private distinction?


•  Why not make everything public?
–  To provide a clean interface
•  Data and messy functions can be made private
–  To maintain an invariant
•  Only a fixed set of functions can access the data
–  To ease debugging
•  Only a fixed set of functions can access the data
•  (known as the “round up the usual suspects” technique)
–  To allow a change of representation
•  You need only to change a fixed set of functions
•  You don’t really know who is using a public member
16
Enumerations

•  An enum (enumeration) is a very simple user-defined


type, specifying its set of values (its enumerators)
•  For example:
enum Month {
jan=1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec
};

Month m = feb;
m = 7; // error: can’t assign int to Month
int n = m; // ok: we can get the numeric value of a Month
Month mm = Month(7); // convert int to Month (unchecked)

17
Enumerations

•  Simple list of constants:


enum { red, green }; // the enum { } doesn’t define a scope
int a = red; // red is available here
enum { red, blue, purple }; // error: red defined twice

•  Type with list of constants


enum Color { red, green, blue, /* … */ };
enum Month { jan, feb, mar, /* … */ };

Month m1 = jan;
Month m2 = red; // error red isn’t a Month
Month m3 = 7; // error 7 isn’t a Month
int i = m1; // ok: an enumerator is converted to its value, i==0
18
Enumerations – Values

•  By default
// the first enumerator has the value 0,
// the next enumerator has the value “one plus the value of the
// enumerator before it”
enum { horse, pig, chicken }; // horse==0, pig==1, chicken==2

•  You can control numbering


enum { jan=1, feb, march /* … */ }; // feb==2, march==3
enum stream_state { good=1, fail=2, bad=4, eof=8 };
int flags = fail+eof; // flags==10
stream_state s = flags; // error: can’t assign an int to a stream_state
stream_state s2 = stream_state(flags); // explicit conversion (be careful!)

19
Classes Date:
1950
// simple Date (use Month type) my_birthday: y
class Date { m 12
public:
d 30
enum Month {
jan=1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec
};
Date(int y, Month m, int d); // check for valid date and initialize
// …
private:
int y; // year
Month m;
int d; // day
};
Date my_birthday(1950, 30, Date::dec); // error: 2nd argument not a Month
Date my_birthday(1950, Date::dec, 30); // ok
20
Const

class Date {
public:
// …
int day() const { return d; } // const member: can’t modify
void add_day(int n); // non-const member: can modify
// …
};

Date d(2000, Date::jan, 20);


const Date cd(2001, Date::feb, 21);

cout << d.day() << " – " << cd.day() << endl; // ok
d.add_day(1); // ok
cd.add_day(1); // error: cd is a const
21
Const
//
Date d(2004, Date::jan, 7); // a variable
const Date d2(2004, Date::feb, 28); // a constant
d2 = d; // error: d2 is const
d2.add(1); // error d2 is const
d = d2; // fine
d.add(1); // fine

d2.f(); // should work if and only if f() doesn’t modify d2


// how do we achieve that? (say that’s what we want, of course)

22
Const member functions
// Distinguish between functions that can modify (mutate) objects
// and those that cannot (“const member functions”)
class Date {
public:
// …
int day() const; // get (a copy of) the day
// …
void add_day(int n); // move the date n days forward
// …
};

const Date dx(2008, Month::nov, 4);


int d = dx.day(); // fine
dx.add_day(4); // error: can’t modify constant (immutable) date

23
Classes
•  What makes a good interface?
–  Minimal
•  As small as possible
–  Complete
•  And no smaller
–  Type safe
•  Beware of confusing argument orders
–  Const correct

24
Classes
n Essen%al  opera%ons  
n Default  constructor  (defaults  to:  nothing)  
n No  default  if  any  other  constructor  is  declared  
n Copy  constructor  (defaults  to:  copy  the  member)  
n Copy  assignment  (defaults  to:  copy  the  members)  
n Destructor  (defaults  to:  nothing)  
n For  example  
Date  d;  //  error:  no  default  constructor  
Date  d2  =  d;  //  ok:  copy  ini3alized  (copy  the  elements)  
d  =  d2;  //  ok  copy  assignment  (copy  the  elements)  

25
Interfaces and “helper functions”

•  Keep a class interface (the set of public functions)


minimal
–  Simplifies understanding
–  Simplifies debugging
–  Simplifies maintenance

•  When we keep the class interface simple and


minimal, we need extra “helper functions” outside
the class (non-member functions)
–  E.g. == (equality) , != (inequality)
–  next_weekday(), next_Sunday()

26
Helper functions
Date next_Sunday(const Date& d)
{
// access d using d.day(), d.month(), and d.year()
// make new Date to return
}
Date next_weekday(const Date& d) { /* … */ }

bool operator==(const Date& a, const Date& b)


{
return a.year()==b.year()
&& a.month()==b.month()
&& a.day()==b.day();
}
bool operator!=(const Date& a, const Date& b) { return !(a==b); }
27
Operator overloading
•  You can define almost all C++ operators for a
class or enumeration operands
–  that’s often called “operator overloading”
enum Month {
jan=1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec
};
Month operator++(Month& m) // prefix increment operator
{
m = (m==dec) ? jan : Month(m+1); // “wrap around”
return m;
}
Month m = nov;
++m; // m becomes dec
++m; // m becomes jan
28
Operator overloading
•  You can define only existing operators
–  E.g., + - * / % [] () ^ ! & < <= > >=
•  You can define operators only with their conventional number
of operands
–  E.g., no unary <= (less than or equal) and no binary ! (not)
•  An overloaded operator must have at least one user-defined
type as operand
–  int operator+(int,int); // error: you can’t overload built-in +
–  Vector operator+(const Vector&, const Vector &); // ok
•  Advice (not language rule):
–  Overload operators only with their conventional meaning
–  + should be addition, * be multiplication, [] be access, () be call, etc.
•  Advice (not language rule):
–  Don’t overload unless you really have to

29

You might also like