Taligent Logo
Porting Paper
dot_clear
dot_clear

Java Cookbook: Porting C++ to Java

Basics

Introduction, Basics, Next Steps, Well-Mannered Objects, Esoterica, Background, Index


The following sections take you through the main steps necessary to convert your program from C++ to Java.


Placement is Everything

Before you start porting, first create the directory structure that you will use. First, figure out what your main package name is. To get it, take your domain name and reverse the fields. Thus xyz.com becomes com.xyz. If you have two directories abc and def for your project, then their packages become com.xyz.abc and com.xyz.def. Now create directories that correspond to this structure, and copy all of your sources to the appropriate directory.

  • com
    • xyz
      • abc
        • class1.java
        • class2.java
      • def
        • class3.java
        • class4.java

The first thing you will notice is that Java does not distinguish between class interface (declaration) and implementation (definition) as C++ does. Rename your header file extensions to be .java. Then take the implementation of each member and copy it in after the declaration of that member, as if you were doing an inline method in C++.

The second step is to take all of the access keywords (public, protected, private), and copy them at the front of each of the succeeding methods and fields that they pertain to. Change the inheritance syntax to use extends instead of a colon. If you use multiple inheritance, see Primogenitur Entail.

Finally, break apart each class into a separate file, and at the top of the class, put your package name, and a list of imports. These imports should be a list of all the other packages that you need to access.

Fixing Basic Structure

C++

inlined C++

Java

// file.h
 

 
 
class Foo :: Bar {
 public:
 
  int square();
 
 
  int cube();
 
 
 private:
  int x;
}
 
// file.c (or .cpp)
 
int Foo::square() {
  return x*x;
}
 
int Foo::cube() {
  return x*x*x;
}
 // file.h
 
 
 

class Foo :: Bar {
public:
 
 int square() {
   return x*x};
 
 int cube() {
  return x*x*x;
 }
 private:
 int x;
}
// file.java
package com.xyz.abc;
import com.xyz.abc.*;
import com.xyz.def.*;
 
class Foo extends Bar {
 
 
 public int square() {
   return x*x};
 
 public int cube() {
  return x*x*x;
 }
 
 private int x;
}

 

Notes

  • Java does not have the notion of friend as in C++. See Java has no friends for more information about how to handle this.
  • Java 1.1 does have nested classes, though Java 1.1 does not. If you cannot wait for 1.1, you will have to move your nested classes out to the top. We suggest using concatenating the names: for a nested class Foo in a class Bar, use Bar_Foo.


To protect the innocent

Next, you need to change a few names. There are a few cases where there is a relatively straightforward name change.

Simple Name Replacements

C++

Java

bool x = true;
boolean x = true;

Most name differences, however, depend on the context.

Context-Dependent Name Replacements

C++

Java

// const field 
static const int x = 3;
 
// const method 
int doSomething() const;
 
// character data
char ch = 'b';
 
// byte data (e.g. short numbers)
char b = 31;
 
// abstract method
int someMethod() = 0;
 
// non-virtual method
int someMethod();
 
// virtual method
virtual int someMethod();

// unknown object (no primative)
void* doAnother() {}
// const field
static final int x = 3;
 
// const method
int doSomething();
 
// character data
char ch = 'b';
 
// byte data
byte b = 31;
 
// abstract method
abstract int someMethod();
 
// non-virtual method
final int someMethod();
 
// virtual method
int someMethod();

// unknown object
Object doAnother() {}

Notes

  • Const, in particular, requires very special handling, and is discussed in detail in Bullet-proofing. The simplest approach at the start is to change it to final for any field, and remove it otherwise.
  • C and C++ do not distinguish between char as a small number or as a piece of character data; in general, though, it usually corresponds to character data and can be left alone. It is also discussed at more length below.
  • Put final in front of every method that doesn't contain the word virtual, then delete all instances of virtual. There is one complication; in C++, if a method is marked virtual in a superclass, then it is implicitly virtual in all subclasses. So, you may need to look at superclasses to see if the method is really virtual.
  • Remove the word inline everywhere. Note that these methods are final, and will be faster to call than non-final (virtual) methods.
  • Remove the word register everywhere. This is just a hint to the compiler anyway, and one that is often ignored by modern optimizations.


All lines are busy

Java does not support operator overloading. You will miss this for about 5 minutes if you are programming in pure Java, but it is a hassle when converting from C++. First you will need to change all the definitions.

Here is a sample list of operators that could be overloaded, and some typical Java equivalent names (there is no fixed set of replacement names; these are only samples.) If you are porting good C++, then the meaning of the operator does not deviate from the core meaning; if not, then you should change the name to correspond to the real meaning (such as append for +). The yellow items have special notes.

