You are on page 1of 53

Comparing Object-Oriented Features of

Delphi, C++, C# and Java


Contents
• Introduction
• Objects and Classes
• Encapsulation
• Inheritance
• Virtual Methods
• Constructors and Destructors / Finalizers
• Abstract Methods and Classes
• Interfaces
• Method Overloading
• Operator Overloading
• Properties
• Exceptions
• Generics and Templates
• Further Reading

Introduction
This document attempts to compare some of the object oriented features available in the
Delphi, C++, C# and Java programming languages. Introductory paragraphs to each
section to explain the concept being compared in the section are available, but are
designed to be brief, introductory discussions only, not comprehensive definitions. The
primary purpose of these introductory paragraphs is to highlight the differences between
the implementations of the concept in the languages being compared, not to serve as
tutorials explaining the concept being compared.

Unless otherwise noted, all source samples listed below were tested and successfully
compiled with the following tools:

• Delphi: Borland® Delphi™ 7 Enterprise Edition


• C++: Borland® C++Builder Compiler and Command Line Tools free download
(bcc32 v5.5)
• C#: Microsoft® .NET Framework v1.1 SDK
• Java: Java™ 2 SDK, Standard Edition 1.4.2_04

Objects and Classes


A class is a structure that contains data (also known as fields or attributes) and
instructions for manipulating that data (also referred to as methods or behavior). Taken as
a whole, a class should model a real world physical or conceptual object. An object is a
dynamic instance of a class. That is, a class provides a blueprint for an object.

Here are examples for how classes are defined:

Delphi:

Unit1.pas:
unit Unit1;

interface

type
TTest1 = class
public
constructor Create;
destructor Destroy; override;
procedure Method1;
end;

implementation

{ TTest1 }

constructor TTest1.Create;
begin
inherited Create;
//
end;

destructor TTest1.Destroy;
begin
//
inherited Destroy;
end;

procedure TTest1.Method1;
begin
//
end;

end.

C++:

test1.h:
#ifndef Test1_H
#define Test1_H

class Test1 {
public:
Test1(void);
~Test1(void);
void method1(void);
};
#endif // Test1_H

test1.cpp:
#ifndef Test1_H
#include "test1.h"
#endif

Test1::Test1(void)
{
//
}

Test1::~Test1(void)
{
//
}

void Test1::method1(void)
{
//
}

C#:

test1.cs:
public class Test1
{
public Test1() {
//
}

public void Method1() {


//
}
}

Java:

Test1.java:
public class Test1 {
public Test1() {
//
}

public void method1() {


//
}
}

Encapsulation
Encapsulation refers to the hiding of implementation details such that the only way to
interact with an object is through a well-defined interface. This is commonly done by
defining access levels.

Delphi has 4 commonly used access levels for members: private, protected, public and
published. Members marked as private are accessible to the members of the class or any
method defined in the same unit's implementation section. Members marked as protected
are accessible by any method of the class or its descendant units; the descendant units can
be defined in different units. Public members are accessible to all. Published members
behave similar to public members, except the compiler generates extra RunTime Type
Information (RTTI). The default access level is public.

The access to a class is determined by which section of the unit the class is defined in:
classes defined in the interface section are accessible to all, classes defined in the
implementation section are only accessible by methods defined in the same unit.

In addition to these, Delphi.NET introduced the access levels of "strict private" and
"strict protected" which essentially behave the same as the classic private and protected
access levels except unit scope has been removed.

Here is a Delphi code example:

Unit1.pas:
unit Unit1;

interface

type
TTest1 = class
private
FPrivateField: Integer;
protected
procedure ProtectedMethod;
public
constructor Create;
destructor Destroy; override;
procedure PublicMethod;
published
procedure PublishedMethod;
end;

implementation

{ TTest1 }

constructor TTest1.Create;
begin
inherited Create;
//
end;

destructor TTest1.Destroy;
begin
//
inherited Destroy;
end;

procedure TTest1.ProtectedMethod;
begin
//
end;

procedure TTest1.PublicMethod;
begin
//
end;

procedure TTest1.PublishedMethod;
begin
//
end;

end.

C++ defines 3 access levels: private, protected and public. The following definitions are
taken from Bjarne Stroustrup's C++ Glossary:

• private base: a base class declared private in a derived class, so that the base's
public members are accessible only from that derived class.
• private member: a member accessible only from its own class.
• protected base: a base class declared protected in a derived class, so that the base's
public and protected members are accessible only in that derived class and classes
derived from that.
• protected member: a member accessible only from classes derived from its class.
• public base: a base class declared public in a derived class, so that the base's
public members are accessible to the users of that derived class.
• public member: a member accessible to all users of a class.
In addition to these access levels, C++ also has the notion of a friend class and friend
functions:

• friend: a function or class explicitly granted access to members of a class by that


class.
• friend function: a function declared as friend in a class so that it has the same
access as the class' members without having to be within the scope of the class.

Here is a C++ code example:

test1.h:
#ifndef Test1_H
#define Test1_H

class Test1 {
private:
int privateField;
protected:
void protectedMethod(void);
public:
Test1(void);
~Test1(void);
void publicMethod(void);
};
#endif // Test1_H

test1.cpp:
#ifndef Test1_H
#include "test1.h"
#endif

Test1::Test1(void)
{
//
}

Test1::~Test1(void)
{
//
}

void Test1::protectedMethod(void)
{
//
}

void Test1::publicMethod(void)
{
//
}
C# defines 5 access modifiers for class members: private, protected, internal, protected
internal and public. Of these access modifiers, private is the default and members marked
as such are accessible only to the class in which it is defined. A member declared as
protected is accessible to the class wherein it is declared and also in any classes which
derive from that class. The internal access modifier specifies that the member is
accessible to any classes defined in the same assembly. A member declared as protected
internal will be accessible by any derived class as well as any classes defined in the same
assembly. A public member is accessible to all.

The same access modifiers are available for use on classes as well, though private,
protected and protected internal are only applicable to nested classes. The default access
level for a non-nested class if no access modifier is specified is internal. The default
access level for a nested class if no access modifier is specified is private.

Here is a C# code example:

test1.cs:
public class Test1
{
public Test1() {
//
}

private int _privateField;

protected void ProtectedMethod() {


//
}

internal void InternalMethod() {


//
}

protected internal void ProtectedInternalMethod() {


//
}
}

Java defines 4 access levels for class members. The public modifier specifies that the
member is visible to all. The protected modifier specifies that the member is visible to
subclasses and to code in the same package. The private modifier specifies that the
member is visible only to code in the same class. If none of these modifiers are used, then
the default access level is assumed; that is, the member is visible to all code in the
package.
Java also defines the following access modifiers for classes: public, protected and private.
Of these, protected and private are only applicable for nested classes. Declaring a class as
public makes the class accessible to all code. If no access modifier is specified, the
default access level of package level access is assumed.

Here is a Java code example:

