$CPP directive

Purpose: $CPP directive attempts C++ compliance in the translated code. Translated code is output to a file named with a .cpp extension. This directive is equivalent to using the BCX command line -c flag.

Example:


 $CPP ' Turn on C++ features and use .cpp filename extension
 
 TestSub(1)
 TestSub(1, 2)
 TestSub(1, 2, 3)

 SUB TestSub OPTIONAL(a, b = 0, c = 0)
  PRINT
  IF a > 0 THEN PRINT a;
  IF b > 0 THEN PRINT b;
  IF c > 0 THEN PRINT c
  PRINT
 END SUB

Result:


 1

 1 2

 1 2 3

$CPPHDR directive

When the $CPPHDR directive is used, with the $CPP directive, the BCX translator automatically adds the following code to the .cpp file translation produced by BCX.


 // Additional lines may be needed
 #if defined(__cplusplus)
   #include <iostream>
   #include <fstream>
   #include <sstream>
   #include <iomanip>
   typedef std::string stdstr;
 #endif

To add other Standard C++ Library header files to the BCX code to be translated use the directive


 #include <Filename>

$NOIO directive

Purpose:The $NOIO directive disables the inclusion of the <iostream> C++ header file.

By default, when the $CPPHDR directive is used, the BCX translation includes the <iostream> C++ header file. You can disable the inclusion by adding the line $NOIO to your BCX program source code, placing it immediately after the $CPPHDR directive.

The C++ Tutorial for BCX Users

With the permission of the original author Eric Brasseur, the following is an abridged BCX version of Brasseur's "The C++ tutorial for C users".

Chapter 3. Console input and output streams

Input from the keyboard and output to the screen can be performed through std::cin >> and std::cout <<.

Example C03.bas:


 $CPP
 $NOMAIN
 
 #INCLUDE <iostream>
 
 FUNCTION MAIN()
 
   DIM age%
   DIM name$
          
   std::cout << "This is a sample program." << std::endl
          
   std::cout << std::endl   ' Just a line feed (end of line)
    
   std::cout << "Type your age : "
   std::cin >> age%
          
   std::cout << "Type your name: "
   std::cin >> name$
          
   std::cout << std::endl
          
   std::cout << "Hello " << name$ << " you're " << age% << " years old." << std::endl
   std::cout << std::endl << std::endl << "Bye!" << std::endl
 
 END FUNCTION

Result:


 This is a sample program.

 Type your age : 24
 Type your name: BCX

 Hello BCX you're 24 years old.

 Bye!

Chapter 7. Global variables

A global variable can be accessed even if another variable with the same name has been declared inside the function.

Example C07.bas:


 $CPP
 $NOMAIN

 #INCLUDE <iostream>
   
 DIM a# = 128
     
 FUNCTION MAIN ()
    
   DIM a# = 256
        
   std::cout << "Local a:  " << a#   << std::endl
   std::cout << "Global a: " << ::a# << std::endl
     
 END FUNCTION

Result:


 Local a:  256
 Global a: 128

Chapter 8. Reference

It is possible to make one variable be another.

Example C08_01.bas:


 $CPP
 $NOMAIN
 
 #INCLUDE <iostream>
 
 FUNCTION MAIN ()
  
   DIM a# = 3.1415927
       
   DIM AS DOUBLE &b = a      ' b is a#
    
   b = 89
       
   std::cout << "a# contains: " << a# << std::endl
 
 END FUNCTION

Result:


 a# contains: 89

If you are used to pointers and absolutely want to know what happens, simply think


 DOUBLE &b = a 

is translated to


 DOUBLE *b = &a 

and all subsequent b are replaced by *b.

The value of reference b cannot be changed after its declaration. For example you cannot write, a few lines further,


 &b = c 

expecting that b is now c. It won't work. Everything is said on the declaration line of b. Reference b and variable a are married on that line and nothing will separate them.

References can be used to allow a function to modify a calling variable

Example C08_02.bas:


 $CPP
 $NOMAIN
 
 #INCLUDE <iostream>
     
 SUB Change (r AS DOUBLE &, s AS DOUBLE)
   r = 100
   s = 200
 END SUB
 
 FUNCTION MAIN ()
 
   RAW AS DOUBLE k, m
      
   k = 3
   m = 4
      
   CALL Change(k, m)
      
   std::cout << k << ", " << m << std::endl
 
 END FUNCTION

Result:


 100, 4

A reference can be used to let a function return a variable.

Example C08_03.bas:


 $CPP
 $NOMAIN
 
 #INCLUDE <iostream>
     
 FUNCTION biggest (r AS DOUBLE &, s AS DOUBLE &) AS DOUBLE &
   IF r > s THEN FUNCTION = r
   FUNCTION = s
 END FUNCTION
 
 FUNCTION MAIN ()
  
   RAW AS DOUBLE k = 3
   RAW AS DOUBLE m = 7
      
   std::cout << "k: " << k << std::endl
   std::cout << "m: " << m << std::endl
   std::cout << std::endl
      
   biggest (k, m) = 10
      
   std::cout << "k: " << k << std::endl
   std::cout << "m: " << m << std::endl
   std::cout << std::endl
      
   biggest (k, m) ++
      
   std::cout << "k: " << k << std::endl
   std::cout << "m: " << m << std::endl
   std::cout << std::endl
 
 END FUNCTION

Result:


 k: 3
 m: 7

 k: 3
 m: 10

 k: 3
 m: 11

Chapter 9. Namespace

Namespaces can be declared. The variables declared within a namespace can be used thanks to the :: operator

Example C09a.bas:


 $CPP
 $NOMAIN
   
 #INCLUDE <iostream>
      
 NAMESPACE first
   RAW AS INT a
   RAW AS INT b
 END NAMESPACE
      
 NAMESPACE second
   RAW AS DOUBLE a
   RAW AS DOUBLE b
 END NAMESPACE
   
 FUNCTION MAIN()
          
   first::a = 2
   first::b = 5
          
   second::a = 6.453
   second::b = 4.1e4
          
   std::cout << first::a + second::a << std::endl
   std::cout << first::b + second::b << std::endl
   
 END FUNCTION

Result:


 8.453
 41005

Example C09b.bas: This example has a more BASIC-like feel to it


 $CPP

 NAMESPACE first
   DIM ABC AS STRING ' ABC is a string 
 END NAMESPACE
 
 NAMESPACE second
   DIM ABC AS DOUBLE ' ABC is a double precision number 
 END NAMESPACE
 
 
 SUB MAIN
 
   first::ABC$ = "Here comes PI:"
   PRINT first::ABC$           ' $ sigil is required 
 
   second::ABC = ATN(1) * 4
   PRINT second::ABC#          ' # sigil is required 
 
   PAUSE
 END SUB

Chapter 10. Inline

If a function contains just simple lines of code, doesn't use for loops or the like, it can be declared inline. This means its code will be inserted everywhere the function is used. That's somewhat like a macro. The main advantage is the program will be faster. A small drawback is it will be bigger, because the full code of the function was inserted everywhere it is used.

Example C10.bas:


 $CPP
 $NOMAIN
 
 #INCLUDE <iostream>
     
 inline FUNCTION hypothenuse (a AS DOUBLE, b AS DOUBLE) AS DOUBLE
   
 FUNCTION = SQRT(a * a + b * b)
 END FUNCTION
 
 FUNCTION MAIN ()
     
   RAW AS DOUBLE k = 6, m = 9
      
   ' Next two lines produce exactly the same result:
    
   std::cout << hypothenuse (k, m) << std::endl
   std::cout << SQRT(k * k + m * m) << std::endl
 
 END FUNCTION

Result:


 10.8167
 10.8167

