User Tools

Site Tools


haas:spring2011:cprog:tasks:task6


Corning Community College

C/C++ Programming


Task 6: Classes and Objects

~~TOC~~

Objective

To begin the exploration of classes, their instantiated objects, and introduce the concepts of Object-Oriented Programming.

Reading

In “C++ Programming: Program Design Including Data Structures” by D.S. Malik, please reference:

  • Chapter 2 “Basic Elements of C++”
  • Chapter 10 “Records (structS)”
  • Chapter 11 “Classes and Data Abstraction”

Background

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:

  • encapsulation- to package data and/or operations into a single well-defined programming unit.
  • data abstraction- the property of an ADT that allows you to work with the data elements without concern for how the data elements are stored inside the computer or how the data operations are performed inside the computer.
  • class- an interface that defines the behavior of its objects. (in C++, it is a syntactical unit that describes a set of data and related operations that are common to its objects).
  • object- an instance, or specimen, of a given class. An object of a given class has the attributes and behavior described by the class that is common to all objects of the same class.

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).

Member Functions

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++.

Elements of syntax

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.

Message Passing

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.

hello.cc

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);
}

g++: The C++ compiler

Terminology

  • Source Code- plain ASCII text with the programming language's structures and grammar, and comments.
  • Assembly Code- plain ASCII text containing the assembly mnemonics equivalent of your source code. (There exists a one-to-many relationship between a programming language command and the corresponding assembly functionality).
  • Object Code- binary file containing the machine code equivalent of the assembly mnemonics. (There is a direct one-to-one relationship between an assembly mnemonic and corresponding machine instruction). This code by itself is not executable as it still relies on functionality from the various system libraries.
  • Machine Code- the final product of the compilation process. This is in machine language- and is in the form that the computer can natively understand it.
  • Architecture- implementation of machine code and supporting processor. Each different processor has different instructions and therefore machine language is not portable between different architectures/processors. Examples of architectures include: SPARC, AXP (Alpha), MIPS, x86 (Intel compatible), PowerPC/G3/G4, m68k, and many others…
  • Binary/Executable- the name given to the final compiled/linked program, which is capable of being invoked on the system (or other systems of the same architecture and platform). When you compile your hello.cc source file, you will have an executable (aka binary). I will interchange binary and executable throughout the course. They are essentially synonyms.
  • Platform- implementation of a computer architecture. Machine Language for platforms of an identical architecture are the same, but the system may be constructed in a different manner to make most functionality incompatible. This is also a bit fuzzy- as it is sometimes referred to regarding hardware and othertimes as software.

Examples of hardware architectures:

  • Sun's SPARCstations (SUN3, SUN4, SUN4c, SUN4d, SUN4m, SUN4u)
  • Silicon Graphic's MIPS workstations (MIPS3, MIPS4, MIPSEL)
  • m68k Macintosh and m68k Amiga
  • PPC (PowerPC)
  • PPC64 (64-bit PowerPC)
  • AMD64 (includes both 64-bit AMD and Intel (Core 2 and above)
  • x86 (32-bit Intel and AMD chips)
  • ia64 (64-bit Intel Itanium chips)

And software platforms:

  • FreeBSD
  • iOS (Apple mobile devices)
  • Linux
  • MacOS X
  • NetBSD
  • OpenBSD
  • Solaris
  • Win32 (95, 98, 98se, ME)
  • WinNT (NT 3.x, 4.x, 2000, XP, Vista, 7)

If we were to refer to Lab46 from a platform/architecture point of view, it would be a Linux/AMD64 machine.

  • Binary Compatibility- the ability of an executable of one platform/architecture to run unassisted on other machines of the same platform/architecture.

C/C++ and UNIX

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 Programming Model

The basic programming model of going from source code (what you write) to machine code (what the machine understands) is as follows:

  1. Source Code
  2. Compiler (to generate Assembly Code)
  3. Assembler (to generate Object Code)
  4. Linker (to link the Object Code with other Object Code from System Libraries)
  5. Finally: Machine Executable Code

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.

Using the compiler

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.

Shapes

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.

Questions

  1. What are the member functions of the Rectangle class?
  2. If dealing with a triangle, what are the formulas for perimeter and area?
  3. With a trapezoid, what are the formulas for perimeter and area?

Program 1

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:

  • define and implement two new member functions- setLength() and setWidth() and adjust your output accordingly to prove that they do what they are supposed to do.
  • Modify the program by adding Triangle and Trapezoid classes. Be sure to define the appropriate member functions and member data. To avoid confusion, be sure to employ the scoping operator (::). Also be sure that each “shape” has the ability to set the length/width as well as to retrieve its area and perimeter.
  • First make your changes to have everything in one big source file. Make sure this compiles and works as expected. Once you have this done, break apart your code into separate files (.h and .cc files), breaking all the code up as efficiently as you see fit (perhaps per each shape). Submit both the single (all-in-one) file, and the multi-file versions of your programs.

Access Control

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.

Questions

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:

  • What errors do you receive when trying to compile?
  • What is the reason the program does not compile in its original state?
  • How can you modify the class to fix the compilation problem (and have the program work as expected)?
  • Now assume you cannot modify the class, how could you fix the problem by changing code in main() and referencing the original class definition?
  • Why is it a good thing to not have direct access to the private member data of a class? Explain your reasoning.
  • Is there any reason you'd prefer to have direct access to all your data? If so, would the problem be better suited for a non Object-Oriented solution? Justify your answer.

Program 2

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).

Review of Compiling/Executing

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$ 

Optimization

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.

Copying files to your submit directory

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"
...

Submission

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:

  • placement of the code you created to solve this task in your ~/src/submit directory
  • name that file: task6.cc
  • addition/commit of task6.cc into your repository
  • create a directory task6/ in your ~/src/submit directory
  • place your multi-file implementation of task6.c in this task6/ directory
  • addition/commit of the task6/ directory and all its contents to your repository

As always, the class mailing list and class IRC channel are available for assistance, but not answers.

haas/spring2011/cprog/tasks/task6.txt · Last modified: 2011/03/08 17:44 by 127.0.0.1