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
Post a Comment