Chapter 11. Exception

You know the classical control flow structures of C: FOR, IF, DO, WHILE ... C++ adds one more control structure named 'exception' consisting of members TRY, THROW, CATCH, and END TRY

Example C11.bas:


 $CPP
 $NOMAIN
 
 #INCLUDE <iostream>
 
 FUNCTION MAIN ()
    
   DIM AS INT a, b, c
    
   std::cout << "Type a number: "
   std::cin >> a
   std::cout << std::endl
        
 TRY
   IF a > 100 THEN THROW 100
   IF a < 10 THEN THROW 10
   c = a/3
   THROW  c
 CATCH (result AS INT)
   std::cout << "Result is: " << result << std::endl
   b = result + 1
 END TRY
        
 std::cout << "b contains: " << b << std::endl
        
 std::cout << std::endl
        
 ' another example of EXCEPTION use:
       
 RAW zero []    = "zero" AS CHAR
 RAW even []    = "even" AS CHAR
 RAW notprime [] = "not prime" AS CHAR
 RAW prime []   = "prime" AS CHAR
        
 TRY
   IF a = 0 THEN THROW zero
   IF (a / 2) * 2 = a THEN THROW even
   XFOR INT i = 3 WHILE i <= SQRT((float)a) BY i++
    std::cout << "Testing " << i << std::endl
    IF (a / i) * i = a THEN THROW notprime
   XNEXT
   THROW prime
 CATCH (conclusion AS CONST CHAR PTR)
   std::cout << "The number you typed is "<< conclusion << std::endl
 END TRY
        
 std::cout << std::endl
 
 END FUNCTION

Result:


 Type a number: 5

 Result is: 10
 b contains: 11

 The number you typed is prime

Chapter 12. Default Parameter Arguments

It is possible to define default parameters for functions.

Example C12.bas:


 $CPP
 $NOMAIN

 #INCLUDE <iostream>
   
 FUNCTION test (a AS DOUBLE, b = 7 AS DOUBLE) AS DOUBLE
   FUNCTION = a - b
 END FUNCTION
 
 FUNCTION MAIN ()
 
 std::cout << test (14, 5) << std::endl
 std::cout << test (14) << std::endl 

 END FUNCTION

Result:


 9
 7

Chapter 13. Function Overload

One important advantage of C++ is the function overload. Several functions can be declared with the same name provided there is a difference in their parameter list. Different functions can have the same name provided something allows the compiler to distinguish between them: number of parameters, type of parameters...

Example C13.bas:


 $CPP
 $NOMAIN

 #INCLUDE <iostream>
   
 FUNCTION test (a AS DOUBLE, b AS DOUBLE) AS DOUBLE
   FUNCTION = a + b
 END FUNCTION
   
 FUNCTION test (a AS INT, b AS INT) AS INT
   FUNCTION = a - b
 END FUNCTION

 FUNCTION MAIN ()
  
 RAW AS DOUBLE   m = 7,  n = 4
 RAW AS INT      k = 5,  p = 3
   
 std::cout << test(m, n) << " , " << test(k, p) << std::endl

 END FUNCTION

Result:


 11 , 2

Chapter 14. Operator Overload

Operator overloading can be used to redefine the basic symbolic operators for new kinds of parameters. The symbolic operators (+ - * / ...) can be defined for new data types.

Example C14.bas:


 $CPP
 $NOMAIN

 #INCLUDE <iostream>
   
 TYPE bcx_vector
   DIM AS DOUBLE x
   DIM AS DOUBLE y
 END TYPE
    
 FUNCTION operator*(a AS DOUBLE, b AS bcx_vector) AS bcx_vector
   DIM AS bcx_vector r
   
   r.x = a * b.x
   r.y = a * b.y
   
   FUNCTION = r
 END FUNCTION

 FUNCTION MAIN ()
  
 DIM AS bcx_vector k, m  ' No need to type "struct bcx_vector"
  
 k.x = 2               ' To be able to write
 k.y = -1               ' k = bcx_vector (2, -1)
  
 m = 3.1415927 * k       ' Magic!
  
 std::cout << "(" << m.x << ", " << m.y << ")" << std::endl

 END FUNCTION

Result:


 (6.28319, -3.14159)

Chapter 15. Template function

Tired of defining the same function five times? One definition for *int* type parameters, one definition for *double* type parameters, one definition for *float* type parameters... Didn't you forget one type? What if a new data type is used? No problem: the C++ compiler can automatically generate every version of the function that is necessary! Just tell it how the function looks like by declaring a *template* function

Example C15.bas:


 $CPP
 $NOMAIN
  
 #INCLUDE <iostream>
     
 TEMPLATE <class ttype>
 FUNCTION minimum (a AS ttype, b AS ttype) AS ttype
   RAW AS ttype r
     
   r = a
   IF b < a THEN r = b
     
   FUNCTION = r
 END FUNCTION
 END TEMPLATE
  
 FUNCTION MAIN ()
         
   RAW AS INT i1, i2, i3
   i1 = 34
   i2 = 6
   i3 = minimum (i1, i2)
   std::cout << "Most little: " << i3 << std::endl
     
   RAW AS DOUBLE d1, d2, d3
   d1 = 7.9
   d2 = 32.1
   d3 = minimum (d1, d2)
   std::cout << "Most little: " << d3 << std::endl
   std::cout << "Most little: " << minimum (d3, 3.5) << std::endl
  
 END FUNCTION

Result:


 Most little: 6
 Most little: 7.9
 Most little: 3.5

Chapter 16. NEW and DELETE

The keywords NEW and DELETE can be used to allocate and deallocate memory. They are cleaner than the functions malloc and free from standard C.

Example C16.bas:


 $CPP
 $NOMAIN

 #INCLUDE <iostream>

 FUNCTION MAIN ()
       
 RAW AS DOUBLE PTR d  ' d is a variable whose purpose
                      ' is to contain the address of a
                      ' zone where a double is located
      
 d = NEW DOUBLE       ' new allocates a zone of memory
                      ' large enough to contain a double
                      ' and returns its address.
                      ' That address is stored in d.
      
 *d = 45.3           ' The number 45.3 is stored
                      ' inside the memory zone
                      ' whose address is given by d.
      
 std::cout << "Type a number: "
 std::cin >> *d
       
 *d = *d + 5
       
 std::cout << "Result: " << *d << std::endl
       
 DELETE d             ' delete deallocates the
                      ' zone of memory whose address
                      ' is given by pointer d.
                      ' Now we can no more use that zone.
           
 d = NEW DOUBLE[15] ' allocates a zone for an array
                      ' of 15 doubles. Note each 15
                      ' double will be constructed.
                      ' This is pointless here but it
                      ' is vital when using a data type
                      ' that needs its constructor be
                      ' used for each instance.
      
 d[0] = 4456
 d[1] = d[0] + 567
       
 std::cout << "Content of d[1]: " << d[1] << std::endl
       
 DELETE [] d          ' delete [] will deallocate the
                      ' memory zone. Note each 15
                      ' double will be destructed.
                      ' This is pointless here but it
                      ' is vital when using a data type
                      ' that needs its destructor be
                      ' used for each instance (the ~
                      ' method). Using delete without
                      ' the [] would deallocate the
                      ' memory zone without destructing
                      ' each of the 15 instances. That
                      ' would cause memory leakage.
      
 RAW AS INT n = 30
       
 d = NEW DOUBLE[n]   ' new can be used to allocate an
                      ' array of random size.
 XFOR INT i = 0 WHILE i < n BY i++
   d[i] = i
 XNEXT
       
 DELETE [] d
       
 DIM AS CHAR PTR s
       
 s = NEW CHAR[100]
       
 s$ = "Hello!"
       
 std::cout << s << std::endl
       
 DELETE [] s

 END FUNCTION