Operator Overload Replacement Names

C++

Java

+
-
!
%
*
/
 
^
&
|
~
>>
<<
plus
minus
not
remainder
times
dividedBy
 
bitXor
bitAnd
bitOr
bitNot
shiftRight
shiftLeft

C++

Java

||
&&
==
<
<=
!=
>
>=
()
[]
 
 
=
 
++
--
*=...
*
->
or
and
equals
isLess
isLessOrEquals
(see below)
(see below)
(see below)
(see below)
elementAt,
setElementAt
 
assign
 
increment
decrement
(see context)
getX, setX
getX, setX

Notes

  • % is remainder in Java, not modulo. That is, -3%5 == -3, and not 2. In C++, it is undefined whether it is remainder or modulo. So since your C++ code is portable (right?), you never depended on the result with negative numbers, and you don't need to make any changes. Otherwise, you will need to change x%y to (x%y - ((x < 0) ? y : 0))
  • Don't bother defining an equivalent to !=. The value should always be the same as if you called !(a == b), so just replace the call sites by (!a.equals(b)). You can also do the same for > and >=.
  • The parentheses operator differs so much from case to case that you will have to look at the context to get a good name.
  • For the pointer operators * and ->, Java has no real equivalents. Use getters and setters as appropriate.
  • Most home-grown operators will not distinguish between predecrement and postdecrement, or preincrement and postincrement. If you really make use of that, you can use the longer names.
  • Assignment (and copy constructors) are more complex than other operators. For more detail, see Difficult Assignments.
  • For the index operators, define 2 methods. You will then have to fix the call sites according to the usage.

Once you have changed all of the definitions, let the compiler find the call-sites for you to fix.

Replacing Overloaded Operator Calls

C++

Java

// declaring
bool operator==
 (const Foo& other) const;
 
 
// using 
if (a == b)

a[3] = 5;
x = a[3];
// declaring
public boolean equals(Foo other) {
 /*...*/
}
 
// using 
if (a.equals(b))

a.setElementAt(3,5);
x = elementAt(3);


Giving pointers

Java is touted as having no pointers. In porting from C++ code, however, you almost want to think of it as the reverse; all objects are pointers--there are no stack objects or value parameters. The syntax of the language hides this fact from you, but you have to be careful, as the following examples show.

Replacing Pointers

C++

Java

// initializing
Foo* x = new Foo(3);
Foo y(4);
Foo z;
 
// assigning 
Foo* a = x;
Foo* c = 0;
Foo* d = NULL;
Foo b = y;
 
// calling
x->doSomething();
y.doSomething();
 
// comparing
if (x == a);
if (y == b);
if (&y == &b);
// initializing
Foo x = new Foo(3);
Foo y = new Foo(4);
Foo z = new Foo();
 
// assigning 
Foo a = x;
Foo c = null;
Foo d = null;
Foo b = y.clone();
 
// calling
x.doSomething();
y.doSomething();
 
// comparing
if (x == a);
if (y.equals(b));
if (y == b);

Important

  • Note that assignment of objects does not assign value; it is the equivalent of pointer assignment. You have to use clone() to get a new object.
  • Similarly, comparison of object with == is a pointer comparison; you have to use equals() to get comparision by value.
  • Java does not automatically convert numbers. Use null instead of zero for a null object. If you are using pointer arithmetic, click here.


No references necessary

Java also does not have references in the same way as C++, although they use the term references for normal objects (much like the conflation of objects and pointer to objects). Most C++ programs only use them in passing parameters to a method, or getting a return value back.

Fixing Parameter References

C++

Java

// input parameter
int method1(const Foo& x);
 
// Mutable output parameter
int method2(Foo x);

// Immutable output parameter
int method2(int& x);

// usage
Foo x;
z = y.method2(x);
w = x;
// input parameter
int method1(Foo x);
 
// Mutable output parameter
int method2(Foo x);

// Immutable output parameter
int method2(int[] x);

// usage
Foo[] x = new Foo[1];
z = y.method2(x);
w = x[1];

Notes

  • Input parameters are simple; just remove the const (however, there is a definite cost to doing this in terms of robustness of your code, see Bullet-proofing for better approaches).
  • Output parameters are more complex. Mutable objects (such as StringBuffer) can be passed in directly. Immutable objects (such as String, Integer) are more troublesome. You have three choices.
    1. Return the value from the method. This probably involves more work in porting, since presumably the reason you had an output parameter was that you were already using the return.
    2. The simplest way--though ugly--is to pass in an array as we did in the example. Since arrays are always Mutable, you can just get/set the first value in the array.
    3. The last way is to create a new class that contains fields corresponding to the output parameters and return value, and return that. If you make that new class Mutable, you can also use it as an output parameter & modify it. This involves more effort, but is somewhat cleaner than the array method.

