Object Pascal to C++ Builder Coding

Overview

This page is intended to provide useful information about translating Object Pascal code into the C++ Builder code.

My use of C++ Builder in the past has been limited simply because I have not given myself enough time to workout how I implement code in C++ Builder which I take for granted in Delphi; for instance enumerates and sets. I now want to start building applications in C++ Builder with the same easy as Delphi and not be limited by my C++ Builder coding knowledge so this page will contain all the information I find out so that it can be useful and hopefully this page will help any of you developers out there who coding in Delphi and have C++ Builder but have not used it due to not knowing how to do the same things in C++ Builder as Delphi.

It will get updated as time goes by and I find more information that I require.

Enumerates

Enumerates are one of those core language features of Object Pascal that I've used right from the days of Turbo Pascal 5.5 when I started coding. For me they make the code more readable. They ensure through strong type checking that you do not assign the wrong value to a variable which could happen if you simply used integer constants and when used with sets (see below) make for a powerful means of managing boolean information.

Defining Enumerates

In Object Pascal we define enumerates as follows:

TMyEnumerate = (meFirst, meSecond, meThird, meFourth);

In C++ Builder we define the same enumerate as follows:

enum TMyEnumerate {meFirst, meSecond, meThird, meFourth};

Declaring Variables

In Object Pascal we create enumerates as follows:

iMyEnumerate : TMyEnumerate;

In C++ Builder we create the same enumerate as follows:

TMyEnumerate iMyEnumerate;

Assigning Values

In Object Pascal we assign enumerates as follows:

iMyEnumerate := meThird;

In C++ Builder we assign the same enumerate as follows:

iMyEnumerate = meThird;

In C++ Builder you can also assign an enumerate to a variable at the time it is declared as follows:

TMyEnumerate iMyEnumerate = meThird;

You can do this because you can declare variables within the context of methods unlike Object Pascal where you must declare you variables in a separate var section.

Sets

This is the other topic I wanted to implement in C++ Builder. I use sets a lot in my code to pass boolean options around. Sets have been implemented in C++ Builder as a class because there is no native impleentation of sets in C++.

Defining Sets

Assuming the definition of our enumerate above in Object Pascal we can define a set as follows:

TMySet = Set Of TMyEnumerate;

The definition of the same set in C++ Builder requires the use of a template which I believe from what I have read actually creates a contained class for the enumerate items and is defined as follows:

typedef Set<TMyEnumerate, meFirst, meFourth> TMySet;

This template takes 3 parameters to create the class as follows:

  1. The enumerate type to be stored in the set;
  2. The lowest value of the enumerate that can be stored in the set;
  3. The highest value of the enumerate that can be stored in the set.

Declaring Variables

In Object Pascal we define a set variables as follows:

MySet : TMySet;

In C++ Builder we define a set variable as follows:

MySet MySet;

Initialising Sets

To initialise a set in Object Pascal we can do one of the following:

MySet := [];                            // Empty set
MySet := [meFirst, meFourth];           // first and last
MySet := [meFirst..meSecond, meFourth]; // first to second and last

To initialise a set in C++ Builder we need to assign a copy of the class to the instance.

MySet = TMySet();                                  // Empty set
MySet = TMySet() << emFirst << emLast;             // first and last
MySet = TMySet() << emFirst << emSecond << emLast; // first to second and last

You will note that in C++ Builder you can't do ranges, you have to add each enumerate but you can concatenate them in a single statement.

Adding and Remove Values from a Set

In Object Pascal we can added enumerates to sets a number of ways as follows:

Include(MySet, emThird);             // Add single enumerate to set
MySet := MySet + [emThird];          // Achieves the same as above
MySet := MySet + [emThird, emFirst]; // Add several enumerates at once

In Object Pascal we can remove enumerates to sets a number of ways as follows:

Exclude(MySet, emThird);             // Remove single enumerate to set
MySet := MySet - [emThird];          // Achieves the same as above
MySet := MySet - [emThird, emFirst]; // Remove several enumerates at once

In C++ Builder we can added enumerates to a set as follows:

MySet << emThird;            // Add single enumerate to set
MySet << emThird << emFirst; // Add several enumerates at once

In C++ Builder we can remove enumerates from a set as follows:

MySet >> emThird;            // Remove single enumerate to set
MySet >> emThird >> emFirst; // Remove several enumerates at once