Result:


 Type a number: 6
 Result: 11
 Content of d[1]: 5023
 Hello!

Chapter 17. METHODS

In standard C a struct contains only data. In C++ a struct definition can also include functions. Those functions are owned by the struct and are meant to operate on the data of the struct. Those functions are called METHODS. The example below defines the method surface() on the struct vector.

Example C17.bas:


 $CPP
 $NOMAIN

 #INCLUDE <iostream>
   
 PPTYPE bcx_vector
   RAW AS DOUBLE x
   RAW AS DOUBLE y
   
   FUNCTION surface () AS DOUBLE
     RAW AS DOUBLE s
     s = x * y
     IF s < 0 THEN s = -s
     FUNCTION = s
   END FUNCTION
 END PPTYPE

 FUNCTION MAIN ()
  
 RAW AS bcx_vector a
       
 a.x = 3
 a.y = 4
       
 std::cout << "The surface of a: " << a.surface() << std::endl

 END FUNCTION

Result:


 The surface of a: 12

Chapter 18. CONSTRUCTOR and DESTRUCTOR

Very special and essential methods are the CONSTRUCTOR and DESTRUCTOR. They are automatically called whenever an instance of a CLASS is created or destroyed (variable declaration, end of program, *new*, *delete*...).

The CONSTRUCTOR will initialize the variables of the instance, do some calculations, allocate some memory for the instance, output some text... whatever is needed.

Here is an example of a class definition with two overloaded constructors

Example C18.bas:


 $CPP
 $NOMAIN

 #INCLUDE <iostream>
  
 CLASS bcx_vector
   PUBLIC:
   RAW AS DOUBLE x
   RAW AS DOUBLE y
    
   CONSTRUCTOR bcx_vector () ' same name as class
    x = 0
     y = 0
   END CONSTRUCTOR
    
   CONSTRUCTOR bcx_vector (a AS DOUBLE, b AS DOUBLE)
     x = a
     y = b
   END CONSTRUCTOR
 END CLASS

 FUNCTION MAIN ()
  
 RAW AS bcx_vector k         ' bcx_vector () is called
   
 std::cout << "bcx_vector k: " << k.x << ", " << k.y << std::endl << std::endl
    
 RAW AS bcx_vector m (45, 2) ' bcx_vector (double, double) is called
   
 std::cout << "bcx_vector m: " << m.x << ", " << m.y << std::endl << std::endl
    
 k = bcx_vector (23, 2)     ' bcx_vector created, copied to k, then erased
   
 std::cout << "bcx_vector k: " << k.x << ", " << k.y << std::endl << std::endl

 END FUNCTION

Result:


 vector k: 0, 0

 vector m: 45, 2

 vector k: 23, 2

Chapter 19. Complex classes

If you cast an object like a vector, everything will happen correctly. For example, if vector *k* contains *(4, 7)*, after the cast *m = k* the vector *m* will contain *(4, 7)* too. The values of k.x and k.y have simply been copied to m.x and m.y.

Now suppose you're playing with objects like the person class above. Those objects contain a pointer to a character string. If you cast the person object by writing *p = r* it is necesary that some function does the work to make *p* be a correct copy of *r*. Otherwise, p.name will point to the same physical character string as r.name. What's more, the former character string pointed to by p.name is lost and becomes a memory zombie. The result will be catastrophic: a mess of pointers and lost data. The methods that will do the job are the COPY CONSTRUCTOR and an overload of the = operator

Example C19.bas:


 $CPP
 $NOMAIN

 #INCLUDE <iostream>
   
 CLASS person
   PUBLIC:
   RAW AS CHAR PTR name
   RAW AS INT age
    
   CONSTRUCTOR person (n = "no name" AS CONST CHAR PTR, a = 0 AS INT)
     name = NEW CHAR[100]
     name$ = n$
     age = a
   END CONSTRUCTOR
    
   CONSTRUCTOR person (s AS CONST person &) ' The COPY CONSTRUCTOR
   name = NEW CHAR[100]
     name$ = s.name$
     age = s.age
   END CONSTRUCTOR
    
   FUNCTION operator= (s AS CONST person &) AS person& ' overload of =
     name$ = s.name$
     age = s.age
     FUNCTION = *this
   END FUNCTION
    
   DESTRUCTOR ~person ()
     DELETE [] name
   END DESTRUCTOR
 END CLASS
    
 SUB modify_person (h AS person&)
   h.age += 7
 END SUB
    
 FUNCTION compute_person (h AS person) AS person
   h.age += 7
   FUNCTION = h
 END FUNCTION

 FUNCTION MAIN ()
  
 RAW AS person p
      
 std::cout << p.name << ", age " << p.age << std::endl << std::endl
   
 ' output: no name, age 0
 
 RAW AS person k ("John", 56)
 std::cout << k.name << ", age " << k.age << std::endl << std::endl
 ' output: John, age 56

 p = k
 std::cout << p.name << ", age " << p.age << std::endl << std::endl
 ' output: John, age 56

 p = person ("Bob", 10)
 std::cout << p.name << ", age " << p.age << std::endl << std::endl
 ' output: Bob, age 10

 ' Neither the copy constructor nor the overload
 ' of = are needed for this operation that modifies
 ' p since just the reference towards p is passed to
 ' the function modify_person:
 modify_person (p)
 std::cout << p.name << ", age " << p.age << std::endl << std::endl
 ' output: Bob, age 17
 
 ' The copy constructor is called to pass a complete
 ' copy of p to the function compute_person. The
 ' function uses that copy to make its computations
 ' then a copy of that modified copy is made to
 ' return the result. Finally, the overload of = is
 ' called to paste that second copy inside k:
 k = compute_person (p)
 
 std::cout << p.name << ", age " << p.age << std::endl << std::endl
 ' output: Bob, age 17

 std::cout << k.name << ", age " << k.age << std::endl << std::endl
 ' output: Bob, age 24

 END FUNCTION

Result:


 no name, age 0

 John, age 56

 John, age 56

 Bob, age 10

 Bob, age 17

 Bob, age 17

 Bob, age 24

The copy constructor allows your program to make copies of instances when doing calculations. It is a key method. During calculations, instances are created to hold intermediate results. They are modified, cast and destroyed without you being aware. This is why those methods can be useful even for simple objects (see Chapter 14.).

In all the examples above, the methods are defined inside the class definition. That automatically makes them inline methods.

Chapter 20. Method prototype

If a method cannot be inline, or you do not want it to be inline, or if you want the class definition to contain the minimum amount of information (or you simply want the usual separate .h header file and .cpp source code file), then you need only put the prototype of the method inside the class and define the method below the class (or in a separate .cpp source file).

Example C20.bas:


 $CPP
 $NOMAIN
 
 #INCLUDE <iostream>
   
 CLASS bcx_vector
   PUBLIC:
   RAW AS DOUBLE x
   RAW AS DOUBLE y
    
   DIM FUNCTION surface() AS DOUBLE
 END CLASS test1,test2
    
 FUNCTION bcx_vector::surface() AS DOUBLE
   RAW AS DOUBLE s = 0
    
   XFOR DOUBLE i = 0 WHILE i < x BY i++
     s = s + y
   XNEXT
    
   FUNCTION = s
 END FUNCTION
    
 FUNCTION MAIN ()
 
   RAW AS bcx_vector k
    
   k.x = 4
   k.y = 5
    
   std::cout << "Surface: " << k.surface() << std::endl
 
 END FUNCTION

Result:


 Surface: 20

Chapter 21. this