Test1.java:
public class Test1 {
public Test1() {
//
}

private int privateField;

protected void protectedMethod() {


//
}

void packageMethod() {
//
}
}

Inheritance
Inheritance refers to the ability to reuse a class to create a new class with added
functionality. The new class, also referred to as the descendant class, derived class or
subclass, is said to inherit the functionality of the ancestor class, base class or superclass.

C++ supports multiple implementation inheritance; that is, a derived class has more than
one immediate base class to inherit its implementation from. In contrast to this, Delphi,
C# and Java support single implementation inheritance, wherein the descendant class or
subclass can only have one direct ancestor class or superclass to inherit its
implementation from. They do, however, support using multiple interface inheritance, an
interface being an abstract type that defines method signatures but do not have an
implementation.

Here are some code examples:

Delphi:

Unit1.pas:
unit Unit1;

interface
type
TBaseClass = class(TInterfacedObject)
public
constructor Create;
destructor Destroy; override;
end;

IFooInterface = interface
procedure Foo;
end;

IBarInterface = interface
function Bar: Integer;
end;

TDerivedClass = class(TBaseClass, IFooInterface, IBarInterface)


procedure Foo;
function Bar: Integer;
end;

implementation

{ TBaseClass }

constructor TBaseClass.Create;
begin
inherited Create;
//
end;

destructor TBaseClass.Destroy;
begin
//
inherited Destroy;
end;

{ TDerivedClass }

procedure TDerivedClass.Foo;
begin
//
end;

function TDerivedClass.Bar: Integer;


begin
Result := 0;
end;

end.

C++:
test1.h:
#ifndef Test1_H
#define Test1_H

class Base1 {
public:
void foo(void);
};

class Base2 {
public:
int bar(void);
};

class DerivedClass : public Base1, public Base2 {


public:
DerivedClass(void);
~DerivedClass(void);
};
#endif // Test1_H

test1.cpp:
#ifndef Test1_H
#include "test1.h"
#endif

void Base1::foo(void)
{
//
}

int Base2::bar(void)
{
return 0;
}

DerivedClass::DerivedClass(void)
{
//
}

DerivedClass::~DerivedClass(void)
{
//
}

C#:
test1.cs:
public class BaseClass
{
public BaseClass() {
//
}
}

public interface IFooInterface


{
void Foo();
}

public interface IBarInterface


{
int Bar();
}

public class DerivedClass : BaseClass, IFooInterface, IBarInterface


{
public void Foo() {
//
}

public int Bar() {


return 0;
}
}

Java:

Test1.java:
class BaseClass {
public BaseClass() {
//
}
}

interface FooInterface {
void foo();
}

interface BarInterface {
int bar();
}
class DerivedClass extends BaseClass implements FooInterface,
BarInterface {
public void foo() {
//
}

public int bar() {


return 0;
}
}

Virtual Methods
Virtual methods allow a method call, at run-time, to be directed to the appropriate code,
appropriate for the type of the object instance used to make the call. In essence, the
method is bound at run-time instead of at compile-time. The method is declared as virtual
in the base class and then overridden in the derived class. Virtual methods are an
important part of polymorphism since the same method call can produce results
appropriate to the object instance used to make the call.

Both Delphi and C# require the overriding code to be explicitly declared as an override.
In C#, the new keyword must be used in derived classes to define a method in the derived
class that hides the base class method. In Java, all methods are virtual by default unless
the method is marked as final. Also, final methods in Java cannot be hidden.

Here is some example code showing the use of virtual methods:

Delphi:

Unit1.pas:
unit Unit1;

interface

type
TBase = class
public
function NonVirtualMethod: string;
function VirtualMethod: string; virtual;
end;

TDerived = class(TBase)
public
function NonVirtualMethod: string;
function VirtualMethod: string; override;
end;

implementation
{ TBase }

function TBase.NonVirtualMethod: string;


begin
Result := 'TBase.NonVirtualMethod';
end;

function TBase.VirtualMethod: string;


begin
Result := 'TBase.VirtualMethod';
end;

{ TDerived }

function TDerived.NonVirtualMethod: string;


begin
Result := 'TDerived.NonVirtualMethod';
end;

function TDerived.VirtualMethod: string;


begin
Result := 'TDerived.VirtualMethod';
end;

end.

Project1.dpr:
program Project1;

{$APPTYPE CONSOLE}

uses
SysUtils,
Unit1 in 'Unit1.pas';

var
Foo, Bar: TBase;

begin
Foo := TBase.Create;
Bar := TDerived.Create;
try
WriteLn(Foo.NonVirtualMethod);
WriteLn(Foo.VirtualMethod);
WriteLn(Bar.NonVirtualMethod);
WriteLn(Bar.VirtualMethod);
finally
Bar.Free;
Foo.Free;
end;
end.
This should produce the following output:

[c:\borland\delphi7\projects]Project1.exe
TBase.NonVirtualMethod
TBase.VirtualMethod
TBase.NonVirtualMethod
TDerived.VirtualMethod

[c:\borland\delphi7\projects]

C++:

test1.h:
#ifndef Test1_H
#define Test1_H

#include <string>

using namespace std;

class Base {
public:
string nonVirtualMethod(void);
virtual string virtualMethod(void);
};

class Derived : public Base {


public:
string nonVirtualMethod(void);
virtual string virtualMethod(void);
};
#endif // Test1_H

test1.cpp:
#ifndef Test1_H
#include "test1.h"
#endif
#include <string>

string Base::nonVirtualMethod(void)
{
string temp = "Base::nonVirtualMethod";
return temp;
}

string Base::virtualMethod(void)
{
string temp = "Base::virtualMethod";
return temp;
}
string Derived::nonVirtualMethod(void)
{
string temp = "Derived::nonVirtualMethod";
return temp;
}

string Derived::virtualMethod(void)
{
string temp = "Derived::virtualMethod";
return temp;
}

main.cpp:
#ifndef Test1_H
#include "test1.h"
#endif
#include <string>
#include <iostream>

using namespace std;

int main()
{
auto_ptr<Base> foo(new Base);
auto_ptr<Base> bar(new Derived);
cout << foo->nonVirtualMethod() << endl;
cout << foo->virtualMethod() << endl;
cout << bar->nonVirtualMethod() << endl;
cout << bar->virtualMethod() << endl;
}

makefile:
# Macros

TOOLSROOT=C:\Borland\BCC55
INCLUDEDIR=$(TOOLSROOT)\Include
LIBDIR=$(TOOLSROOT)\Lib;$(TOOLSROOT)\Lib\PSDK
COMPILER=$(TOOLSROOT)\bin\bcc32.exe
COMPILERSWTS=-tWC -c -I$(INCLUDEDIR)
LINKER=$(TOOLSROOT)\bin\ilink32.exe
LINKERSWTS=-ap -Tpe -x -Gn -L$(LIBDIR)
OBJFILES=test1.obj main.obj
LIBFILES=cw32.lib import32.lib
BASEOUTPUTFILE=main
EXEFILE=$(BASEOUTPUTFILE).exe