Note: In all the above cases, if an enumerate is not in the set trying to remove the enumerate does nothing.

Testing for an Enumerate in a Set

In Object Pascal we can test for the presents of an enumerate in a set with the In key word as follows:

If meThird In MySet Then

In C++ Builder we need to use a member function of the class that represents the set to achieve the same goal as below:

if (MySet.Contains(meThird))

Set Operators

The follows table list the Object Pascal set operators along side the C++ Builder set methods which provide the same functioanlity:

Operation Operand Types Result Type OP Example C++ Example
Union Set Set
Set1 + Set2
Set1 + Set2
Set1 += Set2
Difference Set Set
Set1 - Set2
Set1 - Set2
Set1 -= Set2
Intersection Set Set
Set1 * Set2
Set1 * Set2
Set1 *= Set2
Subset Set Boolean
Set1 <= Set2
Superset Set Boolean
Set1 >= Set2
Equality Set Boolean
Set1 = Set2
Set1 != Set2
Inequality Set Boolean
Set1 <> Set2
Set1 != Set2
Membership Ordinal & Set Boolean
A In Set1
Set1.Contains(A)
Clear set Set Set
Set1 := []
Set1.Clear()
Is Empty Set Boolean
Set1 = []
Set1.Empty()

One thing to note here is that sets in C++ Builder are classes not an ordinal type and therefore have a performance overhead compared to the Object Pascal implementation. If used occasionally then not a problem but if used a lot in performance code, this will impact the performance and you should probably look for another solution (Thanks to C Johnson for this observation).

Data Types

When coding in Object Pascal I take for granted the data types available to me so below is a table of data types and their Object Pascal and C++ Builder equivalents:

Signed Integers

Size Object Pascal C++ Builder
1 ShortInt char
2 SmallInt short, short int
4 Integer, LongInt int, long
8 Int64 __int64

Unsigned Integers

Size Object Pascal C++ Builder
1 Byte BYTE, unsigned short
2 Word unsigned short
4 Cardinal, LongWord unsigned long
1 Boolean bool

Floating Point

Size Object Pascal C++ Builder
4 Single float
8 Double double
10 Extended long double

Variant

Size Object Pascal C++ Builder
16 Variant, OleVariant, TVarData Variant, OleVariant, VARIANT

Strings

Data Type Size Object Pascal C++ Builder
Character 1 Char char
2 WideChar WCHAR
Dynamic String AnsiString AnsiString
Null-Terminated String PChar char *
Null-terminated wide string PWideChar LPCWSTR
Dynamic 2-byte string WideString WideString
Unicode String String String or UnicodeString

Pointer

Data Type Size Object Pascal C++ Builder
Pointer 8 Pointer Void *

Constants

Constant in Object Pascal can be defined as follows:

myConstant = 100;
myConstant : Integer = 100; // Typed constant
strMsg = 'My Message';

Constants can be defined in C++ Builder in the following way:

#define myConstant 100; // Old way
const int myConstant = 100; // New way
const char *strMsg = "My Message";

Operators

Below is a list of Object Pascal operators with their equivalent C++ Builder operator. Note there are more operators in C++ than Object Pascal.

Assignments

Operator Type Object Pascal C++ Builder
Assign := =
Add then Assign (none) +=
Subtract then Assign (none) -=
Multiply then Assign (none) *=
Divide then Assign (none) /=
Modulus then Assign (none) %=
Bitwise And then Assign (none) &=
Bitwise Or then Assign (none) |=
Bitwise Xor then Assign (none) ^=
Bitwise Shl then Assign (none) <<=
Bitwise Shr then Assign (none) >>=

Comparisons

Operator Type Object Pascal C++ Builder
Equal = ==
Not equal <> !=
Greater than > >
Greater than or equal to >= >=
Less than < <
Less than or equal to <= <=

Arithmetic

Operator Type Object Pascal C++ Builder
Add + +
Subtract
Multiply * *
Divide float values / /
Divide integer values Div /
Modulus Mod %
Logical And And &&
Or Or ||
Not Not !

Bitwise

Operator Type Object Pascal C++ Builder
And And &
Or Or |
Xor Xor ^
Not Not ~
Shift to the left Shl <<
Shift to the right Shr >>

Pointers

Operator Type Object Pascal C++ Builder
Deceleration ^Type Type*
Dereferencing Pointer^ *Pointer
Address of variable @Variable &Variable
References Var Type&