When a method is applied to an instance, that method may use the instance's variables, modify them... But sometimes it is necessary to know the address of the instance. No problem, the keyword *this* is intended for that purpose.

Example C21.bas:


 $CPP
 $NOMAIN
 
 #INCLUDE <iostream>
    
 CLASS bcx_vector
   PUBLIC:
   RAW AS DOUBLE x
   RAW AS DOUBLE y
     
   CONSTRUCTOR bcx_vector (a = 0 AS DOUBLE, b = 0 AS DOUBLE)
     x = a
     y = b
   END CONSTRUCTOR
     
   FUNCTION module() AS DOUBLE
     FUNCTION = SQRT(x * x + y * y)
   END FUNCTION
     
   SUB set_length (a = 1 AS DOUBLE)
     RAW AS DOUBLE length
     
     length = this->module()
     
     x = x / length * a
     y = y / length * a
   END SUB
 END CLASS
 
 FUNCTION MAIN ()
   
   RAW AS bcx_vector c (3, 5)
     
   std::cout << "The module of bcx_vector c: " << c.module() << std::endl
     
   c.set_length(2)   ' Transforms c in a bcx_vector of size 2
    
   std::cout << "The module of bcx_vector c: " << c.module() << std::endl
     
   c.set_length()    ' Transforms b in an unitary bcx_vector.
    
   std::cout << "The module of bcx_vector c: " << c.module() << std::endl
 
 END FUNCTION

Result:


 The module of vector c: 5.83095
 The module of vector c: 2
 The module of vector c: 1

Chapter 22. Arrays

Of course, it is possible to declare arrays of objects.

Example C22.bas:


 $CPP
 $NOMAIN

 #INCLUDE <iostream>
   
 CLASS bcx_vector
   PUBLIC:
   RAW AS DOUBLE x
   RAW AS DOUBLE y
    
   CONSTRUCTOR bcx_vector (a = 0 AS DOUBLE, b = 0 AS DOUBLE)
     x = a
     y = b
   END CONSTRUCTOR
    
   FUNCTION module () AS DOUBLE
     FUNCTION = SQRT(x * x + y * y)
   END FUNCTION
 END CLASS

 FUNCTION MAIN ()
  
   RAW AS bcx_vector s[1000]
    
   RAW AS bcx_vector t[3] = {bcx_vector(4, 5), bcx_vector(5, 5), bcx_vector(2, 4)}
    
   s[23] = t[2]
    
   std::cout << t[0].module() << std::endl

 END FUNCTION

Result:


6.40312

Chapter 23. Class declaration

Here is an example of a full class declaration.

Example C23.bas:


 $CPP
 $NOMAIN
 
 #INCLUDE <iostream>
   
 CLASS bcx_vector
   PUBLIC:
   RAW AS DOUBLE x
   RAW AS DOUBLE y
    
   DIM CONSTRUCTOR bcx_vector (a = 0 AS DOUBLE, b = 0 AS DOUBLE)
   DIM CONSTRUCTOR bcx_vector ()
    
   DIM FUNCTION operator + (a AS bcx_vector) AS bcx_vector
   DIM FUNCTION operator - (a AS bcx_vector) AS bcx_vector
   DIM FUNCTION operator - () AS bcx_vector
   DIM FUNCTION operator * (a AS DOUBLE) AS bcx_vector
   DIM FUNCTION module() AS DOUBLE
   DIM SUB set_length (A  AS DOUBLE = 1)
 END CLASS
    
 CONSTRUCTOR bcx_vector::bcx_vector (a AS DOUBLE, b AS DOUBLE)
   x = a
   y = b
 END CONSTRUCTOR
    
 CONSTRUCTOR bcx_vector::bcx_vector ()
   x = 0
   y = 0
 END CONSTRUCTOR
    
 FUNCTION bcx_vector::operator + (a AS bcx_vector) AS bcx_vector
   FUNCTION = bcx_vector (x + a.x, y + a.y)
 END FUNCTION
    
 FUNCTION bcx_vector::operator - (a AS bcx_vector) AS bcx_vector
   FUNCTION = bcx_vector (x - a.x, y - a.y)
 END FUNCTION
    
 FUNCTION bcx_vector::operator - () AS bcx_vector
   FUNCTION = bcx_vector (-x, -y)
 END FUNCTION
    
 FUNCTION bcx_vector::operator * (a AS DOUBLE) AS bcx_vector
   FUNCTION = bcx_vector (x * a, y * a)
 END FUNCTION
    
 FUNCTION bcx_vector::module() AS DOUBLE
   FUNCTION = SQRT(x * x + y * y)
 END FUNCTION
    
 SUB bcx_vector::set_length (a AS DOUBLE)
   RAW AS DOUBLE length = this->module()
    
   x = x / length * a
   y = y / length * a
 END SUB
    
 FUNCTION operator << (o AS std::ostream&, a AS bcx_vector) AS std::ostream&
   o << "(" << a.x << ", " << a.y << ")";
   FUNCTION = o
 END FUNCTION
    
 FUNCTION MAIN ()

   RAW AS bcx_vector a
   RAW AS bcx_vector b
   RAW AS bcx_vector c (3, 5)
    
   a = c * 3
   a = b + c
   c = b - c + a + (b - a) * 7
   c = -c
    
   std::cout << "The module of bcx_vector c: " << c.module() << std::endl
    
   std::cout << "The content of bcx_vector a: " << a << std::endl
   std::cout << "The opposite of bcx_vector a: " << -a << std::endl
    
   c.set_length(2)        ' Transforms c in a bcx_vector of size 2.
   
   a = bcx_vector (56, -3)
   b = bcx_vector (7, c.y)
    
   b.set_length()         ' Transforms b in an unitary bcx_vector.
   
   std::cout << "The content of bcx_vector b: " << b << std::endl
    
   DIM AS DOUBLE k
   k = bcx_vector(1, 1).module() ' k will contain 1.4142.
  std::cout << "k contains: " << k << std::endl

 END FUNCTION

Result:


 The module of bcx_vector c: 40.8167
 The content of bcx_vector a: (3, 5)
 The opposite of bcx_vector a: (-3, -5)
 The content of bcx_vector b: (0.971275, 0.23796)
 k contains: 1.41421

Chapter 23a. Class declaration with destructor.

A destructor has been added to the Chapter 23 example to show the use of the tilde "~" with destructors.

Example C23a.bas:


 $CPP
 $NOMAIN
 
 #INCLUDE <iostream>
   
 CLASS bcx_vector
   PUBLIC:
   RAW AS DOUBLE x
   RAW AS DOUBLE y
    
   DIM CONSTRUCTOR bcx_vector (a = 0 AS DOUBLE, b = 0 AS DOUBLE)
   DIM CONSTRUCTOR bcx_vector ()
   'need ~ below
  DIM DESTRUCTOR ~bcx_vector()
   DIM FUNCTION operator + (a AS bcx_vector) AS bcx_vector
   DIM FUNCTION operator - (a AS bcx_vector) AS bcx_vector
   DIM FUNCTION operator - () AS bcx_vector
   DIM FUNCTION operator * (a AS DOUBLE) AS bcx_vector
   DIM FUNCTION module() AS DOUBLE
   DIM SUB set_length (A  AS DOUBLE = 1)
 END CLASS
    
 CONSTRUCTOR bcx_vector::bcx_vector (a AS DOUBLE, b AS DOUBLE)
   x = a
   y = b
 END CONSTRUCTOR
    
 CONSTRUCTOR bcx_vector::bcx_vector ()
   x = 0
   y = 0
 END CONSTRUCTOR
 'need ~ below
