A (Very) Short C/C++ reference manual

Jason Witherell (Shawnee State University)

 

This document is meant to be used as a quick review of C/C++.  It is meant to be used by people that have used C++ in the past, but need a little refresher.  This document is not a comprehensive reference by any means – I omit many powerful features of C++ in my discussion.  See one of the many C++ references on the web or in print for more details.

 

References:

 

Chapter I. The C/C++ Environment

C/C++ is a compiled language, so you will need a compiler to convert your (text) source files to machine code (assembly).  Two compilers I use frequently are Microsoft Visual Studio Express (2005) on Windows and gcc and g++ on Unix/Linux.  A brief review of each follows:

 

I.1 MS Visual Studio Express

Microsoft Visual Studio Express Edition 2005 (VS) is a freely available (at the time of writing) compiler with an excellent debugger.  In VS, you must first set up a project.  Unless you have a reason to use the advanced project types (Windows application, CLR forms application, etc.), you should make a DOS-type Win32 Console application.

 

Once the project is created, you must add new or existing .h and .cpp (or .c) files to the project.  The compiler (and the underlying linker) then can combine all source files into an executable (.exe) file.

 

Under the Project : myProject Properties… menu option, several common option that I typically set:

      • Configuration Properties: General:
        • Change “Character Set” to “Not Set”
      • Configuration Properties: C/C++: General:
        • Change “Debug Information Format” to “Program Database for Edit & Continue (/ZI)
        • Change “Warning Level” to “Warning Level 1 (/W1)”
      • Configuration Properties: C/C++: Optimization:
        • Change “Optimization” to “Disabled (/Od)
      • Configuration Properties: Linker:
        • Change “Generate Debug Info” to “Yes (/DEBUG)

 

Now, you can start your application in Debug mode (F5), which allows the setting of breakpoints and using the stack trace, etc.  You can also run in non-debug mode (Ctrl-F5).  This mode keeps the window open until the user pressed “Enter”.

I.2 gcc and g++

gcc and g++ are very similar (g++ compiles C++ programs, gcc compiles C programs)

 

At the command prompt, type

gcc –c my_file1.c my_file2.c –o myexe

Then, just type myexe at the command prompt to run your new executable.  Gcc also has a debugger, but you’re on your ownJ

 

I.3 Source program layout.

Every C/C++ (at least the console versions) must have a main program. A minimal C++ program might look like:

 


#include <cstdlib>

#include <iostream>

using namespace std;

 

int main()

{

char name[64];

 

      cout << “Enter your first name: “;

      cin >> name;

      cout << “Thanks for using my program, “ << name << endl;

 

      return 0;

}

 

I.4 Multi-program layout

averager.h

 
Most C/C++ programs of moderate to large size will span multiple files.  A multi-file program might look like similar to this:

 


#ifndef _AVERAGER_H_

#define _AVERAGER_H_

#include <cstdlib>

#include <iostream>

 

float get_average(float * list, int list_size);

 

#endif

 

 


#include “averager.h”

 

float get_average(float * list, int list_size)

{

int i;

float total=0.0;

 

      if (list == NULL || list_size <= 0)

            return 0.0;

 

      for (i=0; i<list_size; i++)

      {

            total += list[i];

}

total /= (float)list_size;

 

return total;

}

 

 

 

 

 

 

 

 

 

main.cpp

 
#include “averager.h”

 

int main()

{

int size, i;

float * numbers=NULL;

 

      cout << “How many numbers? “;

      cin >> size;

     

      numbers = new float[size];

      for (i=0; i<size; i++)

      {

            cout << “Number “ << i << “: “;

            cin >> numbers[i];

      }

 

      cout << “The average is: “ << get_average(numbers, size) << endl;

}

 

 

The compiler compiles average.cpp and main.cpp into object files (assembly code).  averager.h is “copied-and-pasted” before compiling starts anywhere there is the line “#include “averager.h””.  The linker combines average.obj and main.obj into main.exe (or similar).

 

Chapter II. C/C++ Variables

In C/C++, a variable must be declared before it is used. .

int mCnt;

mCnt = 0;

mCnt = “abc”;     // ERROR: incompatible types

 

There are several basic data types available in C/C++ programs:

  • Integers:

