C++ Language News - Volume 1 Number 7

 








  PRODUCT  :  Borland C++                           NUMBER  :  8506

  VERSION  :  All

       OS  :  All

     DATE  :  June 7, 1993                            PAGE  :  1/12


    TITLE  :  C++ Language News - Volume 1 Number 7





               _Borland Language Support News_

  ----------------------------------------------------------------

  volume 1, number 7                     June 7, 1993

  ----------------------------------------------------------------


  USING QUICKSORT WITH C & C++


      Quicksort has become accepted to be one of the most robust

      and fastest sorting algorithms known at this time.  Because

      of the prevalence of implementation and usage, it has become

      part of the standard ANSI C runtime library.  As such, it

      can be simply used in an application such as --


       #include <stdio.h>

       #include <stdlib.h>

       #define MAX        3

       struct foo { double v; };

       int ascend(const void*, const void*);

       void print(struct foo*);

       main()

       {

           struct foo a[MAX];

           a[0].v = 0.0;

           a[1].v = -0.02;

           a[2].v = 0.01;

           print(a);

           qsort((void*) a, MAX, sizeof(a[0]), ascend);

           print(a);

           return 0;

       }

       int ascend(const void *p, const void *q)

       {

           double v = ((struct foo*)p)->v -

                   ((struct foo*)q)->v;

           if (v < 0.0)

              return -1;

           else if (v > 0.0)

              return 1;

           else

              return 0;

       }

       void print(struct foo *a)

       {














  PRODUCT  :  Borland C++                           NUMBER  :  8506

  VERSION  :  All

       OS  :  All

     DATE  :  June 7, 1993                            PAGE  :  2/12


    TITLE  :  C++ Language News - Volume 1 Number 7





           int i;

           printf("[");

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

              printf(" %6.2lf", a[i].v);

           printf("   ]\n");

       }


      The question is often asked how can qsort() be used in C++.

      Since classes and structures within C++ are closely related,

      the use of qsort() with classes is similar to the above C

      application.  Note that ordinary member functions cannot be

      used as the sorting function specified as the last argument

      to qsort();  this is due to member functions implicitly

      passing the 'this' pointer on the stack which is not expected

      by qsort().  This limits the comparison function passed to

      qsort() to regular functions or static member functions.


      Quicksort can also be used in situations where multiple in-

      heritance exists.  The following example demonstrates one

      method of how this can be done --


       #include <iostream.h>

       #include <stdlib.h>

       #include <string.h>

       class fruit {

       public:

           virtual char* name() const  { return "fruit"; }

       };

       class apple : public fruit {

       public:

           char* name() const  { return "apple"; }

       };

       class banana : public fruit {

       public:

           char* name() const  { return "banana"; }

       };

       class orange : public fruit {

       public:

           char* name() const  { return "orange"; }

       };

       void print(const fruit *p[], const int n) {

           cout << "(";

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














  PRODUCT  :  Borland C++                           NUMBER  :  8506

  VERSION  :  All

       OS  :  All

     DATE  :  June 7, 1993                            PAGE  :  3/12


    TITLE  :  C++ Language News - Volume 1 Number 7





               cout << " " << p[i]->name();

           cout << " )" << endl;

       }

       int compare(const void *p, const void *q) {

           return strcmp((*(fruit**)p)->name(),

                   (*(fruit**)q)->name());

       }

       main() {

           const int max = 3;

           fruit *p[max];

           apple a;      banana b;      orange o;

           p[0] = &b;     p[1] = &o;    p[2] = &a;

           print(p, max);

           qsort((void*)p, max, sizeof(fruit*), compare);

           print(p, max);

           return 0;

       }


      Quicksort can thus be used in C++ programs as long as some

      method can be determined of how to compare dissimilar ob-

      jects which can be derived from a common ancestor.



  HOT ISSUES


      Turbo C++ 3.0 incorrectly deals with the increment operator,

      ++, and huge pointers.  The following code illustrates the

      problem and gives the simple workaround.


       #include <iostream.h>

       main() {

           const long max = 95000L;

              static long huge a[max];

              cout << "assigning elements..." << endl;

              for (long i = 0; i < max; ++i)

                  a[i] = i;

              cout << "verifying all array elements..." << endl;

              long huge *p = a;

              for (i = 0; i < max; ++i) {

                  if (*p != i)

                      cerr << "error in a[" << i << "]" << endl;

          //      ++p;                   // errant line of code

                  p = p + 1;             // workaround














  PRODUCT  :  Borland C++                           NUMBER  :  8506

  VERSION  :  All

       OS  :  All

     DATE  :  June 7, 1993                            PAGE  :  4/12


    TITLE  :  C++ Language News - Volume 1 Number 7





              }

              cout << "done" << endl;

              return 0;

          }


      The line that is commented out demonstrates the problem.  If

      this line is uncommented, and the following line is comment-

      ed out, then incorrect program execution will be seen after

      compilation and linking.  If the code is compiled and linked

      as seen above, execution will proceed as expected.



  DOS


  1.  Values such as '-a' and '-b' passed to a program via com-

      mand-line arguments are seen by the compiler as literal

      values (in this case, 0x612d and 0x622d respectively).  By

      casting *argv as a pointer to an integer, determining the

      value of a command-line switch can be done faster in fewer

      lines of code.  eg.


          #include <iostream.h>

          main(int argc, char **argv) {

              while (--argc && **argv++) {

                  cout << "command-line switch = ";

                  switch (*(int*) *argv) {

                      case '-a':  case '-A':

                      case '/a':  case '/A':

                          cout << "-a, -A, /a, or /A" << endl;

                      break;

                  case '-b':  case '-B':

                  case '/b':  case '/B':

                      cout << "-b, -B, /b, or /B" << endl;

                      break;

                  default:

                      cout << *argv << "(unknown)" << endl;

                      break;

                  }

              }

              return 0;

          }
















  PRODUCT  :  Borland C++                           NUMBER  :  8506

  VERSION  :  All

       OS  :  All

     DATE  :  June 7, 1993                            PAGE  :  5/12


    TITLE  :  C++ Language News - Volume 1 Number 7





  OS/2


  1.  The following function will track the splitbar in detail

      view (object information) using the keyboard.  This func-

      tion could be called as a result of a menu item selected

      by the user.


       VOID TrackSplitbar (HWND hwndCnr) {

           TRACKINFO  ti;

           RECTL      rclDV, rclCnr, rclCnrTitle;

           CNRINFO    CnrInfo;


       /* Query the CnrInfo structure from the container.  From

          it, get the current position of the splitbar. */


           WinSendMsg(hwndCnr, CM_QUERYCNRINFO,

                   MPFROMP(&CnrInfo),

                   MPFROMSHORT(sizeof(CNRINFO)));


       /* Get the window rectangles for the container title

          window, the left details view window, and the con-

          tainer window itself. */


          WinQueryWindowRect(WinWindowFromID(hwndCnr,

                       CID_CNRTITLEWND), &rclCnrTitle);

          WinQueryWindowRect(WinWindowFromID(hwndCnr,

                       CID_LEFTDVWND), &rclDV);

          WinQueryWindowRect(hwndCnr, &rclCnr);


       /* Initialize the TrackInfo structure.  The splitbar has

          the width of a SizeBorder, and has the height of the

          container window minus the container title window. */


          ti.cxBorder = (SHORT) WinQuerySysValue(HWND_DESKTOP,

                       SV_CXSIZEBORDER);

          ti.cyBorder = (SHORT) (rclCnr.yTop -

                        rclCnrTitle.yTop);

          ti.cxGrid   = (SHORT) rclCnr.xRight;

          ti.cyGrid   = (SHORT) rclCnr.yTop;


       /* Set the x Keyboard increment to be the number of pels

          you want the splitbar to move when the user presses

          the right and left arrow keys.  Set the y Keyboard














  PRODUCT  :  Borland C++                           NUMBER  :  8506

  VERSION  :  All

       OS  :  All

     DATE  :  June 7, 1993                            PAGE  :  6/12


    TITLE  :  C++ Language News - Volume 1 Number 7





          increment to 0. */


          ti.cxKeyboard = 10;

          ti.cyKeyboard = 0;


       /* Set up the rectangle that is to be tracked.  This is

          the rectangle of the splitbar. */


          ti.rclTrack.xLeft = CnrInfo.xVertSplitbar;

          ti.rclTrack.xRight = ti.rclTrack.xLeft + ti.cxBorder;

          ti.rclTrack.yBottom = rclCnr.yBottom;

          ti.rclTrack.yTop = ti.cyBorder;


       /* Set up the absolute boundary rectangle.  This is the

          rectangle specifying the boundary which the tracking

          rectangle cannot exceed.  Set it to be the left,

          right, and bottom of the container, and the top of

          the splitbar. */


          ti.rclBoundary.xLeft   = rclCnr.xLeft;

          ti.rclBoundary.xRight  = rclCnr.xRight;

          ti.rclBoundary.yBottom = rclCnr.yBottom;

          ti.rclBoundary.yTop    = ti.cyBorder;

          ti.ptlMinTrackSize.x   = ti.cxBorder;

          ti.ptlMinTrackSize.y   = ti.cyBorder;

          ti.ptlMaxTrackSize.x   = ti.cxBorder;

          ti.ptlMaxTrackSize.y   = ti.cyBorder;


       /* Set the track flags.  TF_SETPOINTERPOS will put the

          mouse pointer in the middle of the tracking rectangle

          (splitbar). */


          ti.fs = TF_MOVE | TF_ALLINBOUNDARY |

               TF_SETPOINTERPOS;


       /* If the tracking is successful, inform the container

          of the new splitbar position. */


          if (WinTrackRect(hwndCnr, NULL, &ti)) {

          /* Inform the container of the new splitbar

             position. */


             CnrInfo.xVertSplitbar = ti.rclTrack.xLeft;














  PRODUCT  :  Borland C++                           NUMBER  :  8506

  VERSION  :  All

       OS  :  All

     DATE  :  June 7, 1993                            PAGE  :  7/12


    TITLE  :  C++ Language News - Volume 1 Number 7





             WinSendMsg(hwndCnr, CM_SETCNRINFO,

                  &CnrInfo,

                  MPFROMLONG(CMA_XVERTSPLITBAR));

          }

          return;

       }



  WINDOWS


  1.  How do I associate an icon with a TWindow in OWL?


      Within your application, derive from TWindow, override the

      member function GetClassName() to return a unique name, and

      override the member function GetWindowClass() to load a

      handle to your icon.  eg.


       class TMyWindow : public TWindow {

           // ...

           virtual void GetWindowClass(WNDCLASS&);

           virtual LPSTR GetClassName();

       };


       void TMyWindow::GetWindowClass(WNDCLASS &w) {

           TWindow::GetWindowClass(w);

           w.hIcon = LoadIcon(GetApplication()->hInstance,

                        MAKEINTRESOURCE(ICON_MYICON));

       }


       LPSTR TMyWindow::GetClassName() {

           return ("MY_WINDOW");

       }



  TURBO VISION


  1.  When I compile my old Turbo Vision code that uses TFileList

      with Borland C++ 3.1, it produces errors on the constructor

      calls.  When I check the STDDLG.H header file, I see that

      the constructor parameters have been changed.  Why is this,

      and how do I fix it?


      The version of Turbo Vision shipping with Borland C++ 3.1














  PRODUCT  :  Borland C++                           NUMBER  :  8506

  VERSION  :  All

       OS  :  All

     DATE  :  June 7, 1993                            PAGE  :  8/12


    TITLE  :  C++ Language News - Volume 1 Number 7





      has a modified TFileList object.  The constructor no longer

      accepts the aWildCard parameter in the new object.  This is

      because of a design change allowing a TFileList object to be

      created without actually reading a directory.  At the point

      where you know which directory needs to be read, you can

      call readDirectory() with the appropriate wildcard mask.

      eg.


      old version:

       // note the wildcard mask in double quotes

       TFileList *p = new TFileList(TRect(0, 0, 20, 10),

                           "*.*", 0);


      new version:

       TFileList *p = new TFileList(TRect(0, 0, 20, 10), 0);

       p->readDirectory("*.*");


      The above two segments of code are equivalent.  Alterna-

      tively, readDirectory() doesn't have to be called immed-

      iately.  It could be called after some user input from

      another event.


      This design change allows a delay to be made between when a

      TFileList is instantiated as compared to when the direct-

      ory read is performed.



  PARADOX ENGINE


  1.  I am getting an "Error 118:  Table is busy" error message.

      Why?


      This error happens when the application tries to lock a

      table when the corresponding prevent lock already exists,

      or when the application tries to set a prevent lock and a

      conflicting lock already exists.  Check for old, unused

      lock files.  Delete any *.LCK files that may exist after

      all Paradox Engine applications have terminated.  Also,

      run the TUTILITY program to test for table validity.  See

      page 31 of the _Paradox User's Guide_ for more information

      on locks.


  2.  I am getting an "Error 120:  Table is not found" error














  PRODUCT  :  Borland C++                           NUMBER  :  8506

  VERSION  :  All

       OS  :  All

     DATE  :  June 7, 1993                            PAGE  :  9/12


    TITLE  :  C++ Language News - Volume 1 Number 7





      message.  Why?


      Besides not being able to find the table, this error can

      also occur when the sort order that the Engine uses is

      different from the sort order of the table.  A common

      cause of this error is using the international sort order

      with Paradox, and using the Engine's default ASCII sort

      order.  The sort order can be changed by using the function

      PXSetDefaults().



  PASCAL


  1.  When Pascal programmers are using BASM, they are often

      baffled when it comes time to address a field of an ob-

      ject.  The issue is that the field is usually located at

      an offset from the segment of the pointer to that object,

      not from the data segment of the program.  As a result, a

      viable way to address a field of the object is to first

      load its object's segment and offset into ES:DI.  You can

      use the following line of code to do this:


       les di, Self


      Once you are properly addressing the object itself, then

      all you need do is calculate the offset of the field from

      the beginning of the object.  This can be done by adding the

      proper number of bytes to ES:DI.  For instance, if an object

      has three fields, all two bytes in size, then the offset of

      the third field would be four:


       mov ax, word [es:di + 4]


      If these kinds of calculations bother you, you can avoid

      them by loading the segment and offset of the object di-

      rectly into the data segement, but you should be sure to

      save its original value on the stack, with a push and a pop.

      A simple illustration of the above principlese would be an

      object with 3 fields, the last being an integer called M.

      This example simply moves the value of that field into the

      AX register:


          program AsmObj;














  PRODUCT  :  Borland C++                           NUMBER  :  8506

  VERSION  :  All

       OS  :  All

     DATE  :  June 7, 1993                           PAGE  :  10/12


    TITLE  :  C++ Language News - Volume 1 Number 7





          type

            PMyObject = ^TMyObject;

            TMyObject = Object

            i,j: Word;

            M: Integer;

            procedure Foo;

            procedure Foo1;

          end;


          procedure TMyObject.Foo;

          begin

            asm

              les di, Self

              mov ax, word [es:di + 4]

            end;

       end;


          procedure TMyObject.Foo1;

          begin

            asm

              push ds

              lds di, Self

              mov ax, word ptr [di + M]

              pop ds

            end;

          end;


          var

            O: PMyObject;


          begin

            New(O);

            O^.M := 10;

            O^.Foo;

            O^.Foo1;

            Dispose(O);

          end.



  QUIZ


      Last week's code illustrated the common 'gotcha' associated

      with virtual base classes.  In this case, the most derived














  PRODUCT  :  Borland C++                           NUMBER  :  8506

  VERSION  :  All

       OS  :  All

     DATE  :  June 7, 1993                           PAGE  :  11/12


    TITLE  :  C++ Language News - Volume 1 Number 7





      class in an inheritance tree will initialize the virtual

      base class as opposed to class 'left' or 'right'.  Because

      of this, the value '0' (the constructor's default value)

      will be used in the assignment of 'v' as opposed to the

      value '3'.


      This week's quiz centers about the following code:


       #include <iostream.h>

       #include <assert.h>

       class foo {

           int v;

       public:

           foo(int i = 1) {

               v = i;

               cout << "foo::foo(int);" << endl;

           }

           int f()  { assert(v == 1);  v = 1;  return v; }

           void display()  { cout << "v = " << v << endl; }

       };

       class bar : public foo {

       public:

           bar() : foo(f())  { }

       };

       main() {

           bar b;

           return 0;

       }


      Why is an assert error generated?  The answer will be pub-

      lished in next week's issue.



  NEW TECHNICAL INFORMATION DOCUMENTS AVAILABLE


      Some of the latest technical information documents available

      to customers include the following.


        1390       information on accessing Borland's Down-

                   load Bulletin Board System (DLBBS).

        1378       information on sources on SVGA BGI

                    drivers.

        1338       overview of Borland C++ for OS/2.














  PRODUCT  :  Borland C++                           NUMBER  :  8506

  VERSION  :  All

       OS  :  All

     DATE  :  June 7, 1993                           PAGE  :  12/12


    TITLE  :  C++ Language News - Volume 1 Number 7





         806       installation & configuration issues re-

                   lating to running either Borland or Turbo

                   C++ on a network.


      These documents can be found on either LIB-2 of BCPPDOS or

      BCPPWIN on CompuServe, Borland's DLBBS at (408)438-9096,

      TechFAX at (800)822-4269, or OAS at (408)431-5250.




  DISCLAIMER: You have the right to use this technical information

  subject to the terms of the No-Nonsense License Statement that

  you received with the Borland product to which this information

  pertains.


Comments

Popular posts from this blog

WHAT THE WATCH TOWER BIBLE AND TRACT SOCIETY OF PENNSYLVANIA HAD TO SAY ABOUT WHAT WERE SUPPOSED TO HAVE HAPPENED in 1874

Uninterruptable Power Source (UPS) FAQ

Blade Runner FAQ