Source Code. Projects. Nerd Stuff. Art Stuff.

Lesson 8: Classes

Classes

Structures (Section 6.1)

  • A structure is a way of putting more than one variable under a single umbrella. For example, the following code defines a structure to store data for an employee:
        struct Employee
        {
          int empId;
          char fname[21];
          char midInitial;
          char lname[21];
    
        };
        // Notice the semicolon here. This is not a typo! This is a rare place where you see };
  • The above is really a data type definition, which allows us to declare a variable of that type called emp1:
    1
      Employee emp1;
  • To input the employee’s first name we would type:
    1
      cin >> emp1.fname;
  • The reason for the semicolon above is that we could define variables of that structure type in between the “}” and the “;”. But we won’t do it, because it’s bad style.
  • We could write a function to output an employee’s data on one line, like the following:
        void outputEmployee(Employee e)
        {
          cout << setw(10) << e.empId
               << setw(25) << e.fname
               << setw(5) << e.midInitial
               << setw(25) << e.lname << endl;
        }
  • student struct example program

Classes (Section 6.2)

  • A class is very much like a structure, except that it can have member functionsas well as member variables. We can write a class called CEmployee which is identical to the Employee struct above except that the output function is defined as part of the class:
      class CEmployee
      {
        int empId;
        char fname[21];
        char midInitial;
        char lname[21];
    
        void output();  // Prototype for output member function
      };
    
      // Member function definition:
      void CEmployee::output()
      {
        cout << setw(10) << empId
             << setw(25) << fname
             << setw(5) << midInitial
             << setw(25) << lname << endl;
      }
  • Notice that we no longer have any explicit parameters for the output function. Since this function is a member of the CEmployee class, it automatically has access to all the members of the object on which the function is called. I think of member functions as having an implicit parameter — the object on which the function is called.
  • We could write another member function to input employee data from an input stream:
      void CEmployee::input()
      {
        cout << "Please enter employee ID, first name, middle initial,\n"
             << " and last name in that order, separated by spaces.\n";
    
        cin >> empId >> fname >> midInitial >> lname;
      }
  • Even though we’ve defined an input function, there’s nothing to prevent the following code from being written:
      CEmployee emp1;
      emp1.input();
      strcpy(emp1.lname, "Persiko");

    This code would make the user think their data was being stored, but really their last name would be changed to “Persiko”Now imagine we’re writing this class to sell as a software library for companies to use to store employee data. To make this class robust, we want to force programmers who use the class to use the input and output functions we wrote. We want to prevent the above sort of trickery from happening (we also want to prevent mistakes from having that kind of effect.) To have this kind of control over how a class is used, we need to declare some members private.

  • By default, all members of a class are private. But we can make them public if we wish. A private member is only accessable from the class’ member functions. So if we change our definition of CEmployee to:
      class CEmployee
      {
        private:
          int empId;
          char fname[21];
          char midInitial;
          char lname[21];
    
        public:
          void output();
          void input();
      };

    Then the line “

    1
    strcpy(emp1.lname, "Persiko");

    ” would no longer compile, because we’re accessing the private member “lname”

  • It’s good programming style to make all member variables private, and use public member functions to get and set them. That way the author of the class has maximum control over how it’s used.
  • Accessor – a method which returns the value of a member variable. The name of an accessor method usually starts with “get”.
  • Mutator – a method which sets the value of a member variable. The name of a mutator method usually starts with “set”.
  • Here’s a complete program putting all of this together
  • Overloading of member functions is rather common, and it behaves just like overloading of other kinds of functions. Just remember that overloading simply means two functions share a name. They are distinct from each other in every other way.
  • Constructor – a special kind of member function which is called automatically when an object is instantiated (declared).
  • Constructor syntax is a bit different than other member functions. The constructor has no return type (not even “void”) and its name is the same as the class name. e.g. a constructor with 3 parameters would have the following prototype in the class definition:
    1
      CEmployee(const char first[], char middle, const char last[]);

    and the following header for its own definition:

    1
      CEmployee::CEmployee(const char first[], char middle, const char last[])

    and it would be called by the following declaration:

    1
      CEmployee emp2("Craig", 'A', "Persiko");
  • Default Constructor – a constructor with no arguments, which is called by default when an object is instatiated without arguments (no parenthesis used!) e.g. the constructor whose prototype is:
    1
      CEmployee();

    is called by the following declaration:

    1
      CEmployee emp1;
  • If you don’t define any constructors, a default constructor is automatically generated for you, and it does nothing special. However, if you define any constructors yourself, no default constructor is generated automatically. So if you define only one constructor, and it has parameters, you will not be able to instantiate objects of that class without specifying arguments to match that constructor.
  • Here’s a version of the above program that uses constructors and overloaded member functions
  • Explicit constructor calls – You may instantiate an anonymous object by calling the constructor explicitly For example, the expression:
    1
        CEmployee("Bob", 'W', "Jones")

    will instantiate a new CEmployee object using the 3-argument constructor defined above. This object doesn’t have a variable name attached to it, but it may be used any place that an object is expected. It can, for example, be assigned to an object variable that has already been defined. E.g.:

    1
        emp2 = CEmployee("Bob", 'W', "Jones");

    will replace emp2′s previous value with the new CEmployee object constructed by the explicit constructor call.

Class Design Guidelines (Abstract Data Types) (Section 6.3)

  • Well-designed classes are Abstract Data Types. The principles the book discusses for Abstract Data Types are good principles to keep in mind when developing any class.
  • Terminology – some review and some new terms:
    • A class is a programmer-defined object data type
    • Classes encapsulate basic data types and functions
    • Members of a class are the data and functions within a class
    • Data members are also called properties or instance variables
    • Function members or member functions are also called methods
    • Object-oriented programming (OOP) is a programming style based on defining your own classes and using them to encapsulate and manipulate data.
    • Instantiation is the process of creating a new object (an instance of a class)
    • An object is a single instance of a class
      Example: We could define a rectangle class. When we assign values to each of the data members of the class, we have instantiated (defined) a specific rectangle object.
    • Encapsulation is combining into a single unit both data and the functions that operate on the class data. Such a unit is called an object.
    • Information Hiding – An object�s member functions typically provide the only way to access its data. If you want access to an object�s member data, you call a member function in the object�s class. The data is hidden from non-member functions.
    • Information Hiding also involves hiding how exactly the class’s member functions work.
    • Interface – The way a class is instantiated and used. The interface consists of the set of public class members and what they’re used for. It’s the information one needs to utilize a class.
    • Implementation – The way a class works “under the hood”. The implementation is the private code (hidden information) which makes the interface work.
    • A class’s interface and implementation can be separated into 2 files (the interface into a header file with a “.h” extension). We’ll do this in Chapter 9.
    • Deprecation – Deprecation is the process of making a feature obsolete. This can relate to classes or any other aspect of programming. If you get a compiler warning saying so-and-so is deprecated, it means you should avoid using this feature, because it’s no longer the best way to do things.
    • Inline Functions – functions defined in the class definition. Only advised for short functions. (Explained in Appendix 6)
    • Constructor Initialization Section – special syntax to initialize member variable values in constructors.
  • Example Program: Distance Class (feet and inches) using inline functions and constructor initialization section