int x;

short s;

x = 512;

x = 512.9;        // Allowed, but the .9 is discarded (x holds 512 still).

x = (int)512.9;   // Won’t generate the compile warning.

s = x;           

// An int is generally 4 bytes, a short 2.

  • Characters:

char c;

c = ‘a’;

c = ‘\n’;   // An escape sequence (newline)

c = ‘\t’;   // A tab (note these are single characters – the slash

            // is just a cue to the compiler).

c = ‘\\’;   // A single-backslash character.

c = ‘\’’;   // A single-quote character.

c = 113;    // A char is really just a 1-byte integer.  This is the same as

            // c = ‘q’;

  • Floats:

float f;

double d;

f = 3.14;

f = -1234e-4;     // Same as f = -0.1234;

d = f;

// A float is generally 4-bytes, a double 8.

  • Strings: (character arrays)

char name[] = “Jason”;

char temp_str[256];

char temp_str2[256];

char * sptr;

int x;

float b = 1.05;

strcpy(temp_str, “Shawnee State”);

temp_str[0] = 0;        // Clears the string.  Same as

//    strcpy(temp_str, “”);

x = strlen(temp_str);   // Assigns 13 to x

x = sizeof(temp_str);   // Assigns 256 to x

strcat(temp_str, “: “);

strcat(temp_str, name); // temp_str now holds “Shawnee State: Jason”

sptr = strstr(temp_str, “as”);      // sptr holds the address of the

                                    // beginning of sub-string “ason”.

temp_str[13] = 0;       // temp_str now hold “Shawnee State

sprintf(temp_str2, “%s has worked at %s for %f years.\n”, name, temp_str,

      b);               // temp_str2 now holds “Jason has worked at

                        //    Shawnee State for 1.05 years.”

 

// The <string> library is only available in C++

#include <string>

 

string s;

s = “Jason”;

s = s + “ Witherell”;

strcpy(temp_str, s.c_str());

  • Other types of arrays:

float list[10];

int i;

for (i=0; i<10; i++)

      list[i] = i * i + 1;

// list now contains the numbers: {1, 2, 5, 10, 17, 26, 37, 50, 65, 82}

cout << list[2] << endl;      // Outputs a 5.

  • Structures

typedef struct

{

      int id;

      float salary;

      char name[64];

}EmpRec;

 

EmpRec e;

e.id = 14;

e.salary = 23500;

strcpy(e.name, “Bob”);

 

Chapter III. Pointers

Pointers are another type of basic variable.  However, their use has many subtle implications.

 

III.1 Pointer basics

A pointer is a variable (an int, internally) that holds a memory address.  The compiler, in most instances, requires that you declare what type of variable the pointer points to.  Pointers often use the address-of operator (&) to get an address.

 

int * ptr;  // The * in the declaration indicates this var. is a pointer

int x;      // Not a pointer

ptr = &x;   // ptr now holds the address of x.

x = 14;    

*ptr = 14;  // Does the same thing.  De-referencing the pointer.

 

III.2 Pointers and structures

Pointers can also hold the address of a structure (the beginning, actually). This works identically for objects.

 

EmpRec e;

EmpRect * eptr;

eptr = &e;

e.id = 14;

eptr->id = 14;

(*eptr).id = 14; // All 3 assignments are equivalent.

III.3 Pointers and Arrays

Arrays are really just pointers.  Often, we don’t think of them like that, but by doing so, you get a lot of flexibility.

 

int list[10] = {1, 1, 2, 3, 5, 8, 13, 21, 34, 55};

int * iptr;

iptr = list;      // Note how you DON’T need the ampersand.

list[0] = 0;

iptr[0] = 0;      // Equivalent.

iptr = &list[4];  // Here you DO need the ampersand.

iptr[0] = 0;      // This is like the statement list[4] = 0;

 

III.4 Pointers and functions

In C, to do pass-by-reference parameters to a function, you must use pointers (in C++, you can use a reference parameter).  In C and C++, to pass a list of value (or structures, or objects), you use pointers.

 

void func1(int * list, int list_size)

{

      list[0] = 12;

      list[list_size-1] = 1000;

}

 

void func2(int * num)

