CIS 250 - Class concepts (details)
Objectives
- implement constructors
- implement destructors
- implement dynamic memory allocation
- compare and contrast inheritance and composition
- define the terms: encapsulation, inheritance, and polymorphism
- discuss the importance of encapsulation, inheritance, and polymorphism
- implement C++ classes
- write and use overloaded functions
- use initialization lists
Terminology
- inheritance: using an existing class/object to create a new class object; all
of the data and methods from the base class (superclass) are inherited by the
derived class (subclass)
- instance: an object is called an instance of the class it is based on
- instantiation: creating an object from a class
- composition: using an object as a data member of another object
- inheritance specifies an "is-a" relationship
- composition specifies a "has-a" relationship
- a C++ class can inherit from multiple classes; this can be quite confusing
and will be avoided in this course
A simple class
- class definition format: class className: memberAccessSpecifier baseClassName { memberList };
- see Point.cpp
- private: accessible only within same class
- public: accessible to any code
- protected: accessible only within same class and derived classes (subclasses)
- constructors: used to initialize instance variables and allocate initial resources
- default constructor: the constructor that has no arguments
- converging constructors through a common initialization function so all initialization code is in one spot
- constructors may have initialization lists; they are specified in the function header and
separated using a colon after the parameter list
- initialization lists can be used to specify which base class constructor to call
and which arguments to send it
- accessor (get) methods: used by other classes to get the value of private variables
- mutator (set) methods: used by other classes to change the value of private variables
- predicate methods are those that return true or false
- const modifier (before parameter): means that the parameter may not be changed within the function
- const modifier (at end of function head): means that the function may not change the value of its static or instance variables
- converging code through one validation routine is encouraged to make troubleshooting and modification easier
- new and delete: operators used to create and destroy objects
- regular object variables vs. pointers
- accessing members of objects through reference variables: use . (dot, member of) operator
- accessing members of objects through pointers: use -> operator
- a base class data member with an identifier name duplicated in the derived class can be called
using the scope resolution operator as follows: ::identifier
Function return types
- easy to return a single built-in type
- easy to return an object
- problems arise when returning local (automatic variables) and
dynamically allocated memory
- local variables don't exist after return statement
- dynamically allocated memory must eventually be released
- traditional C-style strings can be a big problem
Function overloading
You can have multiple functions with the same name, but
different argument lists. The compiler can determine which
function to use based on the argument list.
See overload1.cpp for an example.
Constructors, destructors, and dynamic memory allocation
It is common to overload constructors, but unlike Java, C++
constructors can not call each other. Since we try to eliminate
duplicate code when possible and funnel error checking through
individual functions for each check, it makes sense to create a
common initialization function that all the constructors can call.
This initialization function is also the ideal place to update
a static object count variable if there is one.
You don't have to worry about overloading destructors. There
can be only one. A destructor may not be needed unless you have
to deallocate memory that was allocated by the object in a
constructor or mutator method. Another reason you might need a
destructor is to decrement a static object count variable.
The examples for this section use a C-style string as an instance
variable. Smooth handling of a C-style string instance variable
usually requires dynamic memory allocation and deallocation.
You have to be careful when writing such code so you know that the
pointer to the string has been initialized properly, and the memory
returned when the object is destroyed.
See person.h, person.cpp,
and testPerson.cpp for an example.
See person2.h, person2.cpp,
and testPerson2.cpp for a more detailed example
using dynamic memory allocation.