PRODUCT : Borland C++ NUMBER : 8511 VERSION : All OS : All DATE : October 25, 1993 PAGE : 1/10 TITLE : C++ Language News, Volume 1 Number 12 _Borland Language Support News_ ---------------------------------------------------------------- volume 1, number 12 August 17, 1993 ---------------------------------------------------------------- TWO-DIMENSIONAL ARRAY SUBSCRIPTING Any class can provide the appearance of a one-dimension- al array by directly overloading the [] operator, however, the question is frequently asked as to how can the same notational convenience be extended to two-dimensional ar- rays. Two concepts need to be considered in providing this func- tionality in class design. The first focuses on the row- major array storage inherent to both C and C++. Each row in an array is storage contiguously and consecutively. Given a single-dimensioned array a, a + i is the address of the ith element of the array. For a two-dimensional 3x4 (3 rows with 4 elements per row) array b, b + i * 4 + j is the address of element a[i][j]. Of importance is to realize that b + i * 4 is the beginning address of the ith row and adding j to this pointer expression indexes to the jth element of the ith row. This same arithmetic can be extended to class design. Given a class foo, operator [] would return the address of the desired row. If this row address is then following by another operator [], then the desired element would then be obtained. The code below im- plements this concept. The second consideration is how can this overloading of [][] be used on both sides of an assignment statement. For exam- ple, given a two-dimensional integer array a, elements with- in this array can be manipulated as -- int i = a[0][1]; a[0][1] = 2; Given that C++ references can be treated as both lvalues and rvalues, the class design of overloading [][] can be a- chieved by ultimately returning a reference to the element desired. This can also be seen in the implementation below. PRODUCT : Borland C++ NUMBER : 8511 VERSION : All OS : All DATE : October 25, 1993 PAGE : 2/10 TITLE : C++ Language News, Volume 1 Number 12 #include const int n = 3; // #rows in matrix const int m = 4; // #columns in matrix const int v = 0; // initialization value class foo { class column { int *a; public: column(int *p) : a(p) { } int& operator[](const int j) { return a[j]; } }; int a[n][m]; public: foo(); foo::column operator[](const int i) { return (int*) a + i * m; } foo::column operator[](const int i) const { return (int*) a + i * m; } }; foo::foo() { for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) a[i][j] = v; } ostream& operator<<(ostream &out, const foo &f) { for (int i = 0; i < n; ++i) { const int w = 5; out << "|"; for (int j = 0; j < m; ++j) { out.width(w); out << f[i][j]; } out.width(w); out << "|" << endl; } return out; } main() { foo f; f[2][2] = 2; // operator [][] as an lvalue cout << f << endl; PRODUCT : Borland C++ NUMBER : 8511 VERSION : All OS : All DATE : October 25, 1993 PAGE : 3/10 TITLE : C++ Language News, Volume 1 Number 12 int i = f[2][2]; // operator [][] as an rvalue cout << "f[2][2] = " << i << endl; return 0; } HOT ISSUES I get a UAE when I start my ObjectWindows application. I am linking to the static libraries, and the application blows up in the application's constructor. What is happen- ing? The application has been built with far virtual tables on. The static OWL libary is hard coded to work with near tables. Perform a Build All without far vtables enabled. DOS 1. How do I return a function pointer from a function? #include #include typedef int (*FP)(char); FP get_fp(); int f(char); int g(char); main() { int (*fp)(char); fp = get_fp(); int i = fp('A'); cout << "return value = " << i << endl; return 0; } FP get_fp() { int (*fp)(char); char c; cin >> c; switch (c) { case 'f': fp = f; break; PRODUCT : Borland C++ NUMBER : 8511 VERSION : All OS : All DATE : October 25, 1993 PAGE : 4/10 TITLE : C++ Language News, Volume 1 Number 12 case 'g': fp = g; break; default: cerr << "unhandled character " << c << endl; exit(1); } return fp; } int f(char c) { cout << "f(): c = " << c << endl; return 0; } int g(char c) { cout << "g(): c = " << c << endl; return 0; } OS/2 1. In OS/2 2.0, dynamic link libraries are supported to allow the programmer to have the flexibility to load and unload code and data as it is needed by an executing application. The DLL file also allows separate executables to share the same code. This is also how the OS/2 2.0 operating system functions. In and of itself, it is a large collection of DLL's. To statically link with a DLL file, a. Create the DLL with Borland C++ for OS/2; the TLINK.EXE option /Tod must be specified. b. Create an import library to be used by the executable that uses the DLL file. Run IMPLIB.EXE on the DLL file to create and import .LIB files. c. Use the import library created in the above step when linking the executable that uses the DLL. The import library can be linked to the same as any other library file. d. Functions that reside in the DLL will need to be proto- typed with the _EXPFUNC function modifier to notify the compiler that these functinos will be exported from the PRODUCT : Borland C++ NUMBER : 8511 VERSION : All OS : All DATE : October 25, 1993 PAGE : 5/10 TITLE : C++ Language News, Volume 1 Number 12 DLL to be accessible from other modules. WINDOWS 1. How do I use ForEach() to iterate through my child windows. I can't seem to get the example on page 319 of the Object- Windows manual to work. The example is incorrect. To use the ForEach() iterator in an OWL application, the call must be made from within a class method such as SetupWindow. Also the statement: (PTCheckBox)P->Check(); will not function correctly as the compiler will try to resolve the -> first before the cast- ing to PTCheckBox. The correct exampe should read as follows: void CheckTheBox(Pvoid P, Pvoid) { ((PTBCheckBox)P)->Check(); } void TMyDialog::SetupWindow() { TDialog::SetupWindow(); ForEach(CheckTheBox, NULL); } TURBO VISION 1. I'm using getData() and setData() in a dialog box that has a TListBox in it and my program crashes. If I comment out the getData() or setData() call, then are no problems. Why? The TListBoxRec can be found in the source code file TLISTBOX.CPP. It was erroneously placed in a .CPP file as opposed to a header file. This is the structure that needs to be placed inside the programmer's structure for the dia- log box's data. Doing this should make things work proper- ly. If it doesn't, then probably is another unrelated prob- lem. As an example, the following structure for two TInputLines, PRODUCT : Borland C++ NUMBER : 8511 VERSION : All OS : All DATE : October 25, 1993 PAGE : 6/10 TITLE : C++ Language News, Volume 1 Number 12 one TCheckBox and one TRadioButton must be modified to ac- commodate a ListBox if one is present in the dialog: struct dataRec { struct dataRec { char name[80]; char name[80]; char phone[80]; char phone[80]; unsigned chkbox; => unsigned chkbox; unsigned radiobtn; unsigned radiobtn; }; struct TListBoxRec { TCollection *items; ushort selection; }; }; PARADOX ENGINE 1. Some important numbers in association to the Paradox Engine 3.0: maximum table size (PXTblMaxSize) 256Mb maximum blob size 256Mb maximum number of blobs per table disk space maximum record size* non-indexed table 4000 bytes indexed table 1325 bytes maximum number of fields 255 maximum number of secondary indexes 255 maximum number of composite indexes 255 maximum userName size 14 characters PASCAL 1. Do you have an example which will show the format of float- ing point values? Program DoubConv; {$N+} { This program demonstrates the conversion of a 8 byte } { Turbo Pascal real variable type by re-creating the } { exponent and Mantissa. The temporary variable } PRODUCT : Borland C++ NUMBER : 8511 VERSION : All OS : All DATE : October 25, 1993 PAGE : 7/10 TITLE : C++ Language News, Volume 1 Number 12 { Mantissa accumulates the value stored in bytes 2 } { through 8. } type EightByteArray = array[1..8] of byte; UserReal = Extended; var r : double; s : EightByteArray absolute r; { Allow access to individual real type bytes } i,j : byte; PosFlag : boolean; Mantissa : UserReal; Exponent : integer; Number : UserReal; { the mantissa and number can be typed as to the number } { desired i.e. Real, Single, Extended, BCD } function power (x,y : integer) : UserReal; begin power := exp(y * ln(x)); end; begin write('Enter floating point Number '); readln(r); PosFlag := ($80 and s[8]) = 0; { Check if entry is positive from bit 7 of byte 8 } s[8] := s[8] and $7F; { Force bit 7 of byte 8 off } Mantissa := 0.0; { Initialize the Mantissa } for i := 1 to 6 do { Check each byte of mantissa } for j := 0 to 7 do { Check each bit } if ((s[i] shr j) and 1 ) = 1 then Mantissa := Mantissa + power(2, (j + (i-1) * 8)); { Increment mantissa appropriately } for j := 0 to 3 do { get mantissa info from byte 7 } if ((s[7] shr j) and 1) = 1 then Mantissa := Mantissa + power(2, (j + 48)); { Increment mantissa appropriately & add the assumed } { mantissa value at bit 52 } Mantissa := (Mantissa + power(2,52)) / power(2,52); { Normalize the number by dividing by 2^52 } PRODUCT : Borland C++ NUMBER : 8511 VERSION : All OS : All DATE : October 25, 1993 PAGE : 8/10 TITLE : C++ Language News, Volume 1 Number 12 Exponent := s[7] shr 4; Exponent := Exponent + s[8] * 16; if (Exponent > 0) and (Exponent < 2047) then begin Exponent := Exponent - 1023; Number := Mantissa * power(2, exponent); { Get number by multiply Mantissa by the exponent } end else if (Exponent = 0) then begin if mantissa <> 0 then Number := Mantissa * power(2, -1022); end else number := 0; if not PosFlag then Number := Number * -1; writeln(Number); readln; end. 2. Do you have an example which will convert numeric values to hexadecimal notation? Const HexDigits : String[16] = '0123456789ABCDEF'; Type Str4 = String[4]; Var W : Word; I : Integer; Result : Str4; Procedure HexWord( Var Hex : Str4; W : Word ); Begin Hex[1] := HexDigits[( W Div 4096 ) + 1]; W := W Mod 4096; Hex[2] := HexDigits[( W Div 256 ) + 1]; W := W Mod 256; Hex[3] := HexDigits[( W Div 16 ) + 1]; W := W Mod 16; Hex[4] := HexDigits[W + 1]; Hex[0] := #4; PRODUCT : Borland C++ NUMBER : 8511 VERSION : All OS : All DATE : October 25, 1993 PAGE : 9/10 TITLE : C++ Language News, Volume 1 Number 12 End; Begin For W := 0 to 65535 Do Begin HexWord( Result, W ); writeln( 'W = ', W, ' Hex = ', Result ); End; End. QUIZ Last week's question asked for code which would force a de- rived class's copy constructor to also call the base class's copy constructor. Here is one possible solution: #include class foo { int v; public: foo(const int i) { v = i; cout << "foo(const int)" << endl; } foo(const foo &f) { v = f.v; cout << "foo(const foo&)" << endl; } }; class bar : public foo { int u; public: bar(const int i) : foo(i + 1) { u = i; cout << "bar(const int)" << endl; } bar(const bar &b) : foo(b) { u = b.u; cout << "bar(const bar&)" << endl; } }; main() { PRODUCT : Borland C++ NUMBER : 8511 VERSION : All OS : All DATE : October 25, 1993 PAGE : 10/10 TITLE : C++ Language News, Volume 1 Number 12 bar b(0); bar c = b; return 0; } This week's quiz looks at access levels. Write a class which will allow the programmer to publically access a pri- vate member function. The solution will be given in the next issue of the newsletter. NEW TECHNICAL INFORMATION DOCUMENTS AVAILABLE Some of the latest technical information documents available to customers include the following. 1540 Copy semantics. 1539 Creating templates for customized dialog boxes. 1538 Example of a closest match search with the Paradox Engine. 1537 Resizing the overlay buffer at program startup. 1536 Calling 16-bit DLL's in Borland C++ for OS/2. 1535 Creating an IOPL segment in Borland C++ for OS/2 2.x. These documents can be found on either LIB-2 of BCPPDOS or BCPPWIN on CompuServe, Borland's DLBBS at (408)431-5096, 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.