User Tools

Site Tools


Sidebar

projects

  • cci0 (due 20170607)
  • sof0 (due 20170614)
  • dow0 (due 20170621)
  • mbe0 (due 20170628)
  • pnc0 (due 20170705)
  • pnc1 (due 20170712)
  • mbe1 (due 20170719) iOR
  • pnc2 (due 20170719) (or do both, 1 as bonus)
  • fcc0 (due 20170726)
  • sfa0 (due 20170802)
  • oop0 (due 20170809)
  • EoCE – bottom of your journal (due 20170819)
haas:summer2017:cprog:projects:oop0

Corning Community College

CSCS1320 C/C++ Programming

~~TOC~~

Project: OBJECT-ORIENTED PROGRAMMING - CLASSES AND OBJECTS (oop0)

Objective

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

Background

When we have a task or problem at hand we wish to solve, there are often many different ways of solving it. If the task is labor-intensive, perhaps using some tool to facilitate the task would be in order. Or, if the problem requires modification and tweaking, constant evaluation, we may use other tools to help automate the task. Sometimes a task or problem can be greatly simplified by analyzing it logically, determining any structure or patterns inherent therein, and coming up with a solution that most efficiently takes advantage of the situation.

When we look at a problem logically, we can often break it down into discrete parts, each of which is simple (or less complex) to solve, and when cooperating together, can help solve the larger task at hand. In C or shell scripting we tend to deal with things in an imperative (or procedural) manner- 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

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 (especially if you've got a standalone or small codebase).

Terminology

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.

Organization

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 4 byte storage boundaries– as that is how the computer deals with it, we are only concerned with the data, the ability to store a number).

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 these 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
		Function Members
		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 also the function members)- 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

The “Function Members” (Member Functions, whatever) are algorithms used for manipulating the class 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++.

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 OO. (Incidentally, it is also used in other contexts as well, such as in some methods of Distributed Systems/Cluster programming).

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.

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.

Public access control is just that– available for all to see. Private access means only accessible to the other class members WITHIN that particular 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.

There are some additional access control attributes available: protected and friend. Protected access control is utilized more in inheritance, and the “friend” attribute is used in extraneous circumstances when a clear relationship cannot be established (also in inheritance).

Programming in C++

We will be using the GNU C++ (g++) compiler to compile our C++ programs. There are a number of extensions the compiler recognizes:

  • .cc
  • .C (single, but CAPITAL 'C')
  • .cpp
  • .c++

I prefer using .cc, so you will see that in many (if not all) of my examples.

hello0.cc

Your first C++ program!

Time to start playing with C++. Let's start with the traditional “Hello, World!” example:

/*
 * hello0.cc - a simple "Hello, world!" in C++.
 */
 
// include standard I/O stream functions
//
#include <stdio.h>
 
// main() function
//
int main()
{
    fprintf (stdout, "Hello, world!\n");
    return (0);
}

Look familiar? It should. Pretty much EVERYTHING you've written so far can be dropped into a C++ program and compiled. So in a way, you already know aspects of 80-95% of C++.

hello1.cc

Your second C++ program! A slightly more C++-ized version of the above.

Compare the differences:

/*
 * hello1.cc - a simple "Hello, world!" in C++.
 */
 
// include standard I/O stream functions
//
#include <cstdio>
 
// main() function
//
int main()
{
    fprintf (stdout, "Hello, world!\n");
    return (0);
}

Did you see it? It was in the #include statement. The “C++ way” to identify classic C header files is to prefix them with a “c” and drop the ”.h“ (many C++ header files do not have the ”.h“ extension). Modern compilers are generally flexible enough to handle either approach.

hello2.cc

A strictly C++ version of the same thing:

/*
 * hello2.cc - a simple "Hello, world!" in C++.
 */
 
// include standard I/O stream functions
//
#include <iostream>
 
// main() function
//
int main()
{
    std :: cout << "Hello, world!" << std :: endl;
    return (0);
}

Compare the similarities, note the differences.

hello3.cc

A strictly C++ version of the same thing (also how you'd likely see 99% of all C++ references on the planet portray this program):

/*
 * hello3.cc - a more C++-y and simple "Hello, world!" in C++.
 */
 
// include standard I/O stream functions
//
#include <iostream>
using namespace std;
 
// main() function
//
int main()
{
    cout << "Hello, world!" << endl;
    return (0);
}

Take specific note of the “using namespace” and how it further simplified our program's appearance.

This is but another form of abstraction, and information availability; just as variables can have a pertinent scope, the deeper visibility of various objects can be made possible by assuming a default class naming scheme (or namespace) by default.

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.
  • Binary Compatibility- the ability of an executable of one platform/architecture to run unassisted on other machines of the same platform/architecture.

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
  • ARM32
  • ARM64
  • 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)

Examples of software platforms

  • Android
  • FreeBSD
  • iOS
  • Linux
  • macOS (classic)
  • macOS (X)
  • NetBSD
  • OpenBSD
  • Plan 9
  • Solaris
  • Win32 (95, 98, 98se, ME)
  • WinNT (NT 3.x, 4.x, 2000, XP, Vista, 7, 8, 10)

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

Similarly, Linux on a Raspberry Pi 1 or 2 (being a 32-bit machine), would be a Linux/ARM32 machine.

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 predominantly 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 first C++ program was allegedly a program that translated C++ programs into C programs).

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, just as how you've been using gcc:

lab46:~$ g++ -Wall --std=c99 -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.

rectangle class

In the oop0/ subdirectory of the CPROG Public Directory (/var/public/summer2017/cprog/), you will find a file called rectangle.cc:

lab46:~/src/cprog/oop0$ cp /var/public/summer2017/cprog/oop0/rectangle.cc .
lab46:~/src/cprog/oop0$ 

Please read through this source code, compile, and run the program. Make sure you understand what is going on.

Program

We've got the accessor functions of getLength()/setLength() and getWidth()/setWidth() for checking and setting the current values of the particular rectangle's length and width, and area() and perimeter() for performing useful actions on that data. You'll notice all those member functions are empty. Go ahead and finish the implementation of this program:

  • implement the member functions (keeping any function parameter names identical to how you received them)
  • duplicate the output code block in main(), adapting as appropriate for box2, box3, and box4.
  • 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.

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++ -Wall --std=c99 -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++ -Wall --std=c99 -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$ 

Submission

To successfully complete this project, the following criteria must be met:

  • Code must compile cleanly (no warnings or errors)
    • Use the -Wall and –std=c99 flags when compiling.
  • Output must be correct, and resemble the form given in the sample output above.
  • Code must be nicely and consistently indented (you may use the indent tool)
  • Code must utilize the algorithm presented above
  • Code must establish and utilize the functions described above
  • Code must be commented (and those comments relevant)
  • Track/version the source code in a repository
  • Submit a copy of your source code to me using the submit tool.

To submit this program to me using the submit tool, run the following command at your lab46 prompt:

$ submit cprog oop0 oop0.cc
Submitting cprog project "oop0":
    -> oop0.cc(OK)

SUCCESSFULLY SUBMITTED

You should get some sort of confirmation indicating successful submission if all went according to plan. If not, check for typos and or locational mismatches.

haas/summer2017/cprog/projects/oop0.txt · Last modified: 2017/08/01 14:05 by wedge