DESTRUCTOR bcx_vector::~bcx_vector()
        
 END DESTRUCTOR
    
 FUNCTION bcx_vector::operator + (a AS bcx_vector) AS bcx_vector
   FUNCTION = bcx_vector (x + a.x, y + a.y)
 END FUNCTION
    
 FUNCTION bcx_vector::operator - (a AS bcx_vector) AS bcx_vector
   FUNCTION = bcx_vector (x - a.x, y - a.y)
 END FUNCTION
    
 FUNCTION bcx_vector::operator - () AS bcx_vector
   FUNCTION = bcx_vector (-x, -y)
 END FUNCTION
    
 FUNCTION bcx_vector::operator * (a AS DOUBLE) AS bcx_vector
   FUNCTION = bcx_vector (x * a, y * a)
 END FUNCTION
    
 FUNCTION bcx_vector::module() AS DOUBLE
   FUNCTION = SQRT(x * x + y * y)
 END FUNCTION
    
 SUB bcx_vector::set_length (a AS DOUBLE)
   RAW AS DOUBLE length = this->module()
    
   x = x / length * a
   y = y / length * a
 END SUB
    
 FUNCTION operator << (o AS std::ostream&, a AS bcx_vector) AS std::ostream&
   o << "(" << a.x << ", " << a.y << ")";
   FUNCTION = o
 END FUNCTION
    
 FUNCTION MAIN ()

   RAW AS bcx_vector a
   RAW AS bcx_vector b
   RAW AS bcx_vector c (3, 5)
    
   a = c * 3
   a = b + c
   c = b - c + a + (b - a) * 7
   c = -c
    
   std::cout << "The module of bcx_vector c: " << c.module() << std::endl
    
   std::cout << "The content of bcx_vector a: " << a << std::endl
   std::cout << "The oposite of bcx_vector a: " << -a << std::endl
    
   c.set_length(2)        ' Transforms c in a bcx_vector of size 2.
   
   a = bcx_vector (56, -3)
   b = bcx_vector (7, c.y)
    
   b.set_length()         ' Transforms b in an unitary bcx_vector.
   
   std::cout << "The content of bcx_vector b: " << b << std::endl
    
   DIM AS DOUBLE k
   k = bcx_vector(1, 1).module() ' k will contain 1.4142.
  std::cout << "k contains: " << k << std::endl

 END FUNCTION

Result:


 The module of bcx_vector c: 40.8167
 The content of bcx_vector a: (3, 5)
 The opposite of bcx_vector a: (-3, -5)
 The content of bcx_vector b: (0.971275, 0.23796)
 k contains: 1.41421

Chapter 24. Static variables

One or more variables in a class can be declared *static*. In which case, only one instance of those variables exist, shared by all instances of the class. It must be initialised outside the class declaration.

Example C24.bas:


 $CPP
 $NOMAIN
 
 #INCLUDE <iostream>
 
 CLASS bcx_vector
   PUBLIC:
   RAW AS DOUBLE x
   RAW AS DOUBLE y
   STATIC AS INT count
    
   CONSTRUCTOR bcx_vector (a = 0 AS DOUBLE, b = 0 AS DOUBLE)
     x = a
     y = b
     count++
   END CONSTRUCTOR
    
   DESTRUCTOR ~bcx_vector()
     count--
   END DESTRUCTOR
 END CLASS
    
 RAW AS INT bcx_vector::count = 0
 
 FUNCTION MAIN ()

   std::cout << "Number of bcx_vectors:" << std::endl
    
   RAW AS bcx_vector a
   std::cout << bcx_vector::count << std::endl
    
   RAW AS bcx_vector b
   std::cout << bcx_vector::count  << std::endl
    
   RAW AS bcx_vector PTR r, u
    
   r = NEW bcx_vector
   std::cout << bcx_vector::count << std::endl
    
   u = NEW bcx_vector
   std::cout << a.count << std::endl
    
   DELETE r
   std::cout << bcx_vector::count << std::endl
    
   DELETE u
   std::cout << b.count << std::endl

 END FUNCTION

Result:


 Number of bcx_vectors:
 1
 2
 3
 4
 3
 2

Chapter 25. Const variables

A class variable can also be *const*ant. That's just like static, except it is given a value inside the class declaration and that value cannot be modified.

A const within a CLASS must be a static const of integral or enumeration type initialized by a constant expression.

Some compilers, for example g++, have an extension that allows for const static float and doubles within a CLASS. Also, the C++0x standard has introduced a new type, constexpr, which allows in-CLASS float and doubles constants.

Example C25.bas:


 $CPP
 $NOMAIN
  
 #INCLUDE <iostream>
 
 CLASS bcx_vector
   PUBLIC:
   RAW AS DOUBLE x
   RAW AS DOUBLE y
   CONST STATIC INT piint = 3
    
   CONSTRUCTOR bcx_vector (a = 0 AS DOUBLE, b = 0 AS DOUBLE)
     x = a
     y = b
   END CONSTRUCTOR
    
   FUNCTION cylinder_volume () AS DOUBLE
     FUNCTION = x * x / 4 * (piint + 0.14159) * y
   END FUNCTION
 END CLASS
 
 FUNCTION MAIN ()
  
   std::cout << "The value of pi: " << bcx_vector::piint + 0.14159 << std::endl << std::endl
    
   bcx_vector k (3, 4)
    
   std::cout << "Result: " << k.cylinder_volume() << std::endl
 
 END FUNCTION

Result:


 The value of pi: 3.14159

 Result: 28.2743

Chapter 26. Derived Class.

A class can be derived from another class. The new class inherits the variables and methods of the base class. Additional variables and/or methods can be added.

Example C26.bas:


 $CPP
 $NOMAIN
  
 #INCLUDE <iostream>
  
 CLASS bcx_vector
   PUBLIC:
    
   RAW AS DOUBLE x
   RAW AS DOUBLE y
    
   CONSTRUCTOR bcx_vector (a = 0 AS DOUBLE, b = 0 AS DOUBLE)
     x = a
     y = b
   END CONSTRUCTOR
    
   FUNCTION module() AS DOUBLE
     FUNCTION = SQRT(x*x + y*y)
   END FUNCTION
    
   FUNCTION surface() AS DOUBLE
     FUNCTION = x * y
   END FUNCTION
 END CLASS
    
 CLASS trivector USING PUBLIC bcx_vector    ' trivector is derived from bcx_vector
  PUBLIC:
   RAW AS DOUBLE z       ' added to x and y from bcx_vector
   
   CONSTRUCTOR trivector (m=0 AS DOUBLE, n=0 AS DOUBLE, p=0 AS DOUBLE) USING bcx_vector (m, n)
     z = p               ' bcx_vector constructor will
   END CONSTRUCTOR       ' be called before trivector
                         ' constructor, with parameters
                         ' m and n.
   
   CONSTRUCTOR trivector (a AS bcx_vector) ' What to do if a bcx_vector is cast to a trivector
    x = a.x
     y = a.y
     z = 0
   END CONSTRUCTOR
    
   FUNCTION module () AS DOUBLE      ' define module() for trivector
    FUNCTION = SQRT(x*x + y*y + z*z)
   END FUNCTION
    
   FUNCTION volume () AS DOUBLE
     FUNCTION = this->surface() * z    ' or x * y * z
  END FUNCTION
 END CLASS
    
 FUNCTION MAIN ()
  
   RAW AS bcx_vector a (4, 5)
   RAW AS trivector b (1, 2, 3)
    
   std::cout << "a (4, 5)    b (1, 2, 3)    *r = b" << std::endl << std::endl
    
   std::cout << "Surface of a: " << a.surface() << std::endl
   std::cout << "Volume of b: " << b.volume() << std::endl
   std::cout << "Surface of base of b: " << b.surface() << std::endl
    
   std::cout << "Module of a: " << a.module() << std::endl
   std::cout << "Module of b: " << b.module() << std::endl
   std::cout << "Module of base of b: " << b.bcx_vector::module() << std::endl
    
   RAW AS trivector k
   k = a                 ' thanks to trivector(bcx_vector) definition
  ' copy of x and y,       k.z = 0
  RAW AS bcx_vector j
   j = b                 ' copy of x and y.       b.z left out
   
   RAW AS bcx_vector PTR r
   r = &b
    
   std::cout << "Surface of r: " << r->surface() << std::endl
   std::cout << "Module of r: " << r->module() << std::endl
 
 END FUNCTION