#implicit rules
.cpp.obj:
$(COMPILER) $(COMPILERSWTS) $<

# Explicit rules

default: $(EXEFILE)
$(EXEFILE): $(OBJFILES)
$(LINKER) $(LINKERSWTS) c0x32.obj $(OBJFILES),$(EXEFILE),,$
(LIBFILES),,

clean:
del $(OBJFILES)
del $(EXEFILE)
del $(BASEOUTPUTFILE).tds

This should produce the following output:

[c:\borland\bcc55\projects]main.exe
Base::nonVirtualMethod
Base::virtualMethod
Base::nonVirtualMethod
Derived::virtualMethod

[c:\borland\bcc55\projects]

C#:

test1.cs:
using System;

public class BaseClass


{
public string NonVirtualMethod() {
return "BaseClass.NonVirtualMethod";
}

public virtual string VirtualMethod() {


return "BaseClass.VirtualMethod";
}
}

public class DerivedClass : BaseClass


{
new public string NonVirtualMethod() {
return "DerivedClass.NonVirtualMethod";
}

public override string VirtualMethod() {


return "DerivedClass.VirtualMethod";
}
}

public class MainClass


{
public static void Main() {
BaseClass foo = new BaseClass();
BaseClass bar = new DerivedClass();
Console.WriteLine(foo.NonVirtualMethod());
Console.WriteLine(foo.VirtualMethod());
Console.WriteLine(bar.NonVirtualMethod());
Console.WriteLine(bar.VirtualMethod());
}
}

This should produce the following output:

[d:\source\csharp\code]test1.exe
BaseClass.NonVirtualMethod
BaseClass.VirtualMethod
BaseClass.NonVirtualMethod
DerivedClass.VirtualMethod

[d:\source\csharp\code]

Java:

Test1.java:
class BaseClass {
public final String finalMethod() {
return "BaseClass.finalMethod";
}

public String virtualMethod() {


return "BaseClass.virtualMethod";
}
}

class DerivedClass extends BaseClass {


public String virtualMethod() {
return "DerivedClass.virtualMethod";
}
}

public class Test1 {


public static void main(String args[]) {
BaseClass foo = new BaseClass();
BaseClass bar = new DerivedClass();
System.out.println(foo.finalMethod());
System.out.println(foo.virtualMethod());
System.out.println(bar.finalMethod());
System.out.println(bar.virtualMethod());
}
}
This should produce the following output:

[d:\source\java\code]java.exe Test1
BaseClass.finalMethod
BaseClass.virtualMethod
BaseClass.finalMethod
DerivedClass.virtualMethod

[d:\source\java\code]

Constructors And Destructors / Finalizers


Constructors are special methods used to construct an instance of a class. They normally
contain initialization code e.g. code for setting default values for data members,
allocating resources, etc.. The objective of constructors is to allocate memory for the
object and to initialize the object to a valid state before any processing is done.

Destructors serve the opposite purpose of constructors. While constructors take care of
allocating memory and other resources that the object requires during its lifetime, the
destructor's purpose is to ensure that the resources are properly de-allocated as the object
is being destroyed, and the memory being used by the object is freed. In Delphi and C++
(i.e. unmanaged environments) the programmer is responsible for ensuring that an
object's destructor is called once the object is no longer needed.

Finalizers are somewhat similar to destructors but (1) they are non-deterministic, (2) they
are there to release unmanaged resources only. That is, in a managed environment (e.g.
Java Virtual Machine, .NET Common Language Runtime) finalizers are called by the
managed environment, not by the programmer. Hence, there is no way to determine at
which point in time or in which order a finalizer will be called. Also, memory, which is
considered a managed resource, is not freed by the finalizer, but by the garbage collector.
Since most classes written will only be manipulating objects in memory, most objects in
a managed environment will not need a finalizer.

In Delphi, constructors are defined using the constructor keyword and destructors are
defined using the destructor keyword. Delphi, by convention, names its constructor
Create and its destructor Destroy, but these names are not requirements. Also, Delphi
constructors can be made virtual and the default destructor Destroy is virtual. To invoke a
constructor in Delphi, the convention ClassName.ConstructorName is used e.g. if a class
named TMyClass has a constructor Create then constructing an instance is done using
"<variable> := TMyClass.Create;" To invoke the destructor, call the Free method, not the
Destroy method e.g. "<variable>.Free".

In C++, C# and Java, a constructor is defined by creating a method with the same name
as the class. C# and Java require the use of the 'new' keyword to invoke the constructor.
For example, constructing an instance of MyClass is done using "<variable> = new
MyClass()". C++ requires the use of the 'new' keyword if the object is to be allocated on
the heap, otherwise simply declaring a variable of the same type as the class with invoke
the constructor and create the object on the stack. In C++, C# and Java constructors must
be named the same as the name of the class.

Constructors in Delphi do not implicitly call the contructors for the base class. Instead,
the programmer must make an explicit call. In C++, C# and Java, a constructor will
implicitly call the constructors for its base class(es).

Destructors in C# follow the same convention as C++, that is, the destructor must be
named the same as the name of the class, but preceded by a tilde (~). (This syntax often
misleads developers with a C++ background to expect a C# destructor to behave like a
C++ destructor (i.e. it can be called in a deterministic fashion) when in fact it behaves
like a finalizer.) To implement a finalizer in Java, the developer needs only to override
the finalize() method of java.lang.Object.

C++ objects allocated on the stack will automatically have their destructor called when
the object goes out of scope; objects explicitly allocated in the heap using the 'new'
keyword must have its destructor invoked using the 'delete' keyword. While both C#
destructors and Java finalizers are non-deterministic C# destructors are guaranteed to be
called by the .NET CLR (except in cases of an ill-behaved application e.g. one that
crashes, forces the finalizer thread into an infinite loop, etc.) and when they are called,
will in turn implicitly call the other destructors in the inheritance chain, from most
derived class to least derived class. Such is not the case with Java finalizers; finalizers
must explicitly invoke the finalize() method of its superclass and they are not guaranteed
to be invoked.

Delphi, C++, C# and Java all provide default constructors if none are defined in the
current class. All support overloading of constructors.

Delphi:

Unit1.pas:
unit Unit1;

interface

type
TBase = class
constructor Create;
destructor Destroy; override;
end;

TDerived = class(TBase)
constructor Create;
destructor Destroy; override;
end;

TMoreDerived = class(TDerived)
constructor Create;
destructor Destroy; override;
end;

implementation

{ TBase }

constructor TBase.Create;
begin
WriteLn('In TBase.Create');
inherited;
end;

destructor TBase.Destroy;
begin
WriteLn('In TBase.Destroy');
inherited;
end;

{ TDerived }

constructor TDerived.Create;
begin
WriteLn('In TDerived.Create');
inherited;
end;

destructor TDerived.Destroy;
begin
WriteLn('In TDerived.Destroy');
inherited;
end;

{ TMoreDerived }

