  With Class C++ Code Generation for Borland C++ and Visual C++

   by Richard Felsinger, RCF Associates, 960 Scottland Dr, Mt
Pleasant, SC 29464 telephone 803-881-3648 - CompuServe 71162,755 
                                3/7/94

The purpose of article is to present the "how to" steps to
generate C++ code using the With Class CASE (computer aided
software engineering) tool.  With Class is available in a
shareware version from MicroGold Software 696 Birch Hill Drive,
Bridgewater, NJ, 08807 telephone 908-722-6438 - CompuServe
71543,1172.   On CompuServe, you may find With Class in the
Borland Forum - Borland C++ for Windows - Non Tech Cust Service
with the file name wclass.zip.  

The current With Class Version 1.6 generates either ANSI C++
compilable code,  Borland C++ Version 3.1 with OWL 1.0 compilable
code, or Visual C++ with MFC 2.0 compilable code.  To generate
C++ for Borland C++ 4.0 with OWL 2.0 or Microsoft Visual C++ for
QuickWin, you must first generate ANSI C++ and then manually
update the code for the appropriate libraries.   Guidelines will
be presented.

Using With Class, you first create a class diagram showing the
classes, attributes, operations, and relationships.   You fill in
specification forms (dialog boxes) to add additional information
about each class, attribute, operation, and relationship.   With
Class generates the following ANSI C++ compilable code from a
class diagram:
- #ifdefs,
- #includes,
- default constructor,
- constructor with arguments,
- copy constructor, 
- default destructor,
- =operator (assignment operator),
- ==operator (equality operator),
- get and set functions for data members,
- pointer data member for 1 to 1 and 1 to many associations using
C array,
- data member for 1 to 1 and 1 to many aggregations using C
array,
- inheritance relationships.

With Class generates the following C++ for the C++ iostreams:
- operator<< insertion operator for cout statements, 
- operator>> extraction operator for cin statements.
These operators may be used in Borland C++ and Visual C++ under
the QuickWin project option.

With Class generates streamable classes for persistence only for
Borland C++ using OWL 1.0.   To create streamable classes for
Borland C++ 4.0 with OWL 2.0, manually update your code. 
Likewise, to create serial classes for Visual C++ with MFC 2.0,
manually update your code. 

If specified by the user, With Class generates the following:
#include statements for external files (library files), initial
data member values in constructors, virtual functions, pure
virtual functions, static functions, and const functions.   A
user must manually insert the following keywords: static for data
members and friend for functions.   If you use the "Insert the
prefix T" option you must manually update your constructor and
destructor names with the prefix.

         Generating C++ for Borland C++ 3.1 with OWL 1.0

The following are the steps to generate C++ for Borland C++ 3.1
with OWL 1.0.  
 
>> Run With Class from Windows
>> Select "File - Open", e.g., c:\car\car.omt
>> Select "Generate - Options" and select C++ code generation
options  
>> Select "Generate - Generate Code"
>> Select "File - Edit File" and select a ".h" or ".cpp" file for
review

Once the code is generated, then the user may go to a C++
compiler to compile, link, and execute the code.   To use the
Borland C++ 3.1 environment, the following are sample environment
settings for Borland C++ Options:

Application: Large Memory Model
Linker Link Libraries: Static for all libraries
Include Directories: c:\bc\include;
c:\bc\owl\include;c:\bc\classlib\include; 
Library Directories: c:\bc\lib; c:\bc\owl\lib;
c:\bc\classlib\lib;
Compiler - Code Generation - Defines    WIN31

The steps to Compile the C++ Source Files in Borland C++ are:

>> Run Borland C++ (BCW) from Windows
>> Select "Project - Open Project"
>> Enter a project file name, e.g., carproj.prj
>> Select "Project - Add Item"
>> In the Directories Box, change the directory where the C++
files are located, e.g., Car Directory
>> Enter *.cpp in the File Name Box
>> Select the .cpp files, e.g., main.cpp and car.cpp and click on
the "Add Button" to add each file to the project
>> Select "Done"
>> Select "Options - Directories" to update the Include
Directories List
>> In the Include Directories Box, add the directory where the
C++ files are located, e.g., c:\car
>> Select "OK"
>> Select "Compile - Compile" to compile the C++ source code
>> Select "Run - Run" to compile, link, and execute

To execute the program the user must create a main function.  
The steps to create a main function and execute the program in
Borland C++ are listed below.   To execute the C++ source code
with messages, you must update the main module with an object
declaration and messages to the object.  
>> Select "File - Open" 
>> Select the main function, e.g., c:\car\main.cpp
>> Enter the C++ statements for the main, e.g., statements shown
below
>> Select "File - Save" 
>> Select "Compile - Compile" to compile the main function
>> Select "Run - Run" to compile, link, and execute the program

#include "car.h"                   //Added code to use generated
C++
main ()
{
     Car car11;                         //object declaration
     car11.setGasQty (10.0);                      //function call
     car11.start ();                              //function call
     int aGasQty = car11.getGasQty ();            //function call
     return (0);
}

 Generating Streamable Classes for Borland C++ 3.1 with OWL 1.0

A persistent object retains its values when the program is not
running, e.g., the system is not active.  The three primary ways
to create persistent objects are with flat file storage,
relational data base management system storage, or object
oriented data base storage.   With Class generates C++ streamable
classes (Borland C++) for persistent objects with the following
steps: 

>>  Select "Make All Classes Streamable", "Get Methods", and Set
Methods" from the Options Menu.

>>  Select "Generate Code" from the Generate Menu.

>>  Update the generated code as follows:

     Create a stream object, e.g. inputStream or outputStream.

     Open the stream object, e.g. inputStream.open ("CAR.STM").

     Read from or write to the stream object, e.g.
     inputStream >> car1 or outputStream << car1.

     Close the stream object, e.g. inputStream.close ().

As an example, a class diagram was created with a single class
Car with the data member "float gasQuantity".   With Class
automatically generated the get and set functions:
"getGasQuantity" and "setGasQuantity".  The following main
function shows how to create, open, read from,  write to, and
close a C++ a file stream.   In this example, the car1 object was
written to and read from a C++ file stream for persistent
storage.

#include "car.h"                        //Added code to use
generated C++

#include <iostream.h>
int main ()                             //Implements MainUser
{
     Car car1;                     
     car1.setGasQuantity (20.0);
     ofpstream outputStream;             //Creates file stream
     outputStream.open ("CAR.STM");
                                        //Opens file stream
     if (outputStream.bad () )
          cout << "Could not open file/n";
     outputStream << car1;              //Writes to file stream
     outputStream.close ();             //Closes file stream
     Car car2;
     ifpstream inputStream;             //Creates file stream
     inputStream.open ("CAR.STM");      //Opens file stream
     if (inputStream.bad())
          cout << "Could not open file/n";
     inputStream >> car2;               //Reads from file stream
     cout << car1.getGasQuantity ();
     cout << car2.getGasQuantity ();
     inputStream.close();               //Closes file stream
     return 0;
}

      Generating ANSI C++ for Borland C++ 4.0 with OWL 2.0

To generate C++ for Borland C++ 4.0, you must first generate ANSI
C++ then manually update the code for OWL 2.0.    In the With
Class Options dialog, the following are guidelines:
- check "#ifdef",
- check "Get and Set Methods",
- check "ostream << to display classes", 
- check "C Array",
- do not check "Make All Classes Streamable" - OWL 1.0 only,
- do not check "C++ Collection Templates" - OWL 1.0 only.

The steps to generate C++ for Borland C++ 4.0 with OWL 2.0 are
similar to the steps previously stated for Borland C++ 3.1.  
After code has been generated the code can be manually updated
for streamable classes and OWL 2.0 collection classes.  OWL 2.0
collection classes may be used to implement the "1 to many"
relations.  The following OWL 2.0 classes may be used: TListImp,
TArray, TStack, and TBag.  The following short program shows
these classes with their appropriate #include file.