Result:


 a (4, 5)    b (1, 2, 3)    *r = b

 Surface of a: 20
 Volume of b: 6
 Surface of base of b: 2
 Module of a: 6.40312
 Module of b: 3.74166
 Module of base of b: 2.23607
 Surface of r: 2
 Module of r: 2.23607

Chapter 27. Virtual method

In the Chapter 26 example, *r->module()* calculates the vector module, using *x* and *y*, because *r* has been declared a vector pointer. The fact that *r* actually points to a trivector is not taken into account. If you want the program to check the type of the pointed object and choose the appropriate method, then you must declare that method as *virtual* inside the base class.

(If at least one of the methods of the base class is virtual then a "header" of 4 bytes is added to every instance of the classes. This allows the program to determine what a vector actually points to.) (4 bytes is probably implementation specific. On a 64 bit machine maybe it is 8 bytes...)

Example C27.bas:


 $CPP 
 $NOMAIN
  
 #INCLUDE <iostream>
   
 CLASS bcx_vector
   PUBLIC:
   RAW AS DOUBLE x
   RAW AS DOUBLE y
    
   CONSTRUCTOR bcx_vector (a = 0 AS DOUBLE, b = 0 AS DOUBLE)
     x = a
     y = b
   END CONSTRUCTOR
    
   FUNCTION module() AS virtual DOUBLE
     FUNCTION = SQRT(x*x + y*y)
   END FUNCTION
 END CLASS
    
 CLASS trivector USING PUBLIC bcx_vector
   PUBLIC:
   RAW AS DOUBLE z
    
   CONSTRUCTOR trivector (m = 0 AS DOUBLE, n = 0 AS DOUBLE, p = 0 AS DOUBLE)
    x = m                   ' Just for the game,
    y = n                   ' here I do not call the bcx_vector
    z = p                   ' constructor and I make the
  END CONSTRUCTOR          ' trivector constructor do the
                            ' whole job. Same result.
   
   FUNCTION module () AS DOUBLE
     FUNCTION = SQRT(x*x + y*y + z*z)
   END FUNCTION
 END CLASS
    
 SUB test (k AS bcx_vector &)
   std::cout << "Test result:            " << k.module() << std::endl
 END SUB
    
 FUNCTION MAIN ()
  
   RAW AS bcx_vector a (4, 5)
   RAW AS trivector b (1, 2, 3)
    
   std::cout << "a (4, 5)    b (1, 2, 3)" << std::endl << std::endl
    
   RAW AS bcx_vector PTR r
    
   r = &a
   std::cout << "module of bcx_vector a: " << r->module() << std::endl
    
   r = &b
   std::cout << "module of trivector b:  " << r->module() << std::endl
    
   test (a)
    
   test (b)
    
   RAW AS bcx_vector &s = b
    
   std::cout << "module of trivector b:  " << s.module() << std::endl
 
 END FUNCTION

Result:


 a (4, 5)    b (1, 2, 3)

 module of bcx_vector a: 6.40312
 module of trivector b:  3.74166
 Test result:            6.40312
 Test result:            3.74166
 module of trivector b:  3.74166

Chapter 28. Multi-class method

Maybe you wonder if a class can be derived from more than one base class. The answer is yes.

Example C28.bas:


 $CPP
 $NOMAIN
  
 #INCLUDE <iostream>
   
 CLASS bcx_vector
   PUBLIC:
   RAW AS DOUBLE x
   RAW AS DOUBLE y
    
   CONSTRUCTOR bcx_vector (a = 0 AS DOUBLE, b = 0 AS DOUBLE)
     x = a
     y = b
   END CONSTRUCTOR
    
   FUNCTION surface() AS DOUBLE
     FUNCTION = fabs (x * y)
   END FUNCTION
 END CLASS
   
 CLASS number
   PUBLIC:
   RAW AS DOUBLE z
    
   CONSTRUCTOR number (a AS DOUBLE)
     z = a
   END CONSTRUCTOR
    
   FUNCTION is_negative () AS INT
     IF z < 0 THEN
       FUNCTION = 1
     ELSE
       FUNCTION = 0
     END IF
   END FUNCTION
 END CLASS
   
 CLASS trivector USING PUBLIC bcx_vector, PUBLIC number
   PUBLIC:
    
   CONSTRUCTOR trivector(a=0 AS DOUBLE, b=0 AS DOUBLE, c=0 AS DOUBLE) USING bcx_vector(a,b), number(c)
   END CONSTRUCTOR ' The trivector constructor calls the bcx_vector
                     ' constructor, then the number constructor,
                     ' and in this example does nothing more.
   
   FUNCTION volume() AS DOUBLE
     FUNCTION = fabs (x * y * z)
   END FUNCTION
 END CLASS
   
 FUNCTION MAIN ()
  
   RAW AS trivector a(2, 3, -4)
    
   std::cout << a.volume() << std::endl
   std::cout << a.surface() << std::endl
   std::cout << a.is_negative() << std::endl
 
 END FUNCTION

Result:


 24
 6
 1

Chapter 29. Derived Class

Class derivation allows you to construct more complex classes built from base classes. There is another application of class derivation: allowing the programmer to write generic functions.

Suppose you define a base class with no variables. It makes no sense to use instances of that class inside your program. But then you write a function whose purpose it is to sort instances of that class. That function will be able to sort any type of object provided it belongs to a class derived from that base class! The only condition is that inside of each derived class definition, all methods that the sort function needs are correctly defined.

Example C29.bas:


 $CPP
 $NOMAIN
  
 #INCLUDE <iostream>
  
 CLASS octopus
   PUBLIC:
    
   IMPFUNCTION module() = 0 AS virtual DOUBLE
   ' = 0 implies function is not
   ' defined. This makes instances
   ' of this CLASS cannot be declared.
END CLASS
    
 FUNCTION biggest_module (a AS octopus &, b  AS octopus &, c  AS octopus &) AS DOUBLE
   RAW r = a.module() AS DOUBLE
   IF b.module() > r THEN r = b.module()
   IF c.module() > r THEN r = c.module()
   FUNCTION = r
 END FUNCTION
    
 CLASS bcx_vector USING PUBLIC octopus
   PUBLIC:
    
   RAW AS DOUBLE x
   RAW AS DOUBLE y
    
   CONSTRUCTOR bcx_vector (a = 0 AS DOUBLE, b = 0 AS DOUBLE)
     x = a
     y = b
   END CONSTRUCTOR
    
   FUNCTION module() AS DOUBLE
     FUNCTION = SQRT(x * x + y * y)
   END FUNCTION
 END CLASS
    
 CLASS number USING PUBLIC octopus
   PUBLIC:
    
   RAW AS DOUBLE n
    
   CONSTRUCTOR number (a = 0 AS DOUBLE)
     n = a
   END CONSTRUCTOR
    
   FUNCTION module() AS DOUBLE
     IF n >= 0 THEN FUNCTION = n
     FUNCTION = -n
   END FUNCTION
 END CLASS
    
 FUNCTION MAIN ()
  
   RAW AS bcx_vector k (1,2), m (6,7), n (100, 0)
   RAW AS number p (5),   q (-3),  r (-150)
    
   std::cout << biggest_module (k, m, n) << std::endl
   std::cout << biggest_module (p, q, r) << std::endl
   std::cout << biggest_module (p, q, n) << std::endl
 
 END FUNCTION

