Create a class of objects

Digression: get the current local date and time in C++

We will need to know how to do this when we make our first C++ class, class date.

  1. theTime.C, theTime.txt
    (tm_sec might be a leap second.)
    Unofficially, the return value of this call to the to_time_t function is the number of seconds that have elapsed since the ever-memorable night they invented Unix (the original version of Linux), at midnight on January 1, 1970.
    That’s about 56 years ago.
    We divide by 60 * 60 * 24 * 365.25 to convert seconds to years:
    bc -l         (minus lowercase L for the math library of the "binary calculator")
    1769720672 / (60 * 60 * 24 * 365.25)
    56.07906406063832484092
    control-d
    
    The function localtime fills up a structure with information, and returns a pointer to this structure.
    (tm_sec might be a leap second.)

Create a class of objects. Evolve it gradually.

Pass some information (the trio of integers year, month, day) down to the functions (print, next, etc.) that do all the work on the dates.

  1. 3ints.C, 3ints.txt
    Hold the information about a date in three ints.
    The arguments of the function date_print could simply have been of type int, int, int.
    I made them pointerss only to agree with the arguments of the other two date_ functions.

  2. struct.C, struct.txt
    Hold the information about a date in one struct instead of in three separate ints.
    In the expression ++p->day in the one-argument function next, the p is an operand of the ->, not an operand of the ++.
    That’s because in the table of operator precedences, the arrow operator -> (at level 2) has higher precedence than the prefix ++ operator (at level 3).

  3. Hold the information about a date in one object.
    1. obj1.C, obj1.txt.
      An object with data members and (non-static) member functions
    2. obj2.C, obj2.txt.
      1. Add two constructors, taking different argument lists.
        We’ve already seen that a class can have two member functions with the same name, if the member functions have different lists of arguments (the three-argument date::next and the four-argument date::next).
        The constructor whose argument is a const date& is called the copy constructor.
      2. Let the data members be private members of the class.
        The name of a private member can be mentioned only within the member functions of the class, not within the main function.
      3. Let the array be a static data member of the class. No matter how many objects we create, or even if we never create any objects at all, there is always exactly one copy of a static data member.
    3. Exercise.
      Now that class date has a constructor that checks for errors, what would happen if the main function tried to create a
      	date d {2, 30, 2026};   //Bad date: there is no February 30
      
    4. Exercise.
      It’s okay to mention the data members year, month, day inside of the member functions of class date. But now that these data members have become private, what would happen if the main function tried to say
      	cout << "America became independent in "
      		<< independenceDay.year << ".\n";
      
    5. Exercise.
      Remove the declaration and definition of the copy constructor from the class date in obj2.C. Even if we don’t write this constructor, the computer will still behave as if we had.
    6. Exercise.
      Write another constructor for class date. This constructor will have no explicit arguments (i.e., arguments you can see), and will initialize the newborn date object to today’s date. A constructor with no explicit arguments is called a default constructor. The default constructor for class date will have to call the three functions chrono::system_clock::now, chrono::system_clock::to_time_t, and localtime; the main function will no longer have to call them. Test the default constructor by changing the declaration for today in the main function of obj2.C to
      	const date today;   //Call the default constructor.
      	today.print();      //Should output today's date.
      	cout << "is today.\n";
      
    7. Exercise.
      Make another pair of non-const public member functions for the class date in obj2.C named prev and prev. They will be just like the existing member functions next and next, except that they will move the date object into the past instead of the future. Test the new member functions by calling them in main.
    8. Exercise.
      Initialization vs. assignment, first with a plain old int:
      	//Bad.
      
      	int i;        //Initialize i to unpredictable garbage.
      	i = 10;       //Assign a value to i, replacing the garbage.
      
      	//Better.
      
      	int i {10};   //Initialize i to 10.
      
      Now with data members in a constructor:
      //Bad.
      
      //This constructor for class date initializes the three data members of the
      //newborn object to unpredictable garbage.  Then it assigns values to the
      //data members, replacing the garbage.
      
      date::date(int init_month, int init_day, int init_year)
      {
              year = init_year;
      
              if (init_month < 1 || init_month > 12) {
                      cerr << "Bad month " << init_month << "\n";
                      exit(EXIT_FAILURE);
              }
              month = init_month;
      
              if (init_day < 1 || init_day > length[month]) {
                      cerr << "Bad month " << init_month << " and day " << init_day
                              << "\n";
                      exit(EXIT_FAILURE);
              }
              day = init_day;
      }
      
      
      //Better.
      
      //This constructor for class date initializes the three data members of the
      //newborn object to the values supplied by the user, init_year, init_month,
      //init_day.
      
      date::date(int init_month, int init_day, int init_year)
      	: year {init_year}, month {init_month}, day {init_day}
      {
              if (init_month < 1 || init_month > 12) {
                      cerr << "Bad month " << init_month << "\n";
                      exit(EXIT_FAILURE);
              }
      
              if (init_day < 1 || init_day > length[month]) {
                      cerr << "Bad month " << init_month << " and day " << init_day
                              << "\n";
                      exit(EXIT_FAILURE);
              }
      }
      
      obj3.C, obj3.txt.
      The three-argument constructor for class date initializes the data members of the newborn date object, instead of filling them with unpredictable garbage and then assigning to them.
    9. Exercise.
      A static member function of a class is just like a plain old member function of the class, except that the static member function receives no invisible pointer.
      For example, the following static member function monthsInYear does not need to receive the address of any particular object of class date.
      Make a member fuction static when the only data members it mentions are static data members.
      Like a plain old member function, a static member function is allowed to mention the names of the private members of the class.
      	void print() const;          //We already have this declaration.
      	static int monthsInYear();   //Declaration for a new member function.
      	//etc.
      
      //Definition of a static member function of class date.
      
      int date::monthsInYear()
      {
      	return size(length) - 1;   //number of months in a year
      }
      
      		//Test the static member function in the main fuction.
      		cout << "A year has " << date::monthsInYear() << " months.\n";
      

      Use the new static member function date::monthsInYear in the following two existing member functions:

      	//In the three-argument constructor of class date
      
      	if (month < 1 || month > monthsInYear()) {
      		cerr << "Bad month " << init_month << "\n";
      		//etc.
      
      		//In the no-argument next member function of class date
      
      		if (month < monthsInYear()) {
      			++month;
      			//etc.
      
    10. Exercise.
      To make it easy to use our class date in many different C++ programs, divide the program into the following three files, and put them in the same directory. Use the mkdir command to create the directory.
      1. date.h is the header file for class date.
        It contains the blueprint for the class.
        See the explanation for the # lines at the start and end of this file.
      2. date.C is the implementation file for class date.
        It contains the definitions for the static data members, the member functions, and, later, the friend functions of the class.
        It includes the header file date.h.
      3. main.C, main.txt contains the rest of the C++ program that uses objects of class date.
        It #includes the header file date.h.
      cd
      cd public_html
      
      pwd
      /home/students/jsmith/public_html
      
      mkdir date
      ls -ld date
      drwxr-xr-x 2 jsmith students 6 Jan 29 20:54 date
      
      cd date
      pwd
      /home/students/jsmith/public_html/date
      
      wget https://markmeretzky.com/fordham/2000/src/class/date/date.h
      wget https://markmeretzky.com/fordham/2000/src/class/date/date.C
      wget https://markmeretzky.com/fordham/2000/src/class/date/main.C
      
      ls -l                                    (minus lowercase L)
      -rw-r--r-- 1 jsmith students 2067 Jan 29 19:18 date.C
      -rw-r--r-- 1 jsmith students  708 Jan 29 20:26 date.h
      -rw-r--r-- 1 jsmith students  816 Jan 29 19:17 main.C
      
      c++ -o ~/bin/mydate date.C main.C        (minus lowercase O)
      
      ls -l ~/bin/mydate                       (minus lowercase L)
      -rwxr-xr-x 1 jsmith students 14440 Jan 28 21:12 /home/students/jsmith/bin/mydate
      
      mydate
      A year has 12 months.
      7/4/1776 is Independence Day.
      etc.
      
      echo $?      (See the (normally invisible) exit status producted by the program.)
      0
      
      • #include with <angle brackets> looks in the directory /usr/include/c++/15 (on our machine storm.cis.fordham.edu) for the header file.
      • #include with "double quotes" looks in your current directory for the header file.
    11. Here’s another three-file C++ program, consisting of
      1. date.h, the same header file as above
      2. date.C, the same implementation file as above
      3. main2.C, main2.txt, a different main file
      The main function in this program has an array of objects. Compile this program with
      c++ -o ~/bin/main2 main2.C date.C
      ls -l ~/bin/main2
      
      main2
      1/15/2026
      

A date::prev member function

Re-implement class date with fewer data members

The data members are private, so no one other than the member functions of class date needs to know that the data members have changed.
Do not change the three arguments of the constructor, or the output of the print member function, even though the class no longer has three data members.

  1. Re-implement class date with two data members, year and day.
    1. date.h
    2. date.C
    3. main.C, main.txt
  2. Re-implement class date with one data member, day.
    1. date.h
    2. date.C
    3. main.C, main.txt

A friend function of a class

  1. Two ways of giving a distance function to the one-data-member class date.
    1. date.h: declare distance as member function vs. a friend function.
      A “friend function” is similar to a static member function; we’ll have to talk about their difference later.
    2. date.C: define distance as member function vs. a friend function.
    3. main.C, main.txt: exactly the same output for member function vs. friend function.

    My recommendations: if a function needs to mention the private members of a class,

    1. The function should be a member function of the class if it concentrates on one object of the class.
      Examples are date::print in date.h and date.C, point::print in point.h and point.C.
      Two exceptions (coming later): the special functions operator<< and operator>> must be friends, even though each once concentrates on one object of the class.
    2. The function should be a friend function of the class if it deals with two or more objects of the class.
      Examples are date::distance in date.h and date.C, and (coming up) point::equals in point.h and point.C.
    3. The function should be a static member function of the class if it does not use any object of the class.
      Examples are date::monthsInYear and announcer::howMany in announcer.h and announcer.C.

Class point

Like a date object, we can think of a point object primarily as a structure that holds data members.
This program consists of three files:

  1. point.h
  2. point.C
  3. main.C, main.txt
  1. Download, compile and run this three-file C++ program:
    cd
    cd public_html
    
    pwd
    /home/students/jsmith/public_html
    
    mkdir point
    ls -ld point
    drwxr-xr-x 2 jsmith students 6 Jan 29 20:54 point
    
    cd point
    pwd
    /home/students/jsmith/public_html/point
    
    wget https://markmeretzky.com/fordham/2000/src/class/point/point.h
    wget https://markmeretzky.com/fordham/2000/src/class/point/point.C
    wget https://markmeretzky.com/fordham/2000/src/class/point/main.C
    
    ls -l
    -rw-r--r-- 1 jsmith students  447 Jun 10  2025 main.C
    -rw-r--r-- 1 jsmith students 1051 Jun 10  2025 point.C
    -rw-r--r-- 1 jsmith students  477 Jun 10  2025 point.h
    
    c++ -o ~/bin/point main.C point.C
    ls -l ~/bin/point
    
    point
    Length of line AB is 5
    etc.
    
  2. Exercise.
    Give class point a friend function named midpoint, that will construct and return a new point that is exactly halfway between two existing points.
    You will have to declare this function in the file point.h; see the declaration of the friend function distance in this file date.h.
    Here’s what the definition of this function will look like in the file point.C; you have to fill in the two (underlined) blanks.
    //in the file point.C
    
    point midpoint(const point& A, const point& B)   //a friend function
    {
    	const point m {     ,      ); //Construct the midpoint ...
    	return m;                     //...and return it.
    }
    

    You’ll also have to test midpoint in the file main.C.
    This file already has two point objects, A and B.

    	//in the main function in the file main.C
    
    	const point M {midpoint(A, B)};  //Call the copy constructor for class point.
    	cout << "The midpoint of A and B is ";
    	M.print();
    	cout << "\n";
    
  3. Exercise.
    Give class point a static data member named origin of type const point. (See date.h and date.C for the declaration and definition of a static data member.) Then change the body of the point::r member function to
    	//return sqrt(x * x + y * y);
    	return distance(*this, origin); //distance from this point to the origin
    

Class announcer has a constructor and a destructor.

  1. Unlike classes date and point, an object of class announcer holds very little data: just an identifying number for itself.
    The purpose of an announcer object is not to hold data.
    Its purpose is to output a birth announcement and a death announcement at the start and end of its life.
    1. announcer.h
    2. announcer.C
    3. main1.C, main1.txt

    Class announcer has a static data member announcer::count, like the static data member date::length of class date.

    Class announcer has a static member function announcer::howmany, like the static member function date::monthsInYear.
    A static member function does not receive an implicit argument, since a static member function does not use the data members inside of any object.
    (An “implicit” argument is an invisible argument.)

    Class announcer as a copy constructor whose explicit argument is a const announcer& another, just like the obj2.C version of class date had a copy constructor whose explicit argument was a const date& another.
    (An “explicit” argument is an argument you can see, as opposed to the invisible argument that is a pointer to an object.)
    We had to write a copy constructor for class announcer because the copy constructor we’d get by default would do no more than initialize the non-static data member:

    announcer::announcer(const announcer& another)   //"copy" constructor
    	: name {another.name.id}
    {
    }
    

    Download, compile, and run this three-file program:

    cd
    cd public_html
    
    pwd
    /home/students/jsmith/public_html
    
    mkdir announcer
    ls -ld announcer
    drwxr-xr-x 2 jsmith students 6 Feb  5 20:54 announcer
    
    cd announcer
    pwd
    /home/students/jsmith/public_html/announcer
    
    wget https://markmeretzky.com/fordham/2000/src/class/announcer/announcer.h
    wget https://markmeretzky.com/fordham/2000/src/class/announcer/announcer.C
    wget https://markmeretzky.com/fordham/2000/src/class/announcer/announcer.C
    
    ls -l
    -rw-r--r-- 1 jsmith students  657 Feb  5  2025 announcer.C
    -rw-r--r-- 1 jsmith students  521 Feb  5  2025 announcer.h
    -rw-r--r-- 1 jsmith students 1155 Feb  5  2025 main.C
    
    c++ -o ~/bin/announcer main.C announcer.C
    ls -l ~/bin/announcer
    
    announcer
    announcer 10 is born.
    etc.
    
  2. Exercise.
    Download this more complicated main file main2.C to demonstrate where C++ objects are born and die.
    (Here’s the correct output.)
    cd ~/public_html/announcer
    pwd
    
    wget https://markmeretzky.com/fordham/2000/src/class/announcer/main2.C
    ls -l main2.C
    
    c++ -o ~/bin/announcer main2.C announcer.C
    ls -l ~/bin/announcer
    
    announcer
    At start of main, we have 0 objects.
    

Events often happen in pairs.

  1. As a program runs, events often come in pairs:
    1. open and close a file
    2. lock and unlock a record in a database
    3. allocate and deallocate a resource
    4. new and delete[] a block of memory in C++ (a typical resource)
    5. Make something appear and disappear on the screen
    6. compress and decompress a file
    7. encrypt and decrypt a file
    8. connect and disconnect a network connection
    You can think of many more examples!

    To make these events happen in pairs in C++, we trigger constructors and destructors.
    Warning: error checking omitted for simplicity.
    1. constructor.c.
      An old fashioned C program with a pair of explicit function calls, to fopen and fclose.
      It would be bad if you forgot one of these calls, or called them in the wrong order, or called one of them twice.
      Because it’s written in teh language C, compile the program with cc instead of c++.
      cc constructor.c      (Should create a file named a.out)
      ls -l a.out
      -rwxr-xr-x 1 jsmith students 25048 Jun  1 09:18 a.out
      
      ./a.out               (Should create a file named outfile.txt)
      echo $?               (See the exit status producted by a.out)
      0
      
      ls -l outfile.txt
      -rw-r--r-- 1 jsmith students 16 Jun  1 09:26 outfile.txt
      
      cat outfile.txt       (See what's in the file outfile.txt)
      Morning.
      Noon.
      Night.
      
      rm outfile.txt
      
    2. constructor.C.
      A C++ program that constructs and destructs an object, instead of making a pair of explicit function calls.
      This program creates the same outfile.txt file as the above C program.

Events often happen in nested pairs.

  1. A series of jobs often needs to be undone in the opposite order. For example,
    1. Create a window.
      Create icons in the window.
      Do work.
      Destroy the icons.
      Destroy the window.

    2. Create a directory (also called a “folder”).
      Create files in the directory.
      Do work.
      Destroy the files.
      Destroy the directory.

      To undo the jobs in the opposite order, exploit the order in which C++ objects are automatically destructed:
      #include <iostream>
      #include <cstdlib>
      #include "window.h"   //for classes window and icon
      using namespace std;
      
      int main()
      {
      	window w;     //Construct window w.
      	icon i0 {w};  //Construct icon i0 and put it in the window.
      	icon i1 {w};  //Construct icon i1 and put it in the window.
      	icon i2 {w};  //Construct icon i2 and put it in the window.
      
      	doWork();
      
      	return EXIT_SUCCESS; //Destruct i2, i1, i0, w, in that order.
      }
      
    3. Encrypt and compress a file.
      The decompress and decrypt the file.

    4. Generate a file in HTML format, with the pairs of tags nested. This program outputs six pairs of tags by constructing and destructing six objects of class element.
      1. element.h
      2. element.C
      3. main.C, main.txt

    5. The last to go will see the first three go before her.

  2. To escape from the tyranny of the {curly brace} discipline, we can construct each object in its own block of dynamically allocated memory.
    (We saw a block that holds an array of ints in new1.C.)
    The following program allocates three blocks, and puts an object into each one.
    Two pieces of good news:
    1. When we allocate a block with new, the computer automatically calls the constructor for any object(s) in the block.
      (That didn’t happen in new1.C, because the block in new1.C held pathetic little integers, not actual objects.)
    2. When we deallocate a block with delete, the computer automatically calls the destructor for any object(s) in the block.
    For example, the output of this program proves that object m3 is constructed after m1, but is destructed after m1.
    1. announcer.h
    2. announcer.C
    3. main4.C, main4.txt
    c++ main4.C announcer.C
    ls -l a.out
    
    ./a.out
    m1 (announcer number 1) born.
    etc.
    

Construct and destruct a nested object,
another example of nested pairs of events

  1. Below is the class of a big object (an interval) containing two smaller objects (dates) as its data members.
    The constructor for class interval begins by automatically making two detours to a constructor for class date.
    After these detours, the {body} of the constructor for class interval is executed.

    Similarly, the destructor for class interval ends by automatically making two detours to the destructor for class date.
    Before these detours, the {body} of the constructor for class interval is executed.

    1. date.h
    2. date.C
    3. interval.h
    4. interval.C
    5. main.C, main.txt
    Compile and run this five-file program (consisting of date.h, date.C, interval.h, interval.C, and main.C) with
    c++ -o ~/bin/interval main.C interval.C date.C
    ls -l ~/bin/interval
    
    interval
    constructing date 9/1/2025
    etc.
    

Two more examples of classes:
class stack

  1. This stack object is hardwired to hold a stack of ints. A stack is what an accountant would call a LIFO list: “last in, first out”.
    1. stack.h
    2. stack.C
    3. main.C, main.txt
    Compile and run this three-file program (consisting of stack.h, stack.C, and main.C) with
    c++ -o ~/bin/stack main.C stack.C
    ls -l ~/bin/stack
    
    stack
    Type a positive integer to push it,
    etc.
    
  2. stack.C, stack.txt.
    Don’t build your own class stack.
    The C++ Standard Library already has a template class stack, like the template class vector we saw in vectorint1.C.
    Write the name of the data type of your choice in the <angle brackets>.

A digression on signed vs. unsigned integers

On our machine storm.cis.fordham.edu, an int occupies 4 bytes = 32 bits.
Therefore an int can hold any one of 232 = 4,294,967,296 different values.
We let these values represent integers in the range from –2,147,483,648 to 2,147,483,647 inclusive.

The leftmost bit of an int is called the sign bit.
It is 1 for negative numbers, 0 for non-negative numbers.

bits int
01111111 11111111 11111111 11111111 2,147,483,647
01111111 11111111 11111111 11111110 2,147,483,646
01111111 11111111 11111111 11111101 2,147,483,645
00000000 00000000 00000000 00000010 2
00000000 00000000 00000000 00000001 1
00000000 00000000 00000000 00000000 0
11111111 11111111 11111111 11111111 –1
11111111 11111111 11111111 11111110 –2
11111111 11111111 11111111 11111101 –3
10000000 00000000 00000000 00000010 –2,147,483,646
10000000 00000000 00000000 00000001 –2,147,483,647
10000000 00000000 00000000 00000000 –2,147,483,648

On our machine storm.cis.fordham.edu, an unsigned int occupies 4 bytes = 32 bits.
Therefore an unsigned int can hold any one of 232 = 4,294,967,296 different values.
We let these values represent integers in the range from 0 to 4,294,967,295 inclusive.

bits unsigned int
11111111 11111111 11111111 11111111 4,294,967,295
11111111 11111111 11111111 11111110 4,294,967,294
11111111 11111111 11111111 11111101 4,294,967,293
00000000 00000000 00000000 00000010 2
00000000 00000000 00000000 00000001 1
00000000 00000000 00000000 00000000 0

Class myrandom

The member function myrandom::rand in the file myrandom.C scrambles the value of the data member myrandom::next with a multiplication and an addition.
For example, the first time we call myrandom::random, it changes the value of next from 1 to 1,103,527,590.
Mathematicians have determined that the most random part of the resulting value consists of the 15 bits in positions 16 through 30 inclusive.
Here is 1,103,527,590 written in binary with these bits in yellow:

  01000001110001100111111010100110   (this is 1,103,527,590)
  00000000000000000100000111000110   (this is 1,103,527,590 shifted 16 places to the right)
& 00000000000000000111111111111111   (this mask is 0x7FFF)
  00000000000000000100000111000110   (this is 16,838)

The result of the “bitwise and” is
100000111000110
which is 16,838 in decimal.

  1. A myrandom object does only one thing for us. In other words, it has only one member function, not counting the constructor.
    1. myrandom.h
    2. myrandom.C
    3. main.C, main.txt

HW

  1. Class date
  2. (jt88) Constructor takes degrees, minutes, seconds.
    1. Angle.h
    2. Angle.C
    3. main.C
    	// An array of 3 Angle objects
    	const Angle triangle[] = {
    		Angle {90, 0, 0},
    		Angle {45, 0, 0},
    		Angle {45, 0, 0}
    	};
    
    	const size_t n {size(triangle)};   //the number of objects in the array
    
  3. (jc208) coffee
  4. (kwesner1) zclass.
    Each object has two data members, so it’s no surprise that the constructor takes two arguments.
    I wonder what the objects do.
  5. element2
    Eah object is an atom knowing its row in the periodic table.
  6. (mrd22)
    1. vector_project
    2. vector3
  7. MilitaryRank (jmm56)
    1. MilitaryRank
    2. MilitaryRank