{

int temp_val;

      cout << “Enter an integer: “;

      cin >> temp_val;

 

      *num = temp_val;

}

 

void func3(int & num)

// This is the same as func2, but uses a C++ reference parameter

{

int temp_val;

      cout << “Enter an integer: “;

      cin >> temp_val;

 

      num = temp_val;

}

 

// (in the main program)

int list[100];

int mNum;

func1(list, 100); // Afterwards, list[0] and list[99] are set to 12 and 1000.

func2(&mNum);

func3(mNum);

 

III.5 Pointers and dynamic memory allocation

Pointers are needed to dynamically allocate memory (as opposed to static allocation, which is what has been shown so far).  Static allocations are determined at compile time.  For example, when you declare a normal array, you must provide the size.  If you don’t know the size at compile time, you must use dynamic memory allocation.  Also, normal variables have a lifetime of the block in which the variable exists.  Dynamically allocated memory doesn’t persists until de-allocated.

 

int * list = NULL;

int size;

 

cout << “How many numbers?”;

cin >> size;

list = new int[size];

//... use list ...

delete [] list;

 

MyObject * obj;

 

obj = new MyObject(“Jason”, 14, 92.4);

// ... use obj ...

obj->MyObjectFunc1(“Test”);

delete obj;

 

 

Chapter IV. Flow-control statements

There are 2 major flow-control statements in C/C++ with several variants. 

 

IV.1. Branching statements

Includes the if, if/else, if/else if/…/else statements as well as the switch statement

 

int num;

cout << “Enter a number: “;

cin >> num;

if (num <= 3)

{

      cout << “That’s a small number.” << endl;

            }

            else if (num >3 && num <= 6)

            {

                  switch(num)

                  {

                        case 4:

                              cout << “You entered a four.” << endl;

                              break;

                        case 5:

                              cout << “You entered a five.” << endl;

                              break;

                        default:

                              cout << “You entered a six.” << endl;

                              break;

                  }

            }

            else

            {

                  cout << “That’s a big number.” << endl;

            }

 

 

IV.2. Looping statements

Includes the while and do/while statements as well as the for loop (which is just a shorthand for common while loops).

 

int i, cnt;

double data[150];

for (i=0; i<100; i++)

      data[i] = sqrt((float)i);

cnt = 99;

while (cnt >= 0 && data[cnt] > 8.0)

{

      cout << cnt << “: “ << data[cnt] << endl;

      cnt--;

}

// This do-while loop works just like the while loop, except the condition

// is checked after the iteration (useful if you always want to execute the loop

// body at least once).

cnt = 99;

do

{

      cout << cnt << “: “ << data[cnt] << endl;

      cnt--;

}while (cnt >= 0 && data[cnt] > 8.0);

 

Chapter V. Functions

V.1 Basics

Function syntax always follows this pattern: “<return_type> <function_name> (<parameter_list>)”. 

 

int my_func1(float param1, int * param2)

{

      // your code goes here.

}

 

Often, a function declaration appears in a .h file or at the top of the current .c file.  Then in another .c file, or later on in the current one, you find the definition

 

EmpRec my_func2(int id, char * name);

 

// … somewhere else …

 

EmpRec my_func2(int id, char * name)

{

      EmpRec e;

 

      e.id = id;

      strcpy(e.name, name);

 

      return e;

}

 

V.2 Parameter passing

There are two main modes of passing functions in C/C++: by-value and by-reference.  Parameters passed by value have the value of the actual argument copied to the formal parameters.

 

void my_func3(int p)

// p is a formal argument. 

{

      p = 32;

}

 

// … (in main) …

int x = 19;

my_func3(17);           // 17 is the actual argument.  This value is copied to p before the

                  // function executes.

my_func3(x);            // x will still have the value 19 (not 32) after running this function.

 

Pass-by-reference parameters allow the function to change the value of the actual argument (in the caller).

 

void my_func4(int & p)

{

      p = 32;

}

 

// … (in main) …

int x = 19;

my_func4(x);            // x is now given the value 32.

 

 

 


Chapter VI. The Standard Template Library (STL)

The Standard Template Library contains many efficient and easy-to-use common data structures and algorithms.  The classes are templatized, which means you There are many more, but the STL containers I use most are vector and list, and some of the associated algorithms.

 