Class

Operator Type Object Pascal C++ Builder
Class declaration class class
Structure Declaration Record struct
Scope resolution . ::
Direct access . .
Indirect access (none) ->

Miscellaneous

Operator Type Object Pascal C++ Builder
Increment Inc() ++
Decrement Dec()
String quoting ` "

Also, this is valid C code:

if (a = b) {

It assigns the value of B to A, and if it that value is non null, the expression evaluates to true. It's a really tricky C bug to catch because your brain likes to take shortcuts (Thanks again to C Johnson for this).

Conditional Operators

C++ Builder provide a condition operator ( ? : ) that does not exist in Object Pascal. The syntax of this operator is as follows:

(expression1) ? (expression2) = (expression3)

The operator returns expression2 if expression 1 evaluates to true else it will return expresssion3.

For example…

return ((a > b) ? c : d);

…would be written in Object Pascal as:

If a > b Then
  Result := c
Else
  Result := d;

…or alternatively in C++ Builder as:

if ( a > b )
  return c;
else
  return d;

Pointer Operators

In C++ Builder the indirection operator (*) is similar to Object Pascals ^ operator and is used to declare pointers. The same symbols are also used to dereference pointers. Dereferencing a pointer is the mechanism by which instead of having an address to a memory location you can get the value stored at the memory location.

For example:

int a, b = 8;
int * p = &b; // The pointer p points to the value b
a = *p;       // x gets the value pointed to by p

In Object Pascal you would do the following to achieve the same result:

Var
  a, b : Integer;
  p : ^Integer;

Begin
  b := 8;
  p := @b;
  a := p^;
End;

In the above Object Pascal code the last line of code can also be written as a := p. You can omit the ^ dereference in Object Pascal because the compiler realizes you aren't going to assign a pointer to an integer – but C would treat the code the same way. It's one of the few cases of going from Object Pascal to C being at least as tricky as C to Object Pascal (Thanks to C Johnson for this).

The (*) and (&) operators in C++ Builder are equivalent to the (^) and (@) operators in Object Pascal, respectively. The (&) operator is called an address-of operator; it is used to retrieve the address of a variable. The (&) operator is also used to declare references. A reference is just a special case of a pointer, and you can treat it as a regular object. References are very useful when used to pass parameters to functions. In Object Pascal, parameters passed by reference are also called variable parameters. In this case, the (&) reference operator in C++ Builder is equivalent to the Var keyword in Object Pascal.

Creating and Freeing Objects

In C++ Builder you can declare a variables like this:

char buffer[255];

The buffer is now allocated on the stack and this type of variable is called a local variable. There are two issues with local variables. First: they are destroyed when the function returns and second; the memory size that can be allocated on the stack is limited.

This can be solve by allocating memory from the heap as follows:

char* buffer;
buffer = new char;

Or you can write it in one line, such as:

char* buffer = new char;

With the above you have a variable that can be used everywhere in your program with the size you want.

The only thing you now need to remember is that any memory allocated in this fashion needs to be freed. This is done with the delete operator as follows:

delete buffer;

When working with VCL objects in stead of calling their Create() method to allocate their memory you need to use the new operator and delete them with a delete operator. So for instance you might do the following in Object Pascal:

Var
  sl : TStringList;

Begin
  sl := TStringList.Create;
  Try
    ...
  Finally
    sl.Free;
  End;
End;

In C++ Builder you would achieve the same result with the following code:

TStringList* sl = new TStringList();
try {
  ...
} __finally {
  delete sl;
};

In a comment from Luis Felipe Gonzalez Torres, he stated that it is now good practice to use a “smart pointer” when allocating dynamic objects as follows:

std::unique_ptr sl(new TStringList());
std::unique sl(new TStringList());
/* using the sl instance */
sl->Add("Value1");
sl->Add("Value2");
/* when leave scope, the instance is automatically released */

Controlling Program Flow

C++ Builder like Object Pascal has a number of structures for controlling the branching and looping of your code and these can be categoried as follows:

  • If-Else statements;
  • Switch statements;
  • For loop statements;
  • While and Do-While loop statements.

C++Builder and Object Pascal also have break and continue commands, which are quite similar and break or continue the flow of execution. Below are the side by side comparisons of the Object Pascal and C++ Builder statements.

If Then Else

Object Pascal C++ Builder
If (i = val) Then
    Statement1;
if (i = val)
    Statement1;
If (i = val) Then
    Begin
      Statement1;
      ...;
    End;
if (i = val) {
    Statement1;
    ...;
  }
If (i = val) Then
    Statement1
  Else
    Statement2;
if (i = val)
    Statement1;
  else
    Statement2;
If (i = val) Then
    Begin
      Statement1;
      ...;
    End Else
    Begin
      Statement2;
      ...;
    End;
if (i = val) {
    Statement1;
    ...;
  } else {
    Statement2;
    ...;
  };
If (i = val) Then
    Begin
      Statement1;
      ...;
    End Else
  If (i = val2) Then
    Begin
      Statement2;
      ...;
    End Else
    Begin
      Statement3;
      ...;
    End;
if (i = val) {
    Statement1;
    ...;
  } else if (i = val2) {
    Statement2;
    ...;
  } else {
    Statement3;
    ...;
  };

Case / Switch

Object Pascal C++ Builder
Case iValue Of
  Case 1: SingleStatement;
  Case 2:
    Begin
      MultipleStatement;
      ...;
    End;
Else
  DefaultStatement;
  ...:
End;
switch (iValue) {
  case 1:
    SingleStatement;
    break; // Optional - if omitted next case is run
  case 2:
    MultipleStatement;
    ...;
    break;
default:
  DefaultStatement;
  ...:
};

For

Object Pascal C++ Builder
For i := 0 To Count - 1 Do
  SingleStatement;
for (int i = 0; i < Count; i++)
  SingleStatement;
For i := 0 To Count - 1 Do
  Begin
    MultiStatement;
    ...;
  End;
for (int i = 0; i < Count; i++) {
  MultiStatement;
  ...;
};
For i := Count - 1 DownTo 0 Do
  Begin
    MultiStatement;
    ...;
  End;
for (int i = Count - 1; i >= 0; i--) {
  MultiStatement;
  ...;
};

While

Object Pascal C++ Builder
While (x < y) Do
  SingleStatement;
while (x < y)
  SingleStatement;
While (x < y) Do
  Begin
    MultiStatement;
    ...;
  End;
while (x < y) {
  MultiStatement;
  ...;
};

Repeat / Do While

Object Pascal C++ Builder
repeat
  Statement1;
  ...;
until (x < y);
do {
  Statement1;
  ...;
) while (x < y};

Functions and Procedures

C++ Builder like Object Pascal, function prototypes must be declared before they can be used. Unlike Object Pascal, C++ Builder has no special keywords that are used to declare functions like as Function and Procedure. Below are comparison between the declarations of functions and procedures in the two different languages.

Object Pascal C++ Builder
Procedure Add;
void Add;
Procedure Add(x, y: Integer);
void Add(x, y: Integer);
Function Add: Integer;
int Add();
Function Add (x, y: Integer): Integer;
int Add(int x, y);

Casting

This section looks at casting variables from one type to another in C++ Builder and identifies where possible the equivalent Object Pascal code.

Implicit Casting

Implicit conversions are where a value assigned to one type of variable, say a SmallInt can be converted to another type, say Integer without having to do anything other than using the assignment operator. Where you go from a smaller type to larger type is known as promotion and there will be no loss of precision however going from a larger type to a smaller type (which I presume is called demotion) can lead to a loss of precision.

In Object Pascal the following is an example of implicit casting:

Var
  iSmallInt : SmallInt;
  iInteger  : Integer;
  dblSingle : Single;
  dblDouble : Double;

Begin
  ...
  iSmallInt :=  123;
  iInteger := iSmallInt;
  dblSingle := 123456.789;
  dblDouble := dblSingle;
  ...
End;

The following C++ Builder code achieves the same results.

short iSmallInt = 12345;
int iInteger = iSmallInt;
float dblSingle = 123456.789;
double dblDouble = dblSingle;

The following Object Pascal code would produce a loss of precision but I was surprised that the compiler did not tell me there could be a problem (I switched on all the warnings):

iInteger := 123456789;
iSmallInt := iInteger;
dblDouble := 123456.7890123;
dblSingle := dblDouble;

The following code achieves the same results in C++ Builder however this time the compiler does warn me about the loss of precision:

int iInteger = 123456789;
short iSmallInt = iInteger;
double dblDouble = 123456.78901234;
float dblSingle = dblDouble;

The implicit casting of classes can be controlled using a number of member functions: single-argument constructors which allow implicit conversion from a specific class to your class's type; assignment operator – allows implicit conversion from another type when assigned; and type-cast operator – which allows implicit conversion of your class to a specific type. Below is an example:

class TMyClass {};
class TMyOtherClass {
public:
  TMyOtherClass (const TMyClass& x) {} // conversion from TMyClass (constructor):
  TMyOtherClass& operator= (const TMyClass& x) {return *this;} // conversion from TMyClass (assignment):
  operator TMyClass() {return TMyClass();} // conversion to TMyClass (type-cast operator)
};

int main () {
  TMyClass MyClass;
  TMyOtherClass MyOtherClass = MyClass; // calls constructor
  MyOtherClass = MyClass;               // calls assignment
  MyClass = MyOtherClass;               // calls type-cast operator
  return 0;
}

Note: You can control this better by using the explicit keyword.

Object Pascal supports constructors and the assignment operator but does not have the equivalent of the typr-cast operator.

Explicit Casting

Explicit casting is where the compiler will not allow you to cast from one type to another (I'm exclusing classes from this).

One of the situation I find that I need to use explicit casting is where I want to store an integer or enumerate in the Data member of a string list. This could be a line number in a file or some state information I require to be tracked along with the text.

In Object Pascal I would do one of the following to store an integer or enumerate against a string list item:

Type
  TMyEnumerate = (meFirst, meSecond, meThird, meFourth, meFifth, meSixth);

Var
  slMyStrings : TStringList;
  iInteger : Integer;
  iMyEnumerate : TMyEnumerate;
  strText : String;
  iIndex : Integer;

Begin
  slMyStrings := TStringList.Create;
  Try
    strText := 'Some text...';
    iInteger := 123456;
    iMyEnumerate := meThird;
    slMyStrings.AddObject(strText, TObject(iInteger));
    iIndex := slMyStrings.Add(strText);
    slMyStrings.Objects[iIndex] := TObject(iInteger);
    slMyStrings.AddObject(strText, TObject(iMyEnumerate));
    iIndex := slMyStrings.Add(strText);
    slMyStrings.Objects[iIndex] := TObject(iMyEnumerate);
    For iIndex := 0 To slMyStrings.Count - 1 Do
      WriteLn(iIndex, ') ', slMyStrings[iIndex], ' = ', Integer(slMyStrings.Objects[iIndex]));
  Finally
    slMyStrings.Free;
  End;
End.

The identifical code in C++ Builder is shown below:

int _tmain(int argc, _TCHAR* argv[]) {
  enum TMyEnumerate {meFirst, meSecond, meThird, meFourth, meFifth, meSixth};
  TStringList* slMyStrings;
  int iInteger;
  TMyEnumerate iMyEnumerate;
  String strText;
  int iIndex;
  slMyStrings = new TStringList();
  try {
    strText = "Some text...";
    iInteger = 123456;
    iMyEnumerate = meThird;
    slMyStrings->AddObject(strText, (TObject*)iInteger);
    iIndex = slMyStrings->Add(strText);
    slMyStrings->Objects[iIndex] = (TObject*)iInteger;
    slMyStrings->AddObject(strText, (TObject*)iMyEnumerate);
    iIndex = slMyStrings->Add(strText);
    slMyStrings->Objects[iIndex] = (TObject*)iMyEnumerate;
    for (iIndex = 0; iIndex < slMyStrings->Count; iIndex++)
      printf("%d) %s = %d\n", iIndex, slMyStrings->Strings[iIndex], (Integer)slMyStrings->Objects[iIndex]);
  } __finally {
    delete slMyStrings;
  };
  return 0;
}

Similarly I somethings want to store integer or enumerate data in the Data property of a tree view item or list view item. In Object Pascal I would code the following (assuming Item is a TTreeNode).

Item.Data := Pointer(meThird);
iMyEnumerate := TMyEnumerate(Item.Data);

The same code in C++ Builder would be as below:

Item->Data = (void*)meThird;
iMyEnumerate = (TMyEnumerate)Item->Data;

In C++ Builder you can also explicitly cast some of the values in the same way as in Object pascal as shown below:

TMyEnumerate iMyEnumerate = TMyEnumerate(Item->Data);
int iInteger = int(Item->Data);

Const Casting

This is a strange one which Object Pascal has not equivalence. Essentially you can change a variable from being a constant type variable to an ordinaary variable for the purposes of passing that variable to a function which requires a non-constant variable. If your function only reads the value then all is okay however if your function wants to write to the variable then the operation may have unexpected consequences. For me this just seems the wrong approach and would suggest that there is something fundamentally wrong with my code if I needed this.

void OutputText(char* str) {
  cout << str <<   n ;
}

void DoSomething () {
  const char* strTextConst = "Some Text"; // Constant
  OutputText(const_cast(strTextConst));   // Requires a non-constant
}

Dynamic Casting

This can only be done on pointers and references to classes. It requires Run Time Type Information (RTTI) and can allow you to check whether a reference can be cast to another type. If so the new reference is returned else a NULL value is returned. This can be used to simulate the As and In operators in Object Pascal as shown below:

Var
  ptr : TAction;

Begin
  ...
  If Sender Is TAction Then
    Begin
      ptr := (Sender As TAction);
      ptr.Enabled := True;
    End;
  ...
End;
TAction* ptr = dynamic_cast<TAction*>;(Sender);
if (ptr != NULL)
  ptr->Enabled = true;

Static Casting

Static casting allows you to perform the same conversions as dynamic casting but with out checking the types using RTTI and thus you need to ensure that your code will not produce a bad cast exception. This is eqivalent to the below Object Pascal:

Var
  ptr : TAction;

Begin
  ...
  ptr := TAction(Sender);
  ptr.Enabledd := True;
  ...
End;
TAction* ptr = static_cast<TAction*>(Sender);
if (ptr != NULL)
  ptr->Enabled = true;

It has the benefit of less overhead in your code so would be more preferable in performance code situations.

Reinterpret Casting

This is similar to static casting but the conversion is done at the binary level with absolutely no checking and will be compiler specific.

TAction* ptr = reinterpret_cast<TAction*>(Sender);
if (ptr != NULL)
  ptr->Enabled = true;

Record and Structure Definitions

To be written in a future update.

Class Definitions

From C, C++ inherited the struct keyword, which is almost identical to class and is analogous to Object Pascal's Record keyword. The only difference between structures and classes in C++ Builder is that structure data members and member functions are public by default, whereas a class's they are private by default. This is different to Object Pascal in that a class's members by default are either Public if you have not used the {$M+} compiler directive or Published if you have.

As in Delphi, a class in C++Builder has the following features:

  • Constructors, destructors and methods;
  • Access control to data members and member functions;
  • A reference called this which is equivalent to self in Object Pascal.

One of the most powerful features of classes in C++ is that they can be built using multiple inheritance. Multiple inheritance is when a class is derived from two or more base classes. In Object Pascal, classes can only be derived from a single base class.

Below are some basic class definitions for various types of inheritance:

Object Pascal C++ Builder
TMyClass = Class
  // Published
  Strict Private   // Private
  Strict Protected // Protected
  Publish          // Public
  Published        // Published
End;
class TMyClass {  // no inheritance.
  // Private
  private:   // Private declaration
  protected: // Protected declaration
  public:    // Public declaration
  __publshed // Published declarations
};
TMyClass = Class(TBaseClass1)
  ...
End;
class TMyClass: TBaseClass1 (
  ...
);
N/A
class TMyClass: TBaseClass1, TBaseClass2,  TBaseClass3 (
  ...
);

You will note that I've used the Strict versions of Private and Protected. This is more inline with standard OOP practice as it prevents decendants from being able to access the private members of the class when they shouldn't. The members that have Strict Private visibility are only accessible within the class in which they are declared. They are not visible to procedures or functions declared within the same unit. Members declared with Strict Protected visibility are visible within the class in which they are declared and within any descendant class, regardless of where it is declared. When members (those declared without the class or class var keywords) are declared strict private or strict protected, they are inaccessible outside of the instance of a class in which they appear. An instance of a class cannot access strict protected or strict protected instance members in other instances of the same class.

Constructors and Destructors

In both Object Pascal and C++ Builder each class has a constructor and a destructor. If the you do not write a specific constructor or destructor for the class, the compiler will create default ones. The constructor's main purpose is to allocate space for the members of the class and to initialize those class data members. The destructor's job is to free all the allocated memory created in the constructor and during the life time of the class.

A class can have more than one constructor, but it has only one destructor. Constructors and destructors are just like any other member functions of the class, but they have some special features:

  • They don't return values (not even void in the case of C++ Builder);
  • The constructor in C++ Builder takes the name of the class, and the destructor takes the name of the class preceded by the ~ symbol.

For example:

Object Pascal C++ Builder
TMyClass = Class
Public:
  Constructor Create(); // Constructor
  Destructor Destroy(); // Destructor
End;
class TMyClass {
  Public:
  TMyClass();  // Constructor
  ~TMyClass(); // Destructor
};;

Constructors can take parameters as needed, but destructors take none. They also can't be called as a normal function.

Accessing Data Members and Member Functions

If you have the following simple class:

Object Pascal C++ Builder
TMyClass= Class
Strict Private
  int iSize;
End;
class TMyClass {
private
  int iSize = 20;
};

You can declare it in your program as follows:

Object Pascal C++ Builder
Var
  MyClass : MyClass;
  MyClass2  :TMyClass;

Begin
  MyClass = TMyClass.Create;
  MyClass2 = TMyClass.Create;
  ...
End;
TMyClass MyClass;
TMyClass* MyClass2 = new TMyClass;

MyClass in the C++ Builder example is created on the stack, and MyClass2 is created on the heap. With the Object Pascal version classes are always allocated on the heap. To do a similar stack based allocation you would have to use a modern Object Pascal record structure which can have member functions.

You can access the iSize data member for both of them using the direct access operator, as follows:

Object Pascal C++ builder
MyClass.iSize := 30;
MyClass2.iSize := 30;
MyClass.iSize = 30;
(*MyClass2).iSize = 30;

To make it easier to access data members of classes such as MyClass2 C++ introduced the arrow operator (->). The above statement can be re-written as:

MyClass2->iSize = 30;

The self and this References

Similar to the self reference in Object Pascal, this is a hidden data member in all C++ Builder classes. The following is an example of how to use the this reference in C++ Builder:

__fastcall TMyForm::TMyForm(TComponent* Owner) : TForm(Owner) {
  TLabel *Label1 = new TLabel(this);
  Label1->Parent = this;
  Label1->Caption = this->Width;  // which is equivalent to Form1->Width;
};

Event Signatures

This is one of the things I wanted to do but could find any information in the help files. I try and use events to decouple my classes so that if the classes need to updated another class then that calling class need to hook the event and implement the update.

In Object Pascal I would define an event signature as follows:

TUpdatePathProc = Procedure(Sender : TObject; strPath : String) Of Object;

The equivalent code in C++ builder is as below:

typedef void __fastcall (__closure *TUpdatePathProc)(TObject *Sender, String strPath);

Interface Definitions

To be written in a future update.

#define Directive

Object Pascal does not have an equivalent directive or keyword to the C++ Builder #define directive. If you look back to the section on constants above you can see that it has already been used to define a constant in the old C++ type of coding however the #define directive can also be used to create macros. I believe macros are expanded into in-line instances of the code you define so could be thought of as similar to a function or procedure in Object Pascal that is defined with the inline directive.

#define MAX(X, Y) ((X) > (Y) ? (X) : (Y)
#define MIN(X, Y) ((X) > (Y) ? (Y) : (X)

You use the above as follows:

int a, b, max;
a = 5;
b = 6;
max = MAX(a, b);

Uses and the #include Directive

The #include directive in C++ Builder is used in a very similar manner to the Object Pascal Uses clause and allows you to access the code in another module. Note unlike Object Pascal, C++ code is generally split into a head file corresponding to the Object Pascal Interface section and a CPP file corresponding to the Object Pascal Implementation section.

As such code identified in the header file, like the Interface section of a pascal file can be seen by any other code that includes that header however the code in the CPP file cannot be seen in another file by just including its header file.

During compilation the #include directives will be replaced with the header file to which the directive is referencing. The syntax can take one of the following forms:

#include <headerfile.hpp>
#include “headerfile.hpp”

Exception Handling

To be written in a future update.

After thoughts

Some of this information was found in an old copy of C++ Builder 5 Developer's Guide by Hollingworth, Butterfield, Swart and Allsop, the rest I've had to scrat around the internet to find.

If there are any C++ aficionados out there who believe there are better ways to do any of the above or anyone finds a mistake please let me know.