Result:


 100
 150
 100

Chapter 30. Encapsulation: public, protected and private

The *PUBLIC:* directive means the variables or the methods below can be accessed and used everywhere in the program.

If you want the variables and methods to be accessible only to methods of the class AND to methods of derived classes, then you must put the keyword *protected:* before them.

If you want variables or methods to be accessible ONLY to methods of the class, then you must put the keyword *private:* before them.

The fact that variables or methods are declared private or protected means that nothing external to the class can access or use them. That's ENCAPSULATION. (If you want to give a specific function the right to access those variables and methods, then you must include that function's prototype inside the class definition, preceded by the keyword *friend*.)

Good practice is to encapsulate all the variables of a class. This can sound strange if you're used to structs in C. Indeed a struct only makes sense if you can access its data... In C++ you have to create methods to access the data inside a class. The example below uses the basic example of chapter 17, yet declares the class data to be protected.

Example C30_01.bas:


 $CPP
 $NOMAIN
  
 #INCLUDE <iostream>
   
 CLASS bcx_vector
   PROTECTED:
   RAW AS DOUBLE x
   RAW AS DOUBLE y
    
   PUBLIC:
    
   SUB set_x (n AS INT)
     x = n
   END SUB
    
   SUB set_y (n AS INT)
     y = n
   END SUB
    
   FUNCTION surface () AS DOUBLE
     RAW AS DOUBLE s
     s = x * y
     IF s < 0 THEN s = -s
     FUNCTION = s
   END FUNCTION
 END CLASS
    
 FUNCTION MAIN ()
  
   RAW AS bcx_vector a
    
   a.set_x (3)
   a.set_y (4)
    
   std::cout << "The surface of a: " << a.surface() << std::endl
 
 END FUNCTION

Result:


 The surface of a: 12

The example above is a bit odd since the class data x and y can be set but they cannot be read back. Any attempt in function main () to read a.x or a.y will result in a compilation error. In the next example, x and y can be read back.

Example C30_02.bas:


 $CPP
 $NOMAIN
  
 #INCLUDE <iostream>
   
 CLASS bcx_vector
   PROTECTED:
   RAW AS DOUBLE x
   RAW AS DOUBLE y
    
   PUBLIC:
    
   SUB set_x (n AS INT)
     x = n
   END SUB
    
   SUB set_y (n AS INT)
     y = n
   END SUB
    
   FUNCTION get_x () AS DOUBLE
     FUNCTION = x
   END FUNCTION
    
   FUNCTION get_y () AS DOUBLE
     FUNCTION = y
   END FUNCTION
    
   FUNCTION surface () AS DOUBLE
     RAW AS DOUBLE s
     s = x * y
     IF s < 0 THEN s = -s
     FUNCTION = s
   END FUNCTION
 END CLASS
    
 FUNCTION MAIN ()
  
   RAW AS bcx_vector a
    
   a.set_x (3)
   a.set_y (4)
    
   std::cout << "The surface of a: " << a.surface() << std::endl
   std::cout << "The width of a:   " << a.get_x() << std::endl
   std::cout << "The height of a:  " << a.get_y() << std::endl
 
 END FUNCTION

Result:


 The surface of a: 12
 The width of a:   3
 The height of a:  4

Chapter 31. Brief examples of file I/O

Let's talk about input/output. In C++ that's a very broad subject. Here is a program that writes to a file

Example C31_01.bas:


 $CPP
 $NOMAIN
  
 #INCLUDE <iostream>
 #INCLUDE <fstream>
 
 FUNCTION MAIN ()
  
   RAW AS std::fstream f
    
   f.open("test.txt", std::ios::out)
    
   f << "This is a text output to a file." << std::endl
    
   RAW AS DOUBLE a = 345
    
   f  << "A number: " << a << std::endl
    
   f.close()
   std::cout << "test.txt created" << std::endl
 
 END FUNCTION

Result:


 test.txt created

The content of file test.txt should be


 This is a text output to a file.
 A number: 345

Before you use Example C31_02 be sure to create the test.txt file with Example C31_01.

Example C31_02.bas:


 $CPP
 $NOMAIN
  
 #INCLUDE <iostream>
 #INCLUDE <fstream>
 
 FUNCTION MAIN ()
  
   RAW AS std::fstream f
   RAW AS CHAR c
    
   std::cout << "What's inside the test.txt file" << std::endl
   std::cout << std::endl
    
   f.open("test.txt", std::ios::in)
    
   WHILE NOT f.eof()
     f.get(c)   'Or c = f.get()
    std::cout << c
   WEND
    
   f.close()
 
 END FUNCTION

Result:


 What's inside the test.txt file

 This is a text output to a file.
 A number: 345

Chapter 32. Character arrays

Generally speaking, it is possible to do on character arrays the same operations as on files. This is very useful to convert data or manage memory arrays.

Here is a program that writes inside a character array.

Example C32_01.bas:


 $CPP
 $NOMAIN
  
 #INCLUDE <iostream>
 #INCLUDE <strstream>
     
 FUNCTION MAIN ()
  
   RAW AS CHAR a[1024]
   RAW AS std::ostrstream b(a, 1024)
      
  b.seekp(0)                           ' Start from first char.
  b << "2 + 2 = " << 2 + 2 << std::ends ' ( ends, not std::endl )
                                        ' ends is simply the
                                        ' null character   '\0'
  std::cout << a << std::endl
      
   RAW AS DOUBLE v = 2
      
   a$ = "A sinus: "
      
   b.seekp(LEN(a))
   b << "sin (" << v << ") = " << SIN(v) << std::ends
      
   std::cout << a << std::endl
 
 END FUNCTION

Result:


 2 + 2 = 4
 A sinus: sin (2) = 0.909297

A program that reads from a character string

Example C32_02.bas:


 $CPP 
 $NOMAIN
  
 #INCLUDE <iostream>
 #INCLUDE <strstream>
 
 FUNCTION MAIN ()
  
   RAW AS CHAR a[1024]
   RAW AS std::istrstream b(a, 1024)
   
   a$ = "45.656"
      
   RAW AS DOUBLE k, p
      
  b.seekg(0) ' Start from first character.
  b >> k
      
   k = k + 1
      
   std::cout << k << std::endl
      
   a$ = "444.23 56.89"
      
   b.seekg(0)
   b >> k >> p
      
   std::cout << k << ", " << p + 1 << std::endl
 
 END FUNCTION

Result:


 46.656
 444.23, 57.89

Chapter 33. Formatted output

This program performs formatted output two different ways. Please note the *width()* and *setw()* MODIFIERS are only effective on the next item output to the stream. Subsequent items will not be influenced.

Example C33.bas:


 $CPP
 $NOMAIN
  
 #INCLUDE <iostream>
 #INCLUDE <iomanip>
 
 FUNCTION MAIN ()
  
   RAW AS INT i
    
   std::cout << "A list of numbers:" << std::endl
   XFOR i = 1 WHILE i <= 1024 BY i *= 2
     std::cout.width (7)
     std::cout << i << std::endl
   XNEXT
    
   std::cout << "A table of numbers:" << std::endl
   XFOR i = 0 WHILE i <= 4 BY i++
     std::cout << std::setw(3) << i << std::setw(5) << i * i * i << std::endl
   XNEXT
 
 END FUNCTION

