In this lab, you will:
Reference: See the programming example on "Classes" in the C++ Syntax pages.
These two things constitute an Abstract Data Type, or an ADT.
The operations for an ADT fall into 4 categories:
Constructor | Creates data for the ADT. |
Transformer / Mutator / Setter | Modifies data in the ADT. |
Observer / Accessor / Getter | Allows you to "look but not touch" the data in the ADT. |
Iterator | Provides the ability to move through components in an ADT, one at a time. |
The following is an example of a set of specifications for an ADT. This includes a description of the data and the operations on these values.
Type Grades Data or Fields name - a character array of 20 elements (represents student name) id - an integer (represents student #) marks - an array of integers (for storing marks) Operations setName - a transformer type operation setID - a transformer type operation setMarks- a transformer type operation reporter- an observer type operation
Theory and abstraction are fine, but sometimes it's helpful to relate this to some practical knowledge in order to put the concepts into place. With that in mind, we'll introduce the term classes here, which is the most common way in which ADT's are implemented in C++. Here is a comparison between classes, which you may not have read much about yet, and structures, which you explored in a previous lab.
Declaring and using classes is similar to declaring and using structures in C++. First you declare the class (or structure), and then you declare the instances of the class (or structure).
For example, here are comparitive examples of how you declare and instantiate a class and a structure.
class Computer | struct Student |
{ | { |
// By default: private
// data // operations |
// By default: public
// data // operations (not recommended) |
}; | }; |
// Instantiate a class | // Instantiate a structure |
Computer pc; | Student stu; |
There, now you've got the formal definition of an ADT and had a look at how they are implemented in C++ as classes. In the next section, you'll examine class members in more detail.
Term | Definition |
---|---|
class | An implementation of an ADT. |
class member | A datum associated with the class, or
a function used in the class to implement one of the operations associated with the class. These functions are also referred to as methods of the class. |
class object | An instance of the class. |
Class members are either public, meaning that they are accessible from outside the class, or private (the default), meaning that only the class can access them. Generally data is designated as being private (look up "information hiding" in any text) and the methods are designated as being public, so that they can be called from elsewhere.
Here's a simple example:
class Computer { private: // It's not necessary to include this term since that is the default. // However, it's good form to do so and clarifies your meaning. int processorSpeed; public: void setSpeed(int); int getSpeed() const; };
Note: It doesn't matter if private comes before public, or the other way around.
Let's try to visualize what two instances of this Computer
class would look like.
Say you've instantiated a Computer called pc and
another called cray.
Each of them would exist as an object and have its own methods
and data.
You would use dot notation to refer to the members of each instance. e.g. pc.setSpeed(x); or cray.setSpeed(x); Be careful though - if you tried to access the data member, pc.processorSpeed from outside the class you would get an error, because that was declared as being private, unlike the methods, which are public.
When you enter the code for the function in the Filename.cpp file, you must precede each member function name with the name of the class.
e.g. void Computer::setSpeed(int p)The double colon :: is known as the scope resolution operator. It ties the function name to the name of the related class. This is necessary because the function might also exist in another class.
Going back to the example we were just looking at, you could have three files involved in the total program.
Computer.h | The header file for the Computer class.
This contains the private data members and the function prototypes for the operations members. |
Computer.cpp | The function definition file for the Computer class.
Must contain: #include "Computer.h" |
CompServ.cpp | The main program that calls the class.
Must contain: #include "Computer.h" |
You may recall from a previous lab that each .cpp file must be compiled to an object, .o, file individually and then linked together to produce the executable file. Click here to see the picture that summarizes the separate compilation.
When we talked about ADT's one of the classes of operation we identified was Constructor. Constructors initialize data that wasn't there before.
An ADT can have two different general types of constructor. The first constructs the ADT itself. The second constructs pieces of the ADT if the ADT contains other ADTs, as in a list of addresses.
The first type of constructor generally has special language support. In C++ there are a few variations that allow for all, some or no data to be specified at object creation time. Any further changes would be made using transformers or the other type of constructor. The details of how to implement the first type of constructor follow in the next subsection.
The second type of constructor works just like any other member function, but at some point it may call a constructor for the contained data type.
Grades::Grades() { // include C++ statements here to initialize the data members }
Grades::Grades(int a) { // include C++ statements here to initialize the data members } Grades::Grades(int a, int b, int c) { // include C++ statements here to initialize the data members }
Grades student1; // create an object using the default constructor Grades student2(123); // create an object passing a single parameter Grades student3(85, 75, 99); // create an object passing three parametersNote that you would have had to create each of the constructor functions in the class file.
Tree pine2(pine1);
or:
Tree pine2 = pine1;
If you had no copy constructor defined, then the compiler would
supply a default "copy constructor" to create the clone.
Tree pine2(pine1);
",
is the current preferred syntax.
The second notation "Tree pine2 = pine1;
",
is now considered obsolete.
However both forms are given here because a programmer is likely
to encounter both.
Copying an object using the default copy constructor may work for simple objects.
However, if there were pointers in the original object,
only the pointers would be duplicated,
not the data that was being pointed to.
Following the previous example,
suppose Tree objects had an integer data member, and a pointer
data member to a character string.
pine1's pointer would have the address
of the same data as pine2's pointer!
There would then be two ways of accessing (and modifying!) the same data.
This type of a copy operation is called a shallow copy
because the "pointed-to" data is not copied when a 'clone' is made.
This is not a true clone.
If pointers are part of an object, what you may need is
a deep copy
which you would have to define yourself.
Here is the general syntax for a deep copy constructor.
type :: type (const type & object_name)In that example of the general syntax, type refers to the class type name. Notice how the parameter is passed to the copy constructor. You do not want to do any harm to the existing object, so you declare the object parameter as type
const
and use the ampersand
&
to
pass it as a reference
rather than a value.
For example:
Tree::Tree(const Tree & otherTree) { age = otherTree.age; descrip = new char[strlen(otherTree.descrip) + 1]; strcpy(descrip, otherTree.descrip); }Actually, we haven't seen the
new
operator yet.
It defines a dynamic variable in "free store" - a topic of a later lab.
However the code is given here for the sake of giving a complete
example of a deep copy
constructor.
Please get the zip and extract the files to your cs115 directory:
curl https://www.labs.cs.uregina.ca/115/CODE/4-Class.zip -O -s unzip 4-Class.zip
>./main Testing the default constructor and the getters The initialized date is (M-D-Y):1-1-1 Please enter a date:(Month Day Year): 11 03 1976 Please enter a second date:(Month Day Year): 03 03 1999 Printing the two days: The date is (M-D-Y): 11-3-1976 The date is (M-D-Y): 3-3-1999 The days are the same >./main Testing the default constructor and the getters The initialized date is (M-D-Y): 1-1-1 Please enter a date:(Month Day Year): 12 15 2009 Please enter a second date:(Month Day Year): 12 25 2020 Printing the two days: The date is (M-D-Y): 12-15-2009 The date is (M-D-Y): 12-25-2020 The days are different
For the StudentClass that we go over this week, see StudentClass.cpp
Wednesday, 04-Jan-2023 14:57:02 CST |
|
|
|