Alternative Output Parameters

C++

Java

// output parameter
int method2(int& x);

// usage
int x;
z = y.method2(x);
w = x;
// output parameter
int method2(IntWrapper x);

// usage
IntWrapper x = new IntWrapper();
z = y.method2(x);
w = x.intField;

// new class
class IntWrapper {
 public Int intField;
}

Return values can also be references. There are two common idioms for reference returns in C++.

  1. Return *this. This method allows chaining, as in x = y = z;
  2. Return a reference to an input parameter. This allows use of use of functional returns without requiring memory allocation. Below is an example where method2 fills in x, then returns it for further use. Since the principal use of this is in handling memory allocation, there is little need for it in Java, but it may make your porting easier to leave it as is.
  3. Return a reference to a static.

All of these idioms can be used in Java, though the compiler may warn you of problems if you are trying to set a Mutable. In that case, you will have to supply some of the same techniques as with output parameters.

Fixing References

C++

Java

// definition
Foo& setX();
 
// return of ouput parameter
Foo& getY(Foo& Y);
 
// return static constant
const Foo& getAStatic();
 
// use
myObject.setX(3).setY(4);
 
Foo x;
myObject.doZ(myObject.getY(x));
 
z = x * Foo::getAStatic();
// definition
Foo setX();
 
// return of output parameter
Foo getY(Foo Y);
 
// return static
Foo getAStatic();
 
// use
myObject.setX(3).setY(4);
 
Foo x = new Foo();
myObject.doZ(myObject.getY(x));
 
z = x * Foo.getAStatic();

Notes

  • There are a couple of other cases where references might be used in C++, although they should not occur in good C++ code.
    • The method creates a new object on the heap, but then hands back a reference rather than the pointer. This is a prime candidate for memory leaks, since there is no way for the original object to know when to toss the storage. This is a bug in the C++ code, and should be corrected.
    • The method returns a reference to an internal element. For example, it could return &myCharArray[5]. Although legal, this can be the source of many nasty headaches, since the results are undefined if the enclosing storage is altered or moved.


Honest-to-God Arrays

Java arrays are real objects, not just disguised pointers. Generally you replace pointers used to iterate through an array by offsets, and the * operator by an array access. Most of these cases will be flagged by the compiler.

Fixing Arrays

C++

Java

// initializing
double x[10];
double* end = x + 10;
double* current = x;
 
// iterating 
while (current < end) {
 doSomethingTo(*current++);
}
// initializing
double[] x = new double[10];
int end = x.length;
int current = 0;
 
// iterating 
while (current < end) {
 doSomethingTo(x[current++]);
}

Notes

  • Both the syntaxes Foo x[] and Foo[] x work, though the latter is more Java-like.
  • Java arrays can supply you their length, rather than your having to remember it independently. Wherever possible, use this instead of a hard-coded length.
  • As with fields of an object, the items in an array are initialized to zero (for numerical primitives), false for boolean and null for Objects.

Pitfalls

Declaring an array does not create object to fill an array. This is another place where objects behave like pointers, not values. Since arrays of objects are--under the covers--arrays of pointers, they are initialized to null; not to a list of default-constructed objects. If you want them to be default-constructed objects, you must set them yourself!

One other point: although the allocation of static arrays looks similar to C++, be aware that there are vastly different footprint and performance implications. Unlike C++, which builds a static table that is loaded in at runtime, the Java compiler actually generates code to place every single entry in the array, so a very large table could be a performance and footprint hit.

Fixing Arrays

C++

Java

// initializing
Foo x[10];




// initializing
static const int x[] =
 {1,2,3,4,5,6,7,8,...
// initializing
Foo[] x = new Foo[10];
for (int i = 0; i < x.length; ++i) {
 x[i] = new Foo();
}

// initializing
static const int x[] =
 {1,2,3,4,5,6,7,8,...


Introduction, Basics, Next Steps, Well-Mannered Objects, Esoterica, Background, Index

 

 

dot_clear dot_clear dot_clear dot_clear dot_clear
navbar
Products Object Resources In the News Company Info Search
 
If you encounter problems with this service please contact webmaster@taligent.com.

© Copyright. All rights reserved. Taligent, Inc., IBM Corp.