constructor TMoreDerived.Create;
begin
WriteLn('In TMoreDerived.Create');
inherited;
end;

destructor TMoreDerived.Destroy;
begin
WriteLn('In TMoreDerived.Destroy');
inherited;
end;

end.

Project1.dpr:
program Project1;
{$APPTYPE CONSOLE}

uses
SysUtils,
Unit1 in 'Unit1.pas';

var
Foo: TBase;

begin
Foo := TBase.Create;
Foo.Free;
WriteLn;

Foo := TDerived.Create;
Foo.Free;
WriteLn;

Foo := TMoreDerived.Create;
Foo.Free;
end.

This should produce the following output:

[c:\borland\delphi7\projects]Project1.exe
In TBase.Create
In TBase.Destroy

In TDerived.Create
In TBase.Create
In TDerived.Destroy
In TBase.Destroy

In TMoreDerived.Create
In TDerived.Create
In TBase.Create
In TMoreDerived.Destroy
In TDerived.Destroy
In TBase.Destroy

[c:\borland\delphi7\projects]

C++:

test1.h:
#ifndef Test1_H
#define Test1_H

class Base1 {
public:
Base1(void);
~Base1(void);
};

class Base2 {
public:
Base2(void);
~Base2(void);
};

class Derived : public Base1, public Base2 {


public:
Derived(void);
~Derived(void);
};
#endif // Test1_H

test1.cpp:
#ifndef Test1_H
#include "test1.h"
#endif

#include <iostream>

using std::cout;
using std::endl;

Base1::Base1(void)
{
cout << "In Base1::Base1(void)" << endl;
}

Base1::~Base1(void)
{
cout << "In Base1::~Base1(void)" << endl;
}

Base2::Base2(void)
{
cout << "In Base2::Base2(void)" << endl;
}

Base2::~Base2(void)
{
cout << "In Base2::~Base2(void)" << endl;
}

Derived::Derived(void)
{
cout << "In Derived::Derived(void)" << endl;
}
Derived::~Derived(void)
{
cout << "In Derived::~Derived(void)" << endl;
}

main.cpp:
#ifndef Test1_H
#include "test1.h"
#endif

#include <iostream>

using std::cout;
using std::endl;

int main()
{
Base1 a;
cout << endl;

Base2 b;
cout << endl;

Derived c;
cout << endl;
}

makefile:
# Macros

TOOLSROOT=C:\Borland\BCC55
INCLUDEDIR=$(TOOLSROOT)\Include
LIBDIR=$(TOOLSROOT)\Lib;$(TOOLSROOT)\Lib\PSDK
COMPILER=$(TOOLSROOT)\bin\bcc32.exe
COMPILERSWTS=-tWC -c -I$(INCLUDEDIR)
LINKER=$(TOOLSROOT)\bin\ilink32.exe
LINKERSWTS=-ap -Tpe -x -Gn -L$(LIBDIR)
OBJFILES=test1.obj main.obj
LIBFILES=cw32.lib import32.lib
BASEOUTPUTFILE=main
EXEFILE=$(BASEOUTPUTFILE).exe

#implicit rules
.cpp.obj:
$(COMPILER) $(COMPILERSWTS) $<

# Explicit rules

default: $(EXEFILE)

$(EXEFILE): $(OBJFILES)
$(LINKER) $(LINKERSWTS) c0x32.obj $(OBJFILES),$(EXEFILE),,$
(LIBFILES),,

clean:
del $(OBJFILES)
del $(EXEFILE)
del $(BASEOUTPUTFILE).tds

This should produce the following output:

[c:\borland\bcc55\projects]main.exe
In Base1::Base1(void)

In Base2::Base2(void)

In Base1::Base1(void)
In Base2::Base2(void)
In Derived::Derived(void)

In Derived::~Derived(void)
In Base2::~Base2(void)
In Base1::~Base1(void)
In Base2::~Base2(void)
In Base1::~Base1(void)

[c:\borland\bcc55\projects]

C#:

test1.cs:
using System;

class BaseClass
{
public BaseClass() {
Console.WriteLine("In BaseClass constructor");
}

~BaseClass() {
Console.WriteLine("In BaseClass destructor");
}
}

class DerivedClass: BaseClass


{
public DerivedClass() {
Console.WriteLine("In DerivedClass constructor");
}

~DerivedClass() {
Console.WriteLine("In DerivedClass destructor");
}
}
class MoreDerivedClass: DerivedClass
{
public MoreDerivedClass() {
Console.WriteLine("In MoreDerivedClass constructor");
}

~MoreDerivedClass() {
Console.WriteLine("In MoreDerivedClass destructor");
}
}

public class MainClass


{
public static void Main() {
BaseClass foo = new BaseClass();
Console.WriteLine();

foo = new DerivedClass();


Console.WriteLine();

foo = new MoreDerivedClass();


Console.WriteLine();
}
}

This should produce similar output (results may vary due to the non-deterministic nature
of finalization):

[d:\source\csharp\code]test1.exe
In BaseClass constructor

In BaseClass constructor
In DerivedClass constructor

In BaseClass constructor
In DerivedClass constructor
In MoreDerivedClass constructor

In MoreDerivedClass destructor
In DerivedClass destructor
In BaseClass destructor
In DerivedClass destructor
In BaseClass destructor
In BaseClass destructor

[d:\source\csharp\code]

Java:

Test1.java:
class BaseClass {
public BaseClass() {
System.out.println("In BaseClass constructor");
}

protected void finalize() throws Throwable {


System.out.println("In BaseClass finalize()");
super.finalize();
}
}

class DerivedClass extends BaseClass {


public DerivedClass() {
System.out.println("In DerivedClass constructor");
}

protected void finalize() throws Throwable {


System.out.println("In DerivedClass finalize()");
super.finalize();
}
}

class MoreDerivedClass extends DerivedClass {


public MoreDerivedClass() {
System.out.println("In MoreDerivedClass constructor");
}

protected void finalize() throws Throwable {


System.out.println("In MoreDerivedClass finalize()");
super.finalize();
}
}

public class Test1 {


public static void main(String args[]) {
BaseClass foo = new BaseClass();
System.out.println();

foo = new DerivedClass();


System.out.println();

foo = new MoreDerivedClass();


System.out.println();
}
}

This should produce similar output (results may vary due to the non-deterministic nature
of finalization):

[d:\source\java\code]java.exe Test1
In BaseClass constructor
In BaseClass constructor
In DerivedClass constructor

In BaseClass constructor
In DerivedClass constructor
In MoreDerivedClass constructor

[d:\source\java\code]

Abstract Methods and Classes


An abstract method is a method which the class does not implement. In C++ terminology,
such a method is termed a pure virtual function. A class which contains one or more
abstract methods is often called an abstract class although in some cases the term abstract
class is reserved for classes that contains only abstract methods. Abstract classes cannot
be instantiated. Classes which derive from an abstract class should override and provide
implementations for the abstract methods, or should themselves be marked also as
abstract. Delphi uses the abstract keyword to mark a method as abstract. C# and Java use
the abstract keyword to mark a method or class as abstract. A class marked as abstract is
permitted but not required to have abstract members. C++ uses the =0 notation to indicate
that a virtual function is a pure virtual function.