VI.1 vector

Internally, a vector is usually implemented as an array.  Adding and removing are only allowed at the end of the vector (there is another similar structure called the deque that allows adding and removing from the front or end).  Internally, there is a maximum size.  If it is exceeded, the array is re-allocated to a larger size and all elements are copied over.

 

#include <vector>

#include <iostream>

using namespace std;

 

int main()

{

vector <int> flist;

vector <EmpRec> elist;

int i;

EmpRec e;

 

flist.push_back(19);

flist.push_back(23);

for (i=0; i<5; i++)

      flist.push_back(rand() % 100);

flist.pop_back();

flist.pop_back();

for (i=0; i<flist.size(); i++)

      cout << flist[i] << endl;

 

e.id = 42;

e.salary = 23000;

strcpy(e.name, “Tim”);

elist.push_back(e);

e.id = 19;

e.salary = 42000;

strcpy(e.name, “Belinda”);

elist.push_back(e);

// Note: when you push something onto a vector, a copy is made, so

// this will work.

 

flist.clear();

elist.clear();

}

 

VI.2 list

Internally, a list is usually implemented as a linked-list.  As such, it allows efficient adding at any point in the list, but it does not allow random access (subscripting as in the line “cout << flist[i] << endl;”

 

#include <list>

#include <iostream>

using namespace std;

 

typedef struct

{

      int x;

      int y;

      float intensity;

}point;

 

int main()

{

list <point> plist;

list <point>::iterator iter;

list <point>::iterator prev_iter;

point tempp;

 

      tempp.x = 15;

      tempp.y = 32;

      tempp.intensity = 0.75;

      plist.push_back(tempp);

      tempp.x = 12;

      tempp.y = 19;

      tempp.intensity = 0.6;

      plist.push_front(tempp);

      tempp.x = 17;

      tempp.y = 92;

      tempp.intensity = 0.8;

      plist.push_back(tempp);

     

 

 

      cout << "****" << endl;

      for (iter = plist.begin(); iter != plist.end(); iter++)

      {

            cout << "(" << iter->x << ", " << iter->y << ") [";

cout << iter->intensity << "]" << endl;

                  }

 

      tempp.x = 16;

      tempp.y = -23;

      tempp.intensity = 0.5;

      if (plist.begin()->x >= tempp.x)

            plist.push_front(tempp);

      else

      {

            iter = plist.begin();

            while (1)

            {

                  prev_iter = iter;

                  iter++;

                  if (iter == plist.end())

                  {

                        plist.push_back(tempp);

                        break;

                  }

                  else if (prev_iter->x <= tempp.x && iter->x >= tempp.x)

                  {

                        // Insert tempp before iter

                        plist.insert(iter, tempp);   

                        break;

                  }

            }

      }

     

      cout << "****" << endl;

      for (iter = plist.begin(); iter != plist.end(); iter++)

      {

            cout << "(" << iter->x << ", " << iter->y << ") [";

cout << iter->intensity << "]" << endl;

                  }

           

      for (iter = plist.begin(); iter != plist.end(); )

      {

            if (iter->y < 20)

                  iter = plist.erase(iter);

            else

                  iter++;

      }

 

      cout << "****" << endl;

      for (iter = plist.begin(); iter != plist.end(); iter++)

      {

            cout << "(" << iter->x << ", " << iter->y << ") [";

cout << iter->intensity << "]" << endl;

                  }

 

                  plist.clear();

}

 

VI.3 algorithm

The algorithm library has many functions that work with STL objects.  I’ll show two examples here.

 

The Find algorithm (linear search) (O(n))

 

#include <vector>

#include <algorithm>

#include <iostream>

using namespace std;

 

int main()

{

list <double> dlist;

list <double>::iterator iter;

 

      dlist.push_back(3.4);

      dlist.push_back(19.7);

      dlist.push_back(2.3);

      dlist.push_back(9.15);

     

      iter = find(dlist.begin(), dlist.end(), 2.3);

      if (iter != dlist.end())

            cout << "Found!" << endl;

      else

cout << "Not found." << endl;

 

dlist.clear();

            }

 

The Sort algorithm (mergesort or quicksort, most likely) (O(n log n))

            Note: doesn’t work with lists.

 

#include <vector>

#include <algorithm>

#include <iostream>

using namespace std;

 

int main()

{

 

vector <double> dlist;

vector <double>::iterator iter;

 

      dlist.push_back(3.4);

      dlist.push_back(19.7);

      dlist.push_back(2.3);

      dlist.push_back(9.15);

     

      sort(dlist.begin(), dlist.end());

     

      for (int i=0; i<(int)dlist.size(); i++)

cout << dlist[i] << endl;

 

dlist.clear();

            }

 

 

Chapter VII. C++ Files

VII.1 Text Files

 

#include <fstream>

#include <iostream>

#include <vector>

using namespace std;

 

 

int main()

{

#if 1

fstream fp;

int size = 5;

double num;

 

      fp.open("test.txt", ios::out);

      fp << "A Line of text" << endl << "==============" << endl;

      fp << size << endl;

      for (int i=0; i<size; i++)

      {

            num = (float)(rand() % 1001) / 200.0;

            fp << num << endl;

      }

      fp.close();

#else

fstream fp;

int size, i;

char line[256];

double num;

vector <double> data;

 

      fp.open("test.txt", ios::in || ios::binary);

      if (fp)

      {

            fp.getline(line, 255, '\n');

            cout << line << endl;

            fp.getline(line, 255, '\n');

            cout << line << endl;

            fp >> size;

            cout << size << endl;

            for (i=0; i<size; i++)

            {

                  fp >> num;

                  data.push_back(num);

                  cout << data[data.size()-1] << endl;

            }

            fp.close();

           

            data.clear();

 

            // I didn’t use it here, but there the eof function

            // (fp.eof(), which returns true if you’ve read past

            // the end of the file) is very useful in reading

            // text (and binary) files.

      }

      else

            cout << "Couldn't open the file!" << endl;

 

#endif

}

 

VII.2 Binary Files

#include <iostream>

#include <fstream>

using namespace std;

 

 

int main()

{

fstream fp;

int num, i;

short * data = NULL;

long fsize;

 

#if 0

      data = new short[57];

      num = 57;

     

      for (i=0; i<num; i++)

            data[i] = i + 10;

     

      fp.open("test.bin", ios::out | ios::binary);

      if (fp)

      {

            fp.write((char*)&num, sizeof(int));

            fp.write((char*)data, sizeof(short)*num);

     

            fp.close();

      }

      else

            cout << "Couldn't open test.bin for writing!" << endl;

           

      delete [] data;

#else

      fp.open("test.bin", ios::in | ios::binary);

      if (fp)

      {

            // Move the read position (g) (there is a seperate

// write (p) position) to the end of the file, get

// the position (really, the number of bytes in

            // the file), then move the position back to the beginning.

            fp.seekg(0, ios::end);

            fsize = fp.tellg();

            fp.seekg(0, ios::beg);

            fp.read((char*)&num, sizeof(int));

            cout << “File Size=” << fsize << endl;

 

            data = new short[num];

            if (data)

            {

                  fp.read((char*)data, sizeof(short)*num);

                  for (i=0; i<num; i++)

                        cout << i << ": " << data[i] << endl;

                  delete [] data;

            }

           

            fp.close();

      }

      else

            cout << "Couldn't open test.bin for reading!" << endl;

#endif

}

 

Chapter VIII. Objects and Classes

Object-oriented programming in a nutshell is the collection of variables (like a struct) with a set of associated functions (methods) that operate on the data in the collection (the object).  In many situations, this is a much more natural means of writing programs (writing functions and passing data as arguments).

 

POItem.h

 
Chapter VIII.1 Basics

 


#include <string>

#include <iostream>

using namespace std;

 

class POItem

{

private:

      string item_name;

      int quantity;

      float unit_cost;

public:

      // Constructors

      POItem();

      POItem(string n, int q, float uc);

     

      // Miscellaneous functions

      void initialize();

      void Print(char sep='\t');

      float TotalCost();

     

      // Accessors ("getters") and Mutators ("setters")

      string ItemName() {return item_name;}

      int Quantity() {return quantity;}

      float UnitCost() {return unit_cost;}

      void SetItemName(string n) {item_name = n;}

      void SetQuantity(int q) {if (q >= 0) quantity = q; else quantity = 0;}

      void SetUnitCost(float uc) { if (uc >= 0.0) unit_cost = uc; else unit_cost = 0.0;}

};

 

 


#include “POItem.h”

 

POItem::POItem()

{

      initialize();

}

 

POItem::POItem(string n, int q, float uc)

{

      SetItemName(n);

      SetQuantity(q);

      SetUnitCost(uc);

}

 

 

 

 

 

 

POItem.cpp (cont)

 
void POItem::initialize()

{

      item_name = "";

      quantity = 0;

      unit_cost = 0.0;

}

 

void POItem::Print(char sep)

{

      cout << item_name << sep << quantity << sep << unit_cost << endl;

}

 

float POItem::TotalCost()

{

      return quantity * unit_cost;

}

 

 


#include “POItem.h”

 

int main()

{

POItem p;                                             // Uses the default constructor

POItem q("Chocolate Chips", 10, 1.25);    // Uses the second constructor

POItem * ptr = NULL;

POItem plist[5];

int i;

 

      p.Print();

      p.SetItemName("Carrots");

      p.SetQuantity(4);

      p.SetUnitCost(0.89);

      p.Print('@');

      cout << "Value of p: " << p.TotalCost() << endl;

      q.Print();

      cout << "Value of q: " << q.TotalCost() << endl;

     

      ptr = new POItem();

      ptr->Print();

      cout << "Value of *ptr: " << ptr->TotalCost() << endl;

      delete ptr;

      ptr = new POItem("Peanuts", 150, 4.75);

      ptr->Print();

      cout << "Value of *ptr: " << ptr->TotalCost() << endl;

      delete ptr;

      ptr = NULL;

     

      for (i=0; i<5; i++)

      {

            plist[i].SetItemName("Misc Item #" + (i+1));

            plist[i].SetQuantity(i * 5 + 2);

            plist[i].SetUnitCost(i * 0.5 + 0.5);

            plist[i].Print();

      }

}

 

 

Note that this separation into multiple files is completely optional.  It does, however, tend to increase the readability of your code.

 

Chapter VIII.2 Operator Overloading

Operator overloading is a useful technique for some classes.  It allows you to overload the standard C/C++ operators (+, *, =, etc); in other words, you re-define these operators to do some (hopefully) meaningful operation on an object of your class.  In this example, I overload the = operator (assignment) and the + operator (with an integer) to add some to the quantity of the item.

 

This goes somewhere within the class definition in POItem.h:

const POItem & Copy(const POItem & p);   

      const POItem & operator =(const POItem & p) {return Copy(p);}

      POItem operator + (int q);

      POItem operator + (float uc);

This goes somewhere in POItem.cpp:

 

const POItem & POItem::Copy(const POItem & p)

{

      if (p.item_name == item_name) // Notice how you can access the private

                                                      // memebers of a const object reference.

      {

            item_name += ".";

      }

      else

            item_name = p.item_name;

      quantity = p.quantity;

      unit_cost = p.unit_cost;

     

      return (*this);

}

     

POItem POItem::operator + (int q)

{

POItem newPO;

 

      newPO = *this;

      newPO.SetQuantity(newPO.Quantity() + q);

     

      return newPO;

}

 

 

POItem POItem::operator + (float uc)

{

POItem newPO;

 

      newPO = *this;

      newPO.SetUnitCost(newPO.UnitCost() + uc);

     

      return newPO;

}

 

 

 

 

 

And a simple new main program tests these new features out:

int main()

{

POItem p;

POItem q("Chocolate Chips", 10, 1.25);   

 

      p = q;

      p.Print(' ');

     

      p = p + 5;

      p.Print();

     

      p = p + 1.25f;

      p.Print();

 

}

 

 

Chapter IX. Inheritance and Polymorphism

Inheritance allows you to base a new (derived) class from an existing one (a base class).  The derived class can then add new member variables, add or change member functions.  The derived class can also be used as a base class for new classes.

 

IX.1 Inheritance

#include “POItem.h”

 

class DiscountPOItem : public POItem

{

private:

      float discount_pcent;

public:

      DiscountPOItem() {SetItemName(""); SetQuantity(0); SetUnitCost(0.0); SetDiscountPcent(0.0);}

      DiscountPOItem(string n, int q, float uc, float dp) {SetItemName(n); SetQuantity(q); SetUnitCost(uc); SetDiscountPcent(dp);}

     

      float DiscountPcent() {return discount_pcent;}

      void SetDiscountPcent(float dp) {if (dp >= 0.0) discount_pcent = dp; else discount_pcent = 0.0;}

     

      // This is a re-definition of the TotalCost function we inherited from the base class.

      float TotalCost();

     

      void Print(char sep='\t');

};

 

 

void DiscountPOItem::Print(char sep)

{

      // Note: we MUST use the accessor functions to access private member of the base class!

      cout << ItemName() << sep << Quantity() << sep << UnitCost() << sep << discount_pcent << endl;

}

 

 

float DiscountPOItem::TotalCost()

{

float orig_price, new_price;

 

      orig_price = POItem::TotalCost();

      new_price = orig_price - orig_price * discount_pcent;

     

      return new_price;

}

 

 

int main()

{

DiscountPOItem p("Beans", 10, 0.1, 0.05);

 

      p.Print();

      cout << "Total Price of p: " << p.TotalCost() << endl;

 

}

 

IX.2 Polymorphism

Polymorphism is used in conjunction with inheritance.  Let us define class A, and class B and C, both of which are derived from class A.  All three classes define their own version of a function, Func.  One way to use polymorphism is to write a function which takes as an argument, a pointer to an object of type A.  You can then pass any of the three classes to this function.  If you use polymorphism, the correct version of Func will be called based on what was type of object was passed.  Note that this is a run-time determination, not a compile-time determination (which is what happens if you don’t specify you are using polymorphism with Func).

 

#include <iostream>

#include <vector>

using namespace std;

 

class Gun

{

protected:

      int ammo;

      int heat_lvl;

      vector <int> bulletx;

      vector <int> bullety;

public:

      Gun() {initialize();}

      virtual ~Gun() {delete_mem();}

      virtual void initialize();

      virtual void delete_mem();

      virtual void Print();

      virtual void Fire() = 0;

};

 

class Rifle : public Gun

{

public:

      virtual void Fire();

};

 

 

class Handgun : public Gun

{

public:

      virtual void Fire();

};

 

 

void Gun::initialize()

{

      ammo = 10;

      heat_lvl = 0;

}

 

 

void Gun::delete_mem()

{

      bulletx.clear();

      bullety.clear();

}

 

 

void Gun::Print()

{

      cout << "[Ammo=" << ammo << ", Heat=" << heat_lvl << ", #Bullets=" << bulletx.size() << "]" << endl;

}

 

 

void Rifle::Fire()

{

      if (ammo > 0 && heat_lvl < 50)

      {

            cout << "You fire the rifle!" << endl;

            ammo -= 1;

            heat_lvl += 10;

      }

      else if (ammo <= 0)

            cout << "No more ammo!" << endl;

      else if (heat_lvl >= 50)

            cout << "The gun is too hot to fire!" << endl;

}

 

 

void Handgun::Fire()

{

      if (ammo > 0 && heat_lvl < 70)

      {

            cout << "You fire the handgun!" << endl;

            ammo -= 1;

            heat_lvl += 4;

      }

      else if (ammo <= 0)

            cout << "No more ammo!" << endl;

      else if (heat_lvl >= 50)

            cout << "The gun is too hot to fire!" << endl;

}

 

 

void FireTheGun(Gun * g)

{

      g->Fire();

}

 

void PrintGunStatus(Gun & g)

{

      g.Print();

}

 

 

void main()

{

Rifle r;

Handgun h;

 

      FireTheGun(&r);

      PrintGunStatus(r);

      FireTheGun(&h);

      PrintGunStatus(h);

}

 

 

 


Chapter X. C Files

Binary files are very similar to C++ files, except you call functions (for reading, writing, etc) and pass the file reference to the function (instead of using a method of the file object).  Text files primarily use fprintf for writing and fscanf for reading (instead of C++’s chevron (>> and <<) operators).  By the way, you

 

X.1 Text files

int main()

{

FILE *fp=NULL;

DiscountPOItem * plist;

int i, plist_size;

 

#if 0

      plist = new DiscountPOItem[4];

      plist_size = 4;

      plist[0] = DiscountPOItem("Corn", 4, 0.25, 0.0);

      plist[1] = DiscountPOItem("Beans", 8, 0.05, 0.01);

      plist[2] = DiscountPOItem("Milk", 1, 2.59, 0.0);

      plist[3] = DiscountPOItem("Orange Juice", 2, 3.50, 0.05);

 

      fopen_s(&fp, "ctext.txt", "wt");

      if (fp)

      {

            fprintf_s(fp, "%d\n", plist_size);

            for (i=0; i<plist_size; i++)

            {

                  fprintf_s(fp, "%d %f %0.02f %s\n", plist[i].Quantity(),

plist[i].UnitCost(), plist[i].DiscountPcent(),

                              plist[i].ItemName().c_str());

            }

     

            fclose(fp);

      }

     

      delete [] plist;

      plist = NULL;

#else

      char new_name[64];

      int new_qty;

      float new_ucost, new_disc;

 

      fopen_s(&fp, "ctext.txt", "rt");

      if (fp)

      {

            fscanf_s(fp, "%d", &plist_size);

            fgets(new_name, 63, fp);      // "Eat-up" the rest of the line

            plist = new DiscountPOItem[plist_size];

            if (plist)

            {

                  for (i=0; i<plist_size; i++)

                  {

fscanf_s(fp, "%d %f %f", &new_qty, &new_ucost,

&new_disc);

                        fgetc(fp);       

// Get rid of the space after the last number

                        fgets(new_name, 63, fp);

// Get rid of the last character ('\n')

                        new_name[strlen(new_name)-1] = 0;  

                        plist[i].SetItemName(string(new_name));

                        plist[i].SetQuantity(new_qty);

                        plist[i].SetUnitCost(new_ucost);

                        plist[i].SetDiscountPcent(new_disc);

                        plist[i].Print();

                  }

           

                  delete [] plist;

                  plist = NULL;

            }

     

            fclose(fp);

      }

#endif

 

X.2 Binary files

Binary Files are opened in a similar manner to C text files, but with access modes “wb” or “rb” (write-binary or read-binary).  This example illustrates some of the major binary file functions.

 

#include <iostream>

#include <cstdlib>

#include <cstdio>

using namespace std;

 

 

int main()

{

int response=-1, num_entries, val, i, pos;

FILE *fp=NULL;

char fname[256];

 

      while (response != 0)

      {

            cout << "1. Create a data file.\n";

            cout << "2. View an entry in the data file.\n";

            cout << "3. Print out the contents of the file.\n";

            cout << "0. Quit.\n";

            cout << ">>";

            cin >> response;

            if (response == 1)

            {

                  cout << "Data File Name: ";

                  cin >> fname;

                 

                  fopen_s(&fp, fname, "wb");

                  cout << "Number of data 'slots': ";

                  cin >> num_entries;

                  if (num_entries > 0)

                  {

                        for (i=0; i<num_entries; i++)

                        {

                              val = i * 2 + 1;

                              fwrite((void*)&val, sizeof(int), 1, fp);

                        }

                  }

                  fclose(fp);

            }

            else if (response == 2)

            {

                  cout << "Opening " << fname << endl;

                  fopen_s(&fp, fname, "rb");

                 

                  if (fp)

                  {

                        cout << "Which Entry? ";

                        cin >> pos;

                        fseek(fp, 0, SEEK_END); // other options are

// SEEK_SET and SEEK_END

                        if (pos * sizeof(int) < ftell(fp))

                        {

                              fseek(fp, sizeof(int)*pos, SEEK_SET);

                              fread((void*)&val, sizeof(int), 1, fp);

                              cout << "At that position: " << val << endl;

                        }

                  }

                 

                  fclose(fp);

            }

            else if (response == 3)

            {

                  cout << "Opening " << fname << endl;

                  fopen_s(&fp, fname, "rb");

                  if (fp)

                  {

                        while (!feof(fp))

                        {

                              fread((void*)&val, sizeof(int),1, fp);

                              cout << val << endl;

                        }

                  }

                 

                  fclose(fp);

            }

      }

      return 0;

}