03 Classes I
03 Classes I
Lecture 3 — Classes I
Review from Lecture 2
• Vectors are dynamically-sized arrays
• Vectors, strings and other containers should be:
– passed by reference when they are to be changed, and
– passed by constant reference when they aren’t.
If you forget the & and pass by value, the object will be copied which is expensive for containers with lots of
elements. Note: This is unlike arrays, which are not copied when passed by value.
• Vectors can “contain” any type of objects, including strings and other vectors.
Today’s Lecture
• Classes in C++; Types and defining new types; Example: A Date class;
• Class declaration: member variables and member functions; Using the class member functions;
• Member function implementation; Class scope; Classes vs. structs; Designing classes;
• We are now ready to start defining our own new types using classes.
#include <iostream>
#include "date.h"
int main() {
std::cout << "Please enter today's date.\n"
<< "Provide the month, day and year: ";
int month, day, year;
std::cin >> month >> day >> year;
Date today(month, day, year);
Date Sallys_Birthday(9,29,1995);
if (sameDay(tomorrow, Sallys_Birthday)) {
std::cout << "Hey, tomorrow is Sally's birthday!\n";
}
std::cout << "The last day in this month is " << today.lastDayInMonth() << std::endl;
return 0;
}
• Important: Each object we create of type Date has its own distinct member variables.
• Calling class member functions for class objects uses the “dot” notation. For example, tomorrow.increment();
• Note: We don’t need to know the implementation details of the class member functions in order to understand
this example. This is an important feature of object oriented programming and class design.
3.5 Exercise
Add code to date_main.cpp to read in another date, check if it is a leap-year, and check if it is equal to tomorrow.
Output appropriate messages based on the results of the checks.
2
3.6 Class Declaration (date.h) & Implementation (date.cpp)
A class implementation usually consists of 2 files. First we’ll look at the header file date.h
// File: date.h
// Purpose: Header file with declaration of the Date class, including
// member functions and private member variables.
class Date {
public:
Date();
Date(int aMonth, int aDay, int aYear);
// ACCESSORS
int getDay() const;
int getMonth() const;
int getYear() const;
// MODIFIERS
void setDay(int aDay);
void setMonth(int aMonth);
void setYear(int aYear);
void increment();
// prototypes for other functions that operate on class objects are often
// included in the header file, but outside of the class declaration
bool sameDay(const Date &date1, const Date &date2); // same day & month?
And here is the other part of the class implementation, the implementation file date.cpp
// File: date.cpp
// Purpose: Implementation file for the Date class.
#include <iostream>
#include "date.h"
// array to figure out the number of days, it's used by the auxiliary function daysInMonth
const int DaysInMonth[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
Date::Date(int aMonth, int aDay, int aYear) { // construct from month, day, & year
month = aMonth;
day = aDay;
year = aYear;
}
3
int Date::getDay() const {
return day;
}
void Date::setDay(int d) {
day = d;
}
void Date::setMonth(int m) {
month = m;
}
void Date::setYear(int y) {
year = y;
}
void Date::increment() {
if (!isLastDayInMonth()) {
day++;
} else {
day = 1;
if (month == 12) { // December
month = 1;
year++;
} else {
month++;
}
}
}
4
3.7 Class scope notation
• Date:: indicates that what follows is within the scope of the class.
• Within class scope, the member functions and member variables are accessible without the name of the object.
3.8 Constructors
These are special functions that initialize the values of the member variables. You have already used constructors
for string and vector objects.
• The syntax of the call to the constructor mixes variable definitions and function calls. (See date main.cpp)
• “Default constructors” have no arguments.
• Multiple constructors are allowed, just like multiple functions with the same name are allowed. The compiler
determines which one to call based on the types of the arguments (just like any other function call).
• When a new object is created, EXACTLY one constructor for the object is called.
5
• The files date.cpp and date main.cpp are compiled separately and then linked to form the executable program.
First, we compile each source code .cpp file (which incorporate the .h file) and produce date.o and date main.o:
g++ -c -Wall date.cpp
g++ -c -Wall date main.cpp
Then, we create the executable date.out:
g++ -o date.out date.o date main.o
Alternatively, we can do this all on one line (what we usually do for small programs in this course):
g++ -Wall -o date.out date.cpp date main.cpp
3.12 Exercise
Add a member function to the Date class to add a given number of days to the Date object. The number should be
the only argument and it should be an unsigned int. Should this function be const?
Rule for the duration of the Data Structures course: You may not declare new struct types, and class member
variables should not be made public. This rule will ensure you get plenty of practice writing C++ classes with good
programming style.
6
3.16 Designing and implementing classes
Good software design requires a lot of practice, but here are some ideas to start from:
• Begin by outlining what the class objects should be able to do. This gives a start on the member functions.
• Outline what data each object keeps track of, and what member variables are needed for this storage.
• Write a draft class declaration in a .h file.
• Write code that uses the member functions (e.g., the main function). Revise the class .h file as necessary.
• Write the class .cpp file that implements the member functions.
In general, don’t be afraid of major rewrites if you find a class isn’t working correctly or isn’t as easy to use as you
intended. This happens frequently in practice!
3.17 Exercise
What happens if the user inputs 2 30 2012 into the program? How would you modify the Date class to make sure
illegal dates are not created?
std::vector<Date> dates;
dates.push_back(Date(tomorrow);
dates.push_back(Sallys_Birthday);
dates.push_back(10,26,1985);
• If we used:
sort(dates.begin(), dates.end());
the sort function would try to use the < operator on Date objects to sort the dates, just as it uses the < operator
on ints or floats. However, this doesn’t work because there is no such operator on Date objects.
• Fortunately, the sort function can be called with a third argument, a comparison function. E.g.,:
Where earlier_date is a helper function we define in date.h and date.cpp that takes two const references
to Date objects and returns true if and only if the first argument should be considered “less” than the second
in the sorted order.
• That’s great! But wait, how does sort work with STL strings?
7
3.19 Operator Overloading
• A second option for sorting is to define a function that creates a < operator for Date objects! At first, this
seems a bit weird, but it is extremely useful.
• Let’s start with syntax. The expressions a < b and x + y are really function calls!
Syntactically, they are equivalent to operator< (a, b) and operator+ (x, y) respectively.
• When we want to write our own operators, we write them as functions with these weird names.
• For example, if we write:
• Sorting Date objects makes sense because arguably chronological is the only natural, universally agreed-upon
way to do this.
• Similarly, sorting STL string objects makes sense because alphabetical is the accepted order. So yes, the STL
string class has overloaded operator<, and that’s why sorting them works like magic.
• In contrast, if we defined a Person class (storing their name, address, social security number, favorite color,
etc.), we probably wouldn’t agree on how to sort a vector of people. Should it be by name? Or by age? Or by
height? Or by income?
Instead, it would be better to have comparison helper functions that can be used as needed.
E.g., alpha_by_name, youngest_first, tallest_first, etc.