Delphi:

Unit1.pas:
unit Unit1;

interface

type
TAbstractBaseClass = class
public
procedure Method1; virtual; abstract;
end;

TAbstractIntermediateClass = class(TAbstractBaseClass)
public
procedure Method1; override; abstract;
procedure Method2; virtual;
end;

TConcreteClass = class(TAbstractIntermediateClass)
public
procedure Method1; override;
end;

implementation

{ TAbstractIntermediateClass }
procedure TAbstractIntermediateClass.Method2;
begin
//
end;

{ TConcreteClass }

procedure TConcreteClass.Method1;
begin
inherited Method1;
//
end;

end.

C++:

test1.h:
#ifndef Test1_H
#define Test1_H

class AbstractBaseClass {
public:
virtual void method1(void)=0;
};

class AbstractIntermediateClass : public AbstractBaseClass {


public:
virtual void method1(void)=0;
virtual void method2(void);
};

class ConcreteClass : public AbstractIntermediateClass {


public:
virtual void method1(void);
};
#endif // Test1_H

test1.cpp:
#ifndef Test1_H
#include "test1.h"
#endif

void AbstractIntermediateClass::method2(void)
{
//
}
void ConcreteClass::method1(void)
{
//
}

C#:

test1.cs:
public abstract class AbstractBaseClass
{
public abstract void Method1();
}

public abstract class AbstractIntermediateClass : AbstractBaseClass


{
public override abstract void Method1();

public virtual void Method2() {


//
}
}

public class ConcreteClass : AbstractBaseClass


{
public override void Method1() {
//
}
}

Java:

Test1.java:
abstract class AbstractBaseClass {
public abstract void method1();
}

abstract class AbstractIntermediateClass extends AbstractBaseClass {


public abstract void method1();

public void method2() {


//
}
}
class ConcreteClass extends AbstractIntermediateClass {
public void method1() {
//
}
}

Interfaces
An interface is an abstract type that defines members but does not provide an
implementation. Interfaces are used to define a contract; a class that implements an
interface is expected to adhere to the contract provided by the interface and provide
implementations for all the members defined in the interface. Delphi, C# and Java
support interfaces. C++ does not though an abstract class composed purely of public pure
virtual methods could serve a similar purpose.

(See the earlier section on inheritance for code examples of interfaces.)

Method Overloading
Method overloading refers to the ability to define several methods with the same name
but with different signatures (parameter types, number of parameters). Delphi requires
that overloaded methods be marked with the overload keyword.

Delphi:

Unit1.pas:
unit Unit1;

interface

type
TFoo = class
public
procedure MethodA;
end;

TBar = class(TFoo)
public
procedure MethodA(const I: Integer); overload;
procedure MethodB(const I: Integer); overload;
procedure MethodB(const I: Integer; const S: string); overload;
end;

TFooBar = class(TBar)
public
procedure MethodA(const S: string); overload;
function MethodC(const I: Integer): Integer; overload;
function MethodC(const S: string): Integer; overload;
end;

implementation

{ TFoo }

procedure TFoo.MethodA;
begin
//
end;

{ TBar }

procedure TBar.MethodB(const I: Integer);


begin
//
end;

procedure TBar.MethodB(const I: Integer; const S: string);


begin
//
end;

procedure TBar.MethodA(const I: Integer);


begin
//
end;

{ TFooBar }

procedure TFooBar.MethodA(const S: string);


begin
//
end;

function TFooBar.MethodC(const I: Integer): Integer;


begin
Result := 0;
end;

function TFooBar.MethodC(const S: string): Integer;


begin
Result := 0;
end;

end.

C++:

test1.h:
#ifndef Test1_H
#define Test1_H

#include <string>

using namespace std;

class Foo {
public:
void methodA(void);
};

class Bar : public Foo {


public:
void methodA(int);
void methodB(int);
void methodB(int, string);
};

class FooBar : public Bar {


public:
void methodA(string);
int methodC(int);
int methodC(string);
};
#endif // Test1_H

test1.cpp:
#ifndef Test1_H
#include "test1.h"
#endif
#include <string>

void Foo::methodA(void)
{
//
}

void Bar::methodA(int i)
{
//
}

void Bar::methodB(int i)
{
//
}

void Bar::methodB(int i, string s)


{
//
}
void FooBar::methodA(string s)
{
//
}

int FooBar::methodC(int i)
{
return 0;
}

int FooBar::methodC(string s)
{
return 0;
}

C#:

test1.cs:
public class Foo
{
public void MethodA() {
//
}
}

public class Bar : Foo


{
public void MethodA(int i) {
//
}

public void MethodB(int i) {


//
}

public void MethodB(int i, string s) {


//
}
}

public class FooBar : Bar


{
public void MethodA(string s) {
//
}

public int MethodC(int i) {


return 0;
}
public int MethodC(string s) {
return 0;
}
}

Java:

Test1.java:
class Foo {
public void methodA() {
//
}
}

class Bar extends Foo {


public void methodA(int i) {
//
}

public void methodB(int i) {


//
}

public void methodB(int i, String s) {


//
}
}

class FooBar extends Bar {


public void methodA(String s) {
//
}

public int methodC(int i) {


return 0;
}

public int methodC(String s) {


return 0;
}
}

Operator Overloading
Operator overloading is the process of providing new implementations for built-in
operators (such as '+' and '-' for example) when the operands are user-defined types such
as classes. This can simplify the usage of a class and make it more intuitive.
Operator overloading is available in C++ and C# and has recently been added into
Delphi.NET. It is not available in the current Win32 implementation of Delphi, nor is it
available in Java.

The following examples create a simple class for manipulating complex numbers. It
overloads the '+' and '-' operators.

Delphi.NET:

Unit1.pas:
unit Unit1;

interface

type
TComplexNumber = class
public
Real: Integer;
Imaginary: Integer;
class operator Add(const X, Y: TComplexNumber): TComplexNumber;
class operator Subtract(const X, Y: TComplexNumber): TComplexNumber;
function ToString: string; override;
constructor Create(const Real, Imaginary: Integer);
end;

implementation

uses
SysUtils;

{ TComplexNumber }

constructor TComplexNumber.Create(const Real, Imaginary: Integer);


begin
inherited Create;
Self.Real := Real;
Self.Imaginary := Imaginary;
end;

class operator TComplexNumber.Add(const X,


Y: TComplexNumber): TComplexNumber;
begin
Result := TComplexNumber.Create(X.Real + Y.Real, X.Imaginary +
Y.Imaginary);
end;