#include <iostream.h>                   //for cout
#include <cstring.h>                    //for string class
#include <classlib\listimp.h>           //for TListImp class
#include <classlib\arrays.h>            //for TArray class
#include <classlib\stacks.h>            //for TBag class
#include <classlib\bags.h>

int main ()
{
  cout << "hello\n";
  string name1 ("dick");
  string name2 ("geni");

  cout << "Enter your name\n";
  cin >> name1;
  cout << name1;

  TListImp <string> aList;              //List class
  aList.Add (name1);
  aList.Add (name2);
  aList.Detach (name2);

  TSListImp <string> aSortedList;       //Sorted List class    
  aSortedList.Add (name1);
  aSortedList.Add (name2);
  aSortedList.Detach (name2);

  TArray <string> anArray (10);         //Array class
  anArray.Add (name1);
  anArray.Add (name2);
  anArray.Detach (name2);

  TSArray <string> aSortedArray (10);   //Sorted Array class
  aSortedArray.Add (name1);
  aSortedArray.Add (name2);
  aSortedArray.Detach (name2);

  TStack <string> aStack;               //Stack class
  aStack.Push (name1);
  aStack.Push (name2);
  aStack.Pop ();

  TBag <string> aBag;                   //Bag class
  aBag.Add (name1);
  aBag.Add (name2);
  aBag.Detach (name2);

  return 0;
}
   
The following header file shows the use of the TListImp class to
implement a 1 to many aggregation between the car class and the
motor class.  In this example the car has many motors.

#ifndef __CAR_H
#define __CAR_H

#ifndef __MOTOR_H
#include "Motor.h"
#endif

#ifndef __LISTIMP.H                     //added
#include <classlib\listimp.h>           //added
#endif                                  //added

class  Car
{
     TListImp <Motor> motors;      //updated - implements 1 
     int speed;                    //to many relationship

public:

     void start();
     Car()
     { 
          speed = 0;
     }
     Car(int  aSpeed) 
     {
          speed = aSpeed;
     }

     ~Car(){}
     Car(const Car& aCar)
     {
     // Copy Constructor
          speed = aCar.speed;
     }
     Car operator= (const Car& aCar)
     {
     //Assignment Operator
     if (this == &aCar) return *this;
          speed = aCar.speed;
          return *this;
     }
     int operator==(const Car& aCar)
     {
     //Equality Operator
          return (
          (speed == aCar.speed) );
     }
     int  getSpeed() const {return speed; }
     void setSpeed(int  aSpeed) {speed =  aSpeed; }

};
#endif
 
    Generating ANSI C++ for Visual C++ with QuickWin (No MFC)

The easiest way to use With Class and Visual C++ is to create a
QuickWin project.   This will permit the use of the C++ iosteam
objects, e.g. cin and cout.  You must generate ANSI C++.  In the
With Class dialog box, select the following:
- select "#ifdef",
- select "Get and Set Methods",
- select "Copy Constructor and Assignment Operator",
- select "ostream << to Display Classes",
- select "C Array" for 1 to many relationships.
- do not select  "C++ Collection Templates" - uses a class
library,
- do not select "Make All Classes Streamable"  - OWL 1.0 only

For 1 to many relationships, select "C Array".   Then, if
desired, update the code manually for MFC 2.0 collection classes.  
The following are the steps to generate ANSI code using With
Class.

>> Run With Class from Windows
>> Select "File - Open", e.g., c:\car\car.omt
>> Select "Generate - Options" and select C++ code generation
options. Do not select "Make All Classes Streamable" or "C++
Collection Templates"
>> Select "C Array" for 1 to many relationships
>> Select "Generate - Generate Code"
>> Select "File - Edit File" and select a ".h" or ".cpp" file for
review

