Corning Community College
C/C++ Programming
Task 6: Classes and Objects
~~TOC~~
To begin the exploration of classes, their instantiated objects, and introduce the concepts of Object-Oriented Programming.
In “C++ Programming: Program Design Including Data Structures” by D.S. Malik, please reference:
When we look at a problem logically, we can often break it down into discrete parts, each of which is simple to solve, and when cooperating together, can help solve the big task at hand. Familiarity with C or most shell scripting is of the imperative (or procedural) paradigm- we can break things down into their basic parts, and come up with a step-by-step solution for solving the problem.
This is all fine and dandy. In fact, many problems are best solved by using imperative techniques. (Best tool for the job sort of thing). However, there exist other paradigms, such as “logical”, “functional”, and “object-oriented”. We'll be focusing on the “object-oriented” method here.
So what IS Object-Oriented programming? What is Object-Oriented problem solving? What's the point of an “Object”? Basically, the point behind “Object-Oriented” problem solving is “abstraction”.
Abstraction can be defined as “Looking at things in general terms, ignoring detail”. This is a pretty good description. In “Object-Oriented” problem solving, we take the opposite approach to things- instead of being concerned with the definite and exact detail of what is going on, we abstract it away, and look at things from the outside (a black box approach). What's the advantage of this? Not worrying about the minute details, we can focus on the larger image, building big and complex systems more easily, without necessarily getting caught up in all the details.
NOTE: Object-Oriented problem solving is NOT the be all, end all solution to the world. Many schools of thought are now obsessed with “Object-Oriented” concepts (abbreviated OO), claiming it is the latest and greatest. C++ and Java often are top of the list. But remember the saying “use the tool that is best for the job at hand”. Object-Oriented problem solving is NOT always the best way to go about it. Sometimes an imperative solution or a logical solution may be better.
With this abstracted approach to problem solving, we've got some new terminology that must be presented:
So the purpose here is organization and abstraction. We can package our data and look at our data in a manner independent of what a computer may do with it (for example, if we want to look at “integer numbers”, and we abstract them- we don't need to worry about any 4byte storage– as that is how the computer deals with it, we are only concerned with the data).
Organization of data has always played an important part in things. You run an office, you need to keep your paperwork organized. Filing cabinets can be quite useful for this purposes… and can be subdivided into units such as file folders, drawers, etc. Here we are looking at things on the top level- abstracting away things like ink-printed papers, 11×8.5“ paper dimensions, etc.
In programming languages, such as C++, the class is an important packaging mechanism that lets you organize your data. For those who are familiar with the “struct” in C, a class in C++ (or Java) is going to seem very similar. And very appropriately so.
The structure of a class is as follows:
Class Member Functions Data Members
The “Data” refers to the actual data you wish to store or use. In OO we have more attributes we can assign to this data- and that refers to its accessibility. Public, Private, and Protected. Public data is just that– available for all to see. Private data is only accessible to the other members and data WITHIN the particular class. (A class cannot access a neighbor class's private data).
So a class is made up of the various function members and data members. Think of this as the object you are creating- each object has properties, both in values that must be set, as well as the ability to manipulate and view those values. This is exactly the sort of stuff you can do with classes in C++.
This whole idea of classes and abstraction may be worthwhile, but ultimately, when dealing with a computer, we've still got to take into account some level of detail. To make the computer happy, we must provide mechanisms for starting up and shutting down an instance of a class. The terms used are “constructor” and “destructor”. Basically- a constructor is a set of instructions that are called when you are creating an instance (or copy) of this class. A constructor will initialize data members to values, set conditions, etc. so that you can proceed to use the class.
A destructor is called when you are finished with this instance of your class. It cleans up.
The concept of “message passing” comes into play when dealing with Object-Oriented concepts. (Incidentally, it is also used in other contexts as well, such as in various methods of Distributed Systems/Cluster programming, and not necessarily in Object-Oriented environments).
The idea behind message passing is to establish some means of communication (once again, the details of this communication link are abstracted away) and to pass the appropriate information through this link, irrelevant of how it is actually transferred or represented by the underlying hardware.
In your programs, you will be performing message passing when dealing with your classes.
Your first C++ program!
Time to start playing with C++. Let's start with the traditional “Hello, World!” example:
/* * hello.cc - a simple "Hello, world!" in C++. */ // include standard I/O stream functions // #include <iostream> using namespace std; // main() function // int main() { cout << "Hello, world!\n"; return (0); }
Examples of hardware architectures:
And software platforms:
If we were to refer to Lab46 from a platform/architecture point of view, it would be a Linux/AMD64 machine.
Soon after UNIX was created in its first assembly language implementation on a PDP-7, there became a need for it to be portable, so it could run on other machines (including the PDP-11). An attempt was made in the language called B, but it didn't prove to be useful. Soon thereafter C was implemented and UNIX was rewritten in that language.
Since then, C and UNIX have been tightly related to one another- UNIX facilities either appear very “C-like” or are easily accessible with C. In fact, the typical UNIX kernel is exclusively C, aside from the architecture-specific assembly language needed to interface with the basic hardware operations.
Because of this, UNIX is a very portable operating system- and as thirty years of existence has shown, a port of some form or another is found on nearly every computer architecture.
As C++ is fundamentally C with added functionality, all the system-related programming techniques available in C are similarly available to us in C++. In fact, outside of C++ specific aspects, there's very little that cannot be directly translated to a C program.
The basic programming model of going from source code (what you write) to machine code (what the machine understands) is as follows:
For most intents and purposes, the source code is portable among architectures. If the language is high-level, it will not depend on the underlying hardware.
To compile a single source file, you would do the following:
lab46:~$ g++ -o binary source.cc
Where binary is the name of the desired executable, and source.cc is the name of the text file containing the program source.
The -o argument to g++ indicates the name of the output file. Since there is only one file in this case, the compiler automatically performs the assembling and linking steps for us.
In the shapes/ subdirectory of the CPROG Public Directory (/var/public/cprog/), you will find a file called rectangle.cc. Copy this to your ~/src/cprog/ subdirectory as follows:
lab46:~$ cd ~/src/cprog lab46:~/src/cprog$ cp /var/public/cprog/shapes/rectangle.cc . lab46:~/src/cprog$
Please read through this source code, compile, and run the program. Make sure you understand what is going on.
We've got the accessor functions of getLength() and getWidth() for checking the current values of the particular rectangle's length and width, but how about setting them after the fact? Go ahead and add to this program:
Using classes we also have the “public” and “private” functionality available to further control how our data is accessed. C++ provides us with a powerful means of controlling data access to our class.
It is sometimes preferable for different levels of a program to be programmed by different people. Large database applications can often have several different groups of people working on different tasks.
Instead of giving every programmer the entire program to do with as they please, each group can work on their specific component, and release it to the other groups to use in the implementation of their component. Distributing such things in binary form is not uncommon. Look at the world of proprietary software, where no source code is available. You must be able to use their binary code and any documentation the vendor may provide in order to design your solution. You cannot view the source code of the various function calls to see how they work. Instead, you must rely on the documentation, knowing what parameters to send in and what gets returned (if anything) and trust that the code works as the documentation indicates it does.
In the Open Source world, lack of source code isn't as much of a problem, but the concepts of data access are still very important. A program may still have several components to it, and for security purposes the file-save module probably SHOULDN'T have direct access to user passwords. Protecting data is still very important for organizing a solution, no matter what your source code availability is.
In the incomplete/ subdirectory of the CPROG Public Directory ( /var/public/cprog/ ), you will find a file called tryme.cc
This file implements a simple class and a main() function. It doesn't compile in its current state.
Please copy this file into your own ~/src/cprog/ directory, which can be done as follows:
lab46:~$ cd ~/src/cprog lab46:~/src/cprog$ cp /var/public/cprog/incomplete/tryme.cc . lab46:~/src/cprog$
Read through it, and answer the following questions:
Along with your responses to the above questions, please submit a working version of the tryme.cc program as corrected by the specifications of modifying only main() (leave the original class implementation intact).
Just to review the compilation/execution process for working with your source code, if we had a file, hello.cc, that we wished to compile to a binary called hello, we'd first want to compile the code, as follows:
lab46:~/src/cprog$ g++ -o hello hello.cc lab46:~/src/cprog$
Assuming there are no syntax errors or warnings, and everything compiled correctly, you should just get your prompt back. In the event of problems, the compiler will be sure to tell you about them.
Conceptually, the arrangement is as follows:
g++ -o BINARY_FILE SOURCE_FILE
The BINARY_FILE comes immediately after the -o, and the SOURCE_FILE, must never immediately follow a -o. It can precede, and such is perfectly valid (especially if you feel that way more intuitive).
To execute your binary, we need to specify a path to it, so we use ./, which basically says “in the current directory”:
lab46:~/src/cprog$ ./hello Hello, World! lab46:~/src/cprog$
If you find yourself experiencing “anomalous” behavior in your resulting program that just cannot be explained away (ie no discernable logic errors). You can try enabling some compiler optimizations.
Compiler optimizations invoke additional functionality present in the compiler that can do some alterations of your compiled code, reordering things for more efficiency, and even correcting aberrant behavior (but also having the potential to break otherwise “working” behavior).
To use compiler optimizations, we add the “-O#” option (capital letter Oh) to the compiler command-line. There are a number of compiler optimizations available to us (this was all gleaned from the gcc(1) manual page):
option | description |
---|---|
-O0 | no optimization (this is the default, it happens if you don't specify anything) |
-O | reduce code size and execution time, plus some non-expensive optimizations |
-O1 | same as -O |
-O2 | optimize more. Compile time increases for the result of better code and execution |
-O3 | yet more optimizations. Long compile time, perhaps more efficient code |
-Os | optimize for size. Uses a lot of -O2 optimizations so long as it does not impact code size |
So, if you'd like to compile your code with level 1 optimizations:
g++ -O1 -o BINARY_FILE SOURCE_FILE
As your programs get bigger and more complex, the utilization of compiler optimizations can make a significant impact on the resulting performance of your program. For most of the stuff we're doing now, you're not likely to notice many improvements.
As you write your code, hopefully you've developed the good habit of storing all your programs in your ~/src/cprog directory (and have added/committed them to your repository).
But, in order to complete your tasks, you've been requested to place it in your ~/src/submit directory instead.
What to do?!
We'll simply make a copy of your code! Assuming we're working with a source file called myprog.cc in our ~/src/cprog directory, we'll copy it into ~/src/submit/ and give it a name of: taskX.cc
To do that we use the cp command, and run it as follows:
lab46:~/src/cprog$ cp myprog.cc ~/src/submit/taskX.cc lab46:~/src/cprog$
We can then hop over to our submit directory and add/commit it:
lab46:~/src/cprog$ cd ~/src/submit lab46:~/src/submit$ ls contact.info taskU.c taskV.c taskW.c taskX.cc lab46:~/src/submit$ svn add taskX.cc Added taskX.cc lab46:~/src/submit$ svn commit -m "added taskX.cc to the submit directory" ...
All questions in this assignment require an action or response. Please organize your responses into an easily readable format and submit the final results to your instructor per the appropriate methods.
Your assignment is expected to be performed and submitted in a clear and organized fashion- messy or unorganized assignments may have points deducted. Be sure to adhere to the submission policy.
When complete, questions requiring a response can be electronically submit using the following form:
<html><center><a href=“http://lab46.corning-cc.edu/haas/content/cprog/submit.php?task6”>http://lab46.corning-cc.edu/haas/content/cprog/submit.php?task6</a></center></html>
Additionally, the successful results of the following actions will be considered for evaluation:
As always, the class mailing list and class IRC channel are available for assistance, but not answers.