class operator TComplexNumber.Subtract(const X,


Y: TComplexNumber): TComplexNumber;
begin
Result := TComplexNumber.Create(X.Real - Y.Real, X.Imaginary -
Y.Imaginary);
end;
function TComplexNumber.ToString: string;
begin
if (Self.Imaginary > 0) then
Result := Format('%d + %di', [Self.Real, Self.Imaginary])
else
Result := Format('%d - %di', [Self.Real, Abs(Self.Imaginary)]);
end;

end.

Project1.dpr:
program Project1;

{$APPTYPE CONSOLE}

uses
SysUtils,
Unit1 in 'Unit1.pas';

var
A, B: TComplexNumber;

begin
A := TComplexNumber.Create(2, 5);
B := TComplexNumber.Create(4, -3);
WriteLn(Format('A = (%s), B = (%s)', [A, B]));
WriteLn(Format('A + B = (%s)', [A + B]));
WriteLn(Format('A - B = (%s)', [A - B]));
end.

This should produce the following output:

[d:\source\delphi.net\code]Project1.exe
A = (2 + 5i), B = (4 - 3i)
A + B = (6 + 2i)
A - B = (-2 + 8i)

[d:\source\delphi.net\code]

C++:

test1.h:
#ifndef Test1_H
#define Test1_H

#include <string>

using namespace std;


class ComplexNumber {
public:
int real;
int imaginary;
ComplexNumber operator+(const ComplexNumber&) const;
ComplexNumber operator-(const ComplexNumber&) const;
virtual string toString(void) const;
ComplexNumber(int, int);
};
#endif // Test1_H

test1.cpp:
#ifndef Test1_H
#include "test1.h"
#endif
#include <string>
#include <sstream>
#include <cmath>

using namespace std;

string itos(int i)
{
stringstream s;
s << i;
return s.str();
}

ComplexNumber::ComplexNumber(int real = 0, int imaginary = 0)


{
this->real = real;
this->imaginary = imaginary;
}

ComplexNumber ComplexNumber::operator+(const ComplexNumber& param) const


{
ComplexNumber temp;
temp.real = this->real + param.real;
temp.imaginary = this->imaginary + param.imaginary;
return temp;
}

ComplexNumber ComplexNumber::operator-(const ComplexNumber& param) const


{
ComplexNumber temp;
temp.real = this->real - param.real;
temp.imaginary = this->imaginary - param.imaginary;
return temp;
}

string ComplexNumber::toString() const


{
if (this->imaginary > 0)
return itos(real) + " + " + itos(imaginary) + "i";
else
return itos(real) + " - " + itos(abs(imaginary)) + "i";
}

main.cpp:
#ifndef Test1_H
#include "test1.h"
#endif
#include <iostream>

using namespace std;

int main()
{
ComplexNumber a (2, 5);
ComplexNumber b (4, -3);
cout << "a = (" << a.toString() << "), b = (" << b.toString() << ")"
<< endl;
cout << "a + b = (" << (a + b).toString() << ")" << endl;
cout << "a - b = (" << (a - b).toString() << ")" << endl;
}

makefile:
# Macros

TOOLSROOT=C:\Borland\BCC55
INCLUDEDIR=$(TOOLSROOT)\Include
LIBDIR=$(TOOLSROOT)\Lib;$(TOOLSROOT)\Lib\PSDK
COMPILER=$(TOOLSROOT)\bin\bcc32.exe
COMPILERSWTS=-tWC -c -I$(INCLUDEDIR)
LINKER=$(TOOLSROOT)\bin\ilink32.exe
LINKERSWTS=-ap -Tpe -x -Gn -L$(LIBDIR)
OBJFILES=test1.obj main.obj
LIBFILES=cw32.lib import32.lib
BASEOUTPUTFILE=main
EXEFILE=$(BASEOUTPUTFILE).exe

#implicit rules
.cpp.obj:
$(COMPILER) $(COMPILERSWTS) $<

# Explicit rules

default: $(EXEFILE)

$(EXEFILE): $(OBJFILES)
$(LINKER) $(LINKERSWTS) c0x32.obj $(OBJFILES),$(EXEFILE),,$
(LIBFILES),,

clean:
del $(OBJFILES)
del $(EXEFILE)
del $(BASEOUTPUTFILE).tds
This should produce the following output:

[c:\borland\bcc55\projects]main.exe
a = (2 + 5i), b = (4 - 3i)
a + b = (6 + 2i)
a - b = (-2 + 8i)

[c:\borland\bcc55\projects]

C#:

test1.cs:
using System;

class ComplexNumber
{
public int Real;
public int Imaginary;

public ComplexNumber(int real, int imaginary) {


this.Real = real;
this.Imaginary = imaginary;
}

public static ComplexNumber operator +(ComplexNumber a, ComplexNumber


b) {
return new ComplexNumber(a.Real + b.Real, a.Imaginary +
b.Imaginary);
}

public static ComplexNumber operator -(ComplexNumber a, ComplexNumber


b) {
return new ComplexNumber(a.Real - b.Real, a.Imaginary -
b.Imaginary);
}

public override string ToString() {


if (this.Imaginary > 0)
return (string.Format("{0} + {1}i", this.Real, this.Imaginary));
else
return (string.Format("{0} - {1}i", this.Real,
Math.Abs(this.Imaginary)));
}
}

public class MainClass


{
public static void Main() {
ComplexNumber a = new ComplexNumber(2, 5);
ComplexNumber b = new ComplexNumber(4, -3);
Console.WriteLine(string.Format("a = ({0}), b = ({1})", a, b));
Console.WriteLine(string.Format("a + b = ({0})", a + b));
Console.WriteLine(string.Format("a - b = ({0})", a - b));
}
}

This should produce the following output:

[d:\source\csharp\code]test1.exe
a = (2 + 5i), b = (4 - 3i)
a + b = (6 + 2i)
a - b = (-2 + 8i)

[d:\source\csharp\code]

Properties
Properties can be described as object-oriented data members. External to the class,
properties look just like data members. Internally, however, properties can be
implemented as methods. Properties promote encapsulation by allowing the class to hide
the internal representation of its data. Also, by implementing only a getter (also known as
an accessor) method or a setter (also known as a mutator) method, a property can be
made read-only or write-only respectively, thus allowing the class to provide access
control.

Delphi and C# have support for properties built into the language. C++ and Java do not
have support for properties built in but can loosely implement this behavior using a
get/set convention.

Delphi:

Unit1.pas:
unit Unit1;

interface

type
TRectangle = class
private
FHeight: Cardinal;
FWidth: Cardinal;
protected
function GetArea: Cardinal;
public
function ToString: string; virtual;
constructor Create(const Width, Height: Cardinal);
property Area: Cardinal read GetArea;
property Height: Cardinal read FHeight write FHeight;
property Width: Cardinal read FWidth write FWidth;
end;

implementation

uses
SysUtils;

{ TRectangle }

constructor TRectangle.Create(const Width, Height: Cardinal);


begin
inherited Create;
FHeight := Height;
FWidth := Width;
end;

function TRectangle.GetArea: Cardinal;


begin
Result := FWidth * FHeight;
end;