Once the code is generated, then the user may go to Visual C++ to
compile, link, and execute the code.   To use the Visual C++
environment, select defaults and then update the Linker Library
options with COMMDLG and SHELL.  Select "Linker" and then
"Miscellaneous" and enter /NOE.

The steps to compile, link, and execute the C++ in Visual C++
are:

>> Run Visual C++ from Windows
>> Select "Project - New" to create an new project"
>> Enter a project file name, e.g., carproj and select "QuickWin
Application (.EXE) and select "Use Microsoft Foundation Classes"
>> Enter a main file, e.g. main.cpp
>> Select "Add" or "Add All" to add your .cpp files to the
project
>> Select "Project - Options"
>> Select "Linker" and then "Windows Libraries".  Select COMMDLG
and SHELL
>> Select "Linker" and then "Miscellaneous" and enter /NOE
>> Select "File - Open" to open a .cpp file e.g. main.cpp
>> Select "Project - Compile File" to compile the C++ source code
>> Select "Project - Build" to build the project
>> Select "Project - Execute" to execute the project

The following ANSI C++ was generated by With Class for a car
class.   In this example a car has many motors.

////////////////////////Header File///////////////////////////////

#ifndef __CAR_H
#define __CAR_H

#ifndef __MOTOR_H
#include "Motor.h"
#endif

#ifndef __IOSTREAM_H
#include <iostream.h>
#endif

class  Car
{
  Motor motors[100];  //Array to implement 1 to many relationship
  int gasQty;

public:
     void start();
     Car()
     {
          gasQty = 0;
     }
     Car(int  aGasQty) 
     {
          gasQty = aGasQty;
     }
     ~Car(){}
     Car(const Car& aCar)
     {
     // Copy Constructor
          gasQty = aCar.gasQty;
     }
     Car operator= (const Car& aCar)
     {
     //Assignment Operator
     if (this == &aCar) return *this;
          gasQty = aCar.gasQty;
          return *this;
     }
     int operator==(const Car& aCar)
     {
     //Equality Operator
          return (
          (gasQty == aCar.gasQty) );
     }
     int  getGasQty() const {return gasQty; }
     void setGasQty(int  aGasQty) {gasQty =  aGasQty; }
friend ostream& operator<< (ostream& os, Car& aCar);
friend istream& operator>> (istream& is, Car& aCar);

};

#endif
////////////////////Source Code File/////////////////////////

#include "Car.h"

ostream& operator<< (ostream& os, Car& aCar)
     {
          os  << "Class Car" << "\n\n";
          os  << "  gasQty: " <<  aCar.gasQty << '\n';
          return os;
     }
istream& operator>> (istream& is, Car& aCar)
     {
          cout  << "Class Car" << "\n\n";
          cout  << "\nEnter   gasQty: " <<  "\n\n";
          is  >>  aCar.gasQty;
          return is;
     }
void      Car::start()
{

};
    Generating C++ for Visual C++ with MFC 2.0 with AppWizard

With Class generates compilable C++ for MFC 2.0.   For 1 to many
relationships, With Class generates lists and arrays with the MFC
classes CObList and CObArray.   The following is a code listings
showing MFC 2.0 collection classes and their #include file.

#include <iostream.h>                   //For cout
#include <afx.h>                        //For CString
#include <afxcoll.h>                    //For collection classes

class Person : public CObject           //Class to create
collection elements
{ };

int main ()
{
  cout << "The person's name is ";
  CString name ("Dick");
  cout << name;                         //CString object
  
  CStringList aStringList;              //String List
  aStringList.AddHead (name);
  aStringList.RemoveTail ();
  
  Person person1;
  
  CObList personList;           //Add to Head and Remove from Tail
  personList.AddHead (&person1);
  personList.RemoveTail ();
  
  CObList personStack;          //Add and Remove from Head
  personStack.AddHead (&person1);
  personStack.RemoveHead ();
  
  CObList personQueue;          //Add to Tail and Remove from Head
  personQueue.AddTail (&person1);
  personQueue.RemoveHead (); 
  
  CObArray personArray;         //Add and Remove an indexed element
  personArray.InsertAt (0, &person1);
  personArray.RemoveAt (0);
  
  return 1;
}