Result:


 A list of numbers:
      1
      2
      4
      8
     16
     32
     64
    128
    256
    512
   1024
 A table of numbers:
  0    0
  1    1
  2    8
  3   27
  4   64

METHOD and PROPERTY keywords

METHOD is transformed to FUNCTION and PROPERTY is transformed to SUB prior to main BCX translation. METHOD and PROPERTY can only be used in a CLASS which can only be compiled with a C++ compiler in C++ mode.

Example:


 $CPP
 SUB MAIN
  DIM RAW AS bcx_vector a
  a.set_x (3)
  a.set_y (4)
  PRINT "The surface of a: ", a.surface#()
 END SUB
 
 
 CLASS bcx_vector
  PROTECTED:
  DIM RAW AS DOUBLE x
  DIM RAW AS DOUBLE y
  PUBLIC:
 
  PROPERTY set_x (n AS DOUBLE)
   x = n
  END PROPERTY
 
  PROPERTY set_y (n AS DOUBLE)
   y = n
  END PROPERTY
 
  METHOD surface () AS DOUBLE
   DIM RAW AS DOUBLE s
   s = x * y
   IF s < 0 THEN s = -s
   METHOD = s
  END METHOD
 END CLASS

Result:


 The surface of a:  12

PROPGET and PROPSET keywords

PROPGET is transformed to FUNCTION and PROPSET is transformed to SUB prior to main BCX translation. PROPGET and PROPSET can only be used in a CLASS which can only be compiled with a C++ compiler in C++ mode.

Example:


 $CPP
 
 OPTION BASE 1
 
 DIM Vehicle [3] AS CAR
 
 FOR INTEGER i = 1 TO 3
  '******************************************************************** 
  ' Every car starts out as a Black Volkswagon with 2 gallons of fuel 
  '******************************************************************** 
  PRINT "Vehicle:", i,     " is a ", _
  Vehicle[i].Get_Paint$(), " ",      _
  Vehicle[i].Get_Model$(), " with",  _
  Vehicle[i].Get_Fuel () , " gallons of fuel."
 NEXT
 PRINT
 
 '*********************************************************************** 
 '       Now let's trade our Volkswagons in on some muscle cars! 
 '*********************************************************************** 
 
 Vehicle[1].Set_Model ("Chevrolet Corvette")
 Vehicle[1].Set_Paint ("White")
 Vehicle[1].Set_Fuel  (10)
 
 Vehicle[2].Set_Model ("Ford Mustang")
 Vehicle[2].Set_Paint ("Blue")
 Vehicle[2].Set_Fuel  (5)
 
 Vehicle[3].Set_Model ("Dodge Charger")
 Vehicle[3].Set_Paint ("Green")
 Vehicle[3].Set_Fuel  (13)
 
 FOR INTEGER i = 1 TO 3
  PRINT "Vehicle:", i,     " is a ", _
  Vehicle[i].Get_Paint$(), " ",      _
  Vehicle[i].Get_Model$(), " with",  _
  Vehicle[i].Get_Fuel(),   " gallons of fuel."
 NEXT
 
 PAUSE
 
 '******************************************************************** 
 '  Here is our CLASS named "CAR".  Each instance of "CAR" contains a 
 '  CONSTRUCTOR, 3 variables, 3 "Setters", 3 "Getters" and a function 
 '******************************************************************** 
 
 CLASS CAR
  PROTECTED:
  DIM Model$, Paint$, Fuel   ' << These are our car PROPERTIES 
 
  '***************************************************************** 
  ' A CONSTRUCTOR is like a SUB that is called automatically when 
  ' a new instance of CAR is created.  CONSTRUCTOR names must use 
  ' the same name as the CLASS that it is stored within.  That is 
  ' why our CLASS and CONSTRUCTOR are both named "CAR".  That is 
  ' a C++ rule and therefore also a BCX rule. 
  '***************************************************************** 
  PUBLIC:
  CONSTRUCTOR CAR (M$ = "Volkswagon", P$ = "BLACK", F  = 2 )
   Model$ = M$
   Paint$ = P$
   Fuel   = F
  END CONSTRUCTOR
 
  '***************************************************************** 
  '              Here are our property "SETTERS" 
  '***************************************************************** 
 
  PROPSET Set_Model (M$)
   Model$  = M$
  END PROPSET
 
  PROPSET Set_Paint (c$)
   Paint$ = c$
  END PROPSET
 
  PROPSET Set_Fuel (x AS INTEGER)
   Fuel = x
  END PROPSET
 
 
  '***************************************************************** 
  '              Here are our property "GETTERS" 
  '***************************************************************** 
 
  PROPGET Get_Model() AS STRING
   PROPGET = MixCase$ (Model$) ' Uses our helper function (below) 
  END PROPGET
 
  PROPGET Get_Fuel() AS INTEGER
   PROPGET = Fuel
  END PROPGET
 
  PROPGET Get_Paint() AS STRING
   PROPGET = MixCase$ (Paint$) ' Uses our helper function (below) 
  END PROPGET
 
  '***************************************************************** 
  '             Here is a user-defined helper FUNCTION 
  '***************************************************************** 
 
  FUNCTION MixCase$(A$)    ' Here is a local User-Defined Function 
   FUNCTION = MCASE$(A$) ' calling a built-in BCX string function 
  END FUNCTION
 
 END CLASS

Result:


 Vehicle: 1 is a Black Volkswagon with 2 gallons of fuel.
 Vehicle: 2 is a Black Volkswagon with 2 gallons of fuel.
 Vehicle: 3 is a Black Volkswagon with 2 gallons of fuel.

 Vehicle: 1 is a White Chevy Corvette with 10 gallons of fuel.
 Vehicle: 2 is a Blue Ford Mustang with 5 gallons of fuel.
 Vehicle: 3 is a Green Dodge Charger with 13 gallons of fuel.

RBFOR, RBEXIT, and RBNEXT keywords

Purpose: RBFOR, RBEXIT, and RBNEXT support C++range-based FOR ... NEXT loops. These require a C++11 or newer compiler.


Syntax:

 RBFOR(DataType iteranger : iteratee)
 Statements
 [ RBEXIT RBFOR ]
 RBNEXT

Parameters:

  • DataType data type of iterator. AUTO& data type inference by reference is preferred for the iteranger.
  • iteranger ordinal tracker of the iteratee.
  • iteratee an array, vector or any other construct that can iterated.

Remarks:

RBEXIT RBFOR can be used to exit the loop. Functionality is identical to EXIT FOR.

Example

The following example iterates through the named directory, in this code the D:/t directory, and prints any entries that have a .exe, .c, or .cpp extension.

This example requires a compiler conforming, at minimum, to the C++17 standard.


 $CPP
 $CPPHDR

 #INCLUDE <filesystem>

 FUNCTION MAIN()
   RAW AS std::filesystem::path p = "C:\temp"  ' Modify to suit your needs 
   DIM S1$
   IF std::filesystem::exists(p) THEN
     IF std::filesystem::is_directory(p) THEN
       RBFOR(AUTO& e : std::filesystem::recursive_directory_iterator(p))
       S1$ = e.path().string().c_str()  ' Be careful not to accidentally change case 
       IF (UCASE$(BCXSPLITPATH$(S1$, FEXT)) = ".EXE") OR _
          (UCASE$(BCXSPLITPATH$(S1$, FEXT)) = ".C")   OR _
          (UCASE$(BCXSPLITPATH$(S1$, FEXT)) = ".CPP") THEN
          PRINT S1$
       END IF
       RBNEXT
     ENDIF
   ELSE
     PRINT "Specified drive, path, and/or file extensions not found."
   END IF
   PRINT "ALL Done"
   PAUSE
 END FUNCTION