function TRectangle.ToString: string;


begin
Result := Format('Height: %d, Width: %d, Area: %d', [Height, Width,
Area]);
end;

end.

Project1.dpr:
program Project1;

{$APPTYPE CONSOLE}

uses
SysUtils,
Unit1 in 'Unit1.pas';

begin
with TRectangle.Create(2, 3) do
try
WriteLn(ToString);
Height := 4;
Width := 3;
WriteLn(ToString);
finally
Free;
end;
end.

This should produce the following output:


[c:\borland\delphi7\projects]Project1.exe
Height: 3, Width: 2, Area: 6
Height: 4, Width: 3, Area: 12

[c:\borland\delphi7\projects]

C#:

test1.cs:
using System;

class Rectangle
{
private uint _height;
private uint _width;

public Rectangle(uint width, uint height) {


_width = width;
_height = height;
}

public uint Area {


get { return _width * _height; }
}

public uint Height {


get { return _height; }
set { _height = value; }
}

public uint Width {


get { return _width; }
set { _width = value; }
}

public override string ToString() {


return string.Format("Height: {0}, Width: {1}, Area: {2}", Height,
Width, Area);
}
}

public class MainClass


{
public static void Main() {
Rectangle MyRectangle = new Rectangle(2, 3);
Console.WriteLine(MyRectangle);
MyRectangle.Height = 4;
MyRectangle.Width = 3;
Console.WriteLine(MyRectangle);
}
}
This should produce the following output:

[d:\source\csharp\code]test1.exe
Height: 3, Width: 2, Area: 6
Height: 4, Width: 3, Area: 12

[d:\source\csharp\code]

Exceptions
Exceptions provide a uniform mechanism for handling errors. Exceptions are created and
raised or thrown when the code enters a condition that it cannot or should not handle by
itself. Once the exception is raised or thrown, the exception handling mechanism breaks
out of the normal flow of code execution and searches for an appropriate exception
handler. If an appropriate exception handler is found, then the error condition is handled
in an appropriate manner and normal code execution resumes. Otherwise, the application
is assumed to be in an unstable / unpredictable state and exits with an error.

Delphi provides the raise keyword to create an exception and a try...except and
try...finally construct (but no unified try...except...finally construct though a try...finally
block can be nested within a try...except block to emulate this behavior) for exception
handling. Code written in a try block is executed and if an exception occurs, the
exception handling mechanism searches for an appropriate except block to handle the
exception. The on keyword is used to specify which exceptions an except block can
handle. A single except block can contain multiple on keywords. If the on keyword is not
used, then the except block will handle all exceptions. Code written in a finally block is
guaranteed to execute regardless of whether or not an exception is raised.

Unit1.pas:
unit Unit1;

interface

uses
SysUtils;

type
EMyException = class(Exception);

TMyClass = class
public
procedure MyMethod;
constructor Create;
destructor Destroy; override;
end;

implementation

{ TMyClass }
procedure TMyClass.MyMethod;
begin
WriteLn('Entering TMyClass.MyMethod');
raise EMyException.Create('Exception raised in TMyClass.MyMethod!');
WriteLn('Leaving TMyClass.MyMethod'); // this should never get
executed
end;

constructor TMyClass.Create;
begin
inherited Create;
WriteLn('In TMyClass.Create');
end;

destructor TMyClass.Destroy;
begin
WriteLn('In TMyClass.Destroy');
inherited Destroy;
end;

end.

Project1.dpr:
program Project1;

{$APPTYPE CONSOLE}

uses
SysUtils,
Unit1 in 'Unit1.pas';

var
MyClass: TMyClass;

begin
MyClass := TMyClass.Create;
try
try
MyClass.MyMethod;
except
on EMyException do
WriteLn(ErrOutput, 'Caught an EMyException!');
end;
finally
MyClass.Free;
end;
end.

This should produce the following output:

[c:\borland\delphi7\projects]Project1.exe
In TMyClass.Create
Entering TMyClass.MyMethod
Caught an EMyException!
In TMyClass.Destroy

[c:\borland\delphi7\projects]

C++ provides the throw keyword for creating an exception and provides a try...catch
construct for exception handling. Code written in the try block is executed and if an
exception is thrown, the exception handling mechanism looks for an appropriate catch
block to deal with the exception. A single try block can have multiple catch blocks
associated with it. Catch blocks have a required exception declaration to specify what
type of exception it can handle. An exception declaration of (...) means that the catch
block will catch all exceptions.

A function can optionally specify what exceptions it can throw via an exception
specification in the function declaration. The throw keyword is also used for this purpose.
If no exception specification is present then the function can throw any exception.

test1.h:
#ifndef Test1_H
#define Test1_H

#include <string>

using std::string;

class MyException {
public:
MyException(string);
string getMessage() const;
private:
string message;
};

class MyClass {
public:
MyClass();
~MyClass();
void myMethod();
};
#endif // Test1_H

test1.cpp:
#ifndef Test1_H
#include "test1.h"
#endif

#include <iostream>

using std::cout;
using std::endl;

MyException::MyException(string errorMessage)
{
message = errorMessage;
}

string MyException::getMessage() const


{
return message;
}

MyClass::MyClass()
{
cout << "In MyClass::MyClass()" << endl;
}

MyClass::~MyClass()
{
cout << "In MyClass::~MyClass()" << endl;
}

void MyClass::myMethod()
{
cout << "Entering MyClass::myMethod()" << endl;
throw MyException("Exception thrown in MyClass::myMethod()!");
cout << "Leaving MyClass::myMethod()" << endl; // this should never
get executed
}

main.cpp:
#ifndef Test1_H
#include "test1.h"
#endif

#include <iostream>

using std::cerr;
using std::endl;

int main()
{
MyClass myClass;
try {
myClass.myMethod();
}
catch(MyException) {
cerr << "Caught a MyException!" << endl;
}
}

makefile:
# Macros
TOOLSROOT=C:\Borland\BCC55
INCLUDEDIR=$(TOOLSROOT)\Include
LIBDIR=$(TOOLSROOT)\Lib;$(TOOLSROOT)\Lib\PSDK
COMPILER=$(TOOLSROOT)\bin\bcc32.exe
COMPILERSWTS=-tWC -c -I$(INCLUDEDIR)
LINKER=$(TOOLSROOT)\bin\ilink32.exe
LINKERSWTS=-ap -Tpe -x -Gn -L$(LIBDIR)
OBJFILES=test1.obj main.obj
LIBFILES=cw32.lib import32.lib
BASEOUTPUTFILE=main
EXEFILE=$(BASEOUTPUTFILE).exe

#implicit rules
.cpp.obj:
$(COMPILER) $(COMPILERSWTS) $<

# Explicit rules

default: $(EXEFILE)

$(EXEFILE): $(OBJFILES)
$(LINKER) $(LINKERSWTS) c0x32.obj $(OBJFILES),$(EXEFILE),,$
(LIBFILES),,