To generate C++ using With Class, the following are guidelines to
select options in the C++ code generation dialog box:
- select "#ifdef",
- select "Get and Set Methods",
- select "C++ Collection Template" for Array or List
- select "Visual C++"
- ensure #include "stdafx.h" is the first include file in each
.cpp file.
- do not select "Copy Constructor and Assignment Operator" to
avoid conflicts with CObject class,
- do not select "Make All Classes Streamable" - this is for OWL
1.0 only
- do not select "ostream << to Display Classes - this uses
iosteam.h

The following are the steps in Visual C++ to compile, link, and
execute a program.
>> Select "Project - AppWizard" to create a new project
>> Select "Project - Edit" to add .cpp files to the project
>> Select "File - Open" to open the doc file, e.g. "xxxdoc.h"
>> Update the "xxxdoc.h" file to include a new .h file
>> Select "Project - Compile File" to compile the document file,
e.g. "xxxdoc.cpp"
>> Select "Project - Build"
>> Select "Project - Execute"

After you use the AppWizard, update the "xxxdoc.h" file to
include at least one of your new classes and declare at least one
object.   The following code fragment was added to the xxxdoc.h
class to include the Car class:

#ifndef __CAR_H               //added
#include "Car.h"              //added
#endif                        //added

Car car1;                //added as a data member

The following header and source code files show the use of the
CObList class to implement a 1 to many aggregation between the
car class and the motor class.  In this example the car has many
motors.  

///////////////////////////Header File//////////////////////////

#ifndef __CAR_H
#define __CAR_H

#ifndef __MOTOR_H
#include "Motor.h"
#endif

#ifndef __AFXCOLL_H
#include <afxcoll.h>
#endif

class  Car
{
     CObList motors;  //implements 1 to many - Ensure class Motor
     int gasQty;              //is a derived class of CObject

public:

     void start();
     Car()
     {
          gasQty = 0;
     }
     Car(int  aGasQty) 
     {
          gasQty = aGasQty;
     }
     ~Car(){}
     int  getGasQty() const {return gasQty; }
     void setGasQty(int  aGasQty) {gasQty =  aGasQty; }
};

#endif

//////////////////////Source Code File///////////////////
#include "stdafx.h"           //Important - Must be first
#include "Car.h"

void      Car::start()
{

};

The following header file is the Motor class.  Note that Motor is
a derived class of CObject.   This is required so that motor
objects can be stored in the object of the CObjList to implement
the 1 to many relationship.

//////////////////////////////////Header File/////////////////////

#ifndef __MOTOR_H
#define __MOTOR_H

class  Motor : public CObject       //Derived class of CObject
{
     int rpm;
public:
     void operate();
     Motor()
     {
          rpm = 0;
     }
     Motor(int  aRpm) 
     {
          rpm = aRpm;
     }
     ~Motor(){}
     int  getRpm() const {return rpm; }
     void setRpm(int  aRpm) {rpm =  aRpm; }
};
#endif

                             Summary

The purpose of article was to present the "how to" steps to
generate C++ code using the With Class CASE (computer aided
software engineering) tool.    It presented guidelines for
updating generated ANSI C++ to use Borland OWL 2.0 and Microsoft
MFC 2.0 class libraries for collections.    Comments and
suggestions on this article are solicited.  Richard Felsinger
CompuServe 71162,755 or telephone 803-881-3648.


About RCF Associates - RCF Associates is a small software
consulting company in Mt Pleasant, SC that specializes in
training and developing object-oriented systems using
object-oriented methodologies (Rumbaugh OMT, Coad-Yourdon, Booch,
Fusion), CASE tools, object-oriented languages (C++, Ada,
Eiffel), and Microsoft Windows applications (Access, Visio, Office).    