clean:
del $(OBJFILES)
del $(EXEFILE)
del $(BASEOUTPUTFILE).tds

This should produce the following output:

[c:\borland\bcc55\projects]main.exe
In MyClass::MyClass()
Entering MyClass::myMethod()
Caught a MyException!
In MyClass::~MyClass()

[c:\borland\bcc55\projects]

C# uses the throw keyword to throw an exception and provides try...catch, try...finally
and try...catch...finally constructs for exception handling. Code in the try block is
executed and if an exception is thrown, the exception handling mechanism searches for
an appropriate catch block. A single try block can have multiple catch blocks associated
with it. A catch block can declare the exception type that it handles. If a catch clause does
not specify the exception type it will catch all exceptions thrown. Code in a finally block
will be executed regardless of whether or not an exception is thrown.

using System;

class MyException: Exception { };


class MyClass
{
public MyClass() {
Console.WriteLine("In MyClass.MyClass()");
}

~MyClass() {
Console.WriteLine("In MyClass.~MyClass()");
}

public void MyMethod() {


Console.WriteLine("Entering MyClass.MyMethod()");
throw new MyException();
Console.WriteLine("Leaving MyClass.MyMethod()"); // this should
never get executed
}
}

public class MainClass


{
public static void Main() {
MyClass myClass = new MyClass();
try {
myClass.MyMethod();
}
catch (MyException) {
Console.Error.WriteLine("Caught a MyException!");
}
finally {
Console.WriteLine("In finally block"); // will always get executed
}
}
}

This should produce similar output:

[d:\source\csharp\code]test1.exe
In MyClass.MyClass()
Entering MyClass.MyMethod()
Caught a MyException!
In finally block
In MyClass.~MyClass()

[d:\source\csharp\code]

Java uses the throw keyword to throw an exception and provides try...catch, try...finally
and try...catch...finally constructs for exception handling. Code inside a try block is
executed and if an exception is thrown, the exception handling mechanism searches for
an appropriate catch block. A single try block can have multiple catch blocks associated
with it. Catch blocks are required to specify the exception type that they handle. Code in
a finally block will be executed regardless of whether or not an exception is thrown.

Java also requires that methods either catch or specify all checked exceptions that can be
thrown within the scope of the method. This is done using the throws clause of the
method declaration.

Test1.java:
class MyException extends Exception { };

class MyClass {
public MyClass() {
System.out.println("In MyClass.MyClass()");
}
protected void finalize() throws Throwable {
System.out.println("In MyClass.finalize()");
}
public void myMethod() throws MyException {
System.out.println("Entering myClass.myMethod()");
throw new MyException();
}
}

public class Test1 {


public static void main(String args[]) {
MyClass myClass = new MyClass();
try {
myClass.myMethod();
}
catch(MyException e) {
System.err.println("Caught a MyException!");
}
finally {
System.out.println("In finally block"); // will always get
executed
}
}
}

This should produce similar output:

[d:\source\java\code]java.exe Test1
In MyClass.MyClass()
Entering myClass.myMethod()
Caught a MyException!
In finally block

[d:\source\java\code]
Generics and Templates
Templates and Generics are constructs for parametric polymorphism. That is, they make
creating parameterized types for creating type safe collections. However, they do not
refer to the same thing i.e. templates are not generics and generics are not templates. For
more information on what the differences are, refer to the following external links:

• C++ Potential: Templates and Generics


• Generics in C#, Java, and C++

Currently, only the C++ language supports templates. Generic support is planned for
version 2.0 of the C# language and for version 1.5 of the Java language.

C++:

stacktemplate.h:
#ifndef StackTemplate_H
#define StackTemplate_H

#define EMPTYSTACK -1

template<class T>
class Stack {
public:
Stack(int);
~Stack();
bool push(const T&);
bool pop(T&);
private:
bool isEmpty() const;
bool isFull() const;
int stackSize;
int stackTop;
T* stackPtr;
};

template<class T>
Stack<T>::Stack(int maxStackSize)
{
stackSize = maxStackSize;
stackTop = EMPTYSTACK;
stackPtr = new T[stackSize];
}

template<class T>
Stack<T>::~Stack()
{
delete [] stackPtr;
}

template<class T>
bool Stack<T>::push(const T& param)
{
if (!isFull()) {
stackPtr[++stackTop] = param;
return true;
}
return false;
}

template<class T>
bool Stack<T>::pop(T& param)
{
if (!isEmpty()) {
param = stackPtr[stackTop--];
return true;
}
return false;
}

template<class T>
bool Stack<T>::isEmpty() const
{
return stackTop == EMPTYSTACK;
}

template<class T>
bool Stack<T>::isFull() const
{
return stackTop == stackSize - 1;
}

#endif

main.cpp:
#ifndef StackTemplate_H
#include "stacktemplate.h"
#endif
#include <iostream>

using std::cout;
using std::endl;

int main()
{
Stack<int> intStack (5);
int i = 2;
while(intStack.push(i)) {
cout << "pushing " << i << " onto intStack" << endl;
i += 2;
}
while(intStack.pop(i)) {
cout << "popped " << i << " from intStack" << endl;
}
cout << endl;

Stack<float> floatStack (5);


float f = 2.1;
while(floatStack.push(f)) {
cout << "pushing " << f << " onto floatStack" << endl;
f += 2.1;
}
while(floatStack.pop(f)) {
cout << "popping " << f << " from floatStack" << endl;
}
}

This should produce the following output:

[c:\borland\bcc55\projects]main.exe
pushing 2 onto intStack
pushing 4 onto intStack
pushing 6 onto intStack
pushing 8 onto intStack
pushing 10 onto intStack
popped 10 from intStack
popped 8 from intStack
popped 6 from intStack
popped 4 from intStack
popped 2 from intStack

pushing 2.1 onto floatStack


pushing 4.2 onto floatStack
pushing 6.3 onto floatStack
pushing 8.4 onto floatStack
pushing 10.5 onto floatStack
popping 10.5 from floatStack
popping 8.4 from floatStack
popping 6.3 from floatStack
popping 4.2 from floatStack
popping 2.1 from floatStack

[c:\borland\bcc55\projects]

Further Reading
For more information, refer to the following links:

• Delphi:
o Delphi Basics : http://www.delphibasics.co.uk/
o Object Pascal Style Guide:
http://community.borland.com/soapbox/techvoyage/article/1,1795,10280,0
0.html
• C++:
o Bjarne Stroustrup's homepage - The C++ Programming Language:
http://www.research.att.com/~bs/C++.html
• C#:
o MSDN - C# Language Specification:
http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/csspec/html/CSharpSpecStart.asp
o Standard ECMA-334 - C# Language Specification 2nd edition (December
2002): http://www.ecma-international.org/publications/standards/Ecma-
334.htm
• Java:
o Code Conventions for the Java™ Programming Language:
http://java.sun.com/docs/codeconv/html/CodeConvTOC.doc.html
o The Java Language Specification: http://java.sun.com/docs/books/jls/

You might also like