Java Cookbook:
Porting C++ to Java
Introduction, Basics, Next
Steps, Well-Mannered Objects, Esoterica, Background,
Index
Esoterica
The following sections deal with less common constructs in C++.
|
Primogenitur
Entail
Java does not support multiple inheritance. It
does support interfaces, which can get you a long way towards
replacing multiple inheritance. You can think of interfaces as fully abstract
classes, with no data fields and all pure virtual methods. If all but one
of the base classes for your class are fully abstract classes, then just
turn them into interfaces.
Simple Multiple Inheritance
C++
|
Java
|
// Bar is fully abstract
class Bar {
...
void someMethod() = 0;
}
// simple multiple inheritance
class Foo : Fii, Bar {...
|
// Bar is purely abstract
interface Bar {
...
void someMethod();
}
// simple multiple inheritance
class Foo extends Fii
implements Bar {...
|
- If the inheritance is not simple, then you will have to do some more
work. First, pick the base class that is most central to the function of
the class in question. For each of the other base classes:
- define a new interface that each one implements
- declare a field of the type of each base in your target class
- delegate methods in your target class to the appropriate field
Goto higher levels
C++
|
Java
|
// Other base classes
class Bar {
...
void methodA();
}
class Foe {
...
int methodB();
}
// simple multiple inheritance
class Foo : Fii, Bar, Foe {
...
}
|
// Other base classes
class Bar {
...
void methodA();
}
class Foe {
...
int methodB();
}
// simple multiple inheritance
class Foo extends Fii
implements BarInterface,
FoeInterface {...
...
void methodA() {
bar.methodA();
}
void methodB() {
return foe.methodB();
}
private Bar bar = new Bar();
private Foe foe = new Foe();
}
// Interfaces
interface BarInterface {
...
void methodA();
}
interface FoeInterface {
...
void methodB();
}
|
Size
doesn't matter
You can't use sizeof in Java. You generally
only use it when you are doing unions, bit-field manipulations or C-style
memory management. You will need to look carefully at the intent to see
how to port the code. For example:
Replacing sizeof
C++
|
Java
|
x = (Foo*) alloc(sizeof(Foo)*len);
|
x = new Foo[len];
|
You will have to remove the bitfield notation,
since that is not supported in Java. Generally you can just dispense with
the notation. If you really, really need bitfields to save
storage, see Shave and a Haircut.
Shave
and a Haircut
If you really, really need bitfields
to save storage, then you will need to do it yourself, basically by duplicating
the code that is behind the use of bitfields in C++. If you are using large
numbers of single bits, use java.util.BitSet (Bitset is
safer and easier than managing the masks and shifting yourself, but will
not save you storage unless you have a significant number of bits.)
Replacing Bitfields
C++
|
Java
|
// declaring
struct Foo {
// ...
unsigned int z:3;
}
// using
a = myFoo.z;
z = myFoo.b;
|
// declaring
class Foo {
// ...
public byte getZ() {
return (xyz & Z_MASK) >>> Z_SHIFT;
}
public void setZ() {
xyz = (b << Z_SHIFT) & Z_MASK
| xyz & ~Z_MASK;
}
private int xyz;
private final static Z_SHIFT = 17;
private final static Z_SHIFT = 0x7;
}
// using
a = myFoo.getZ();
myFoo.setZ(b);
|
Unions are also excluded from Java. The easiest
approach to porting then is just to make the union into a class.
Unions
C++
|
Java
|
// declaring
union Foo {
bool isFiiVsBarr;
Fii x;
Barr y;
}
|
// declaring
class Foo {
boolean isFiiVsBarr;
Fii x;
Barr y;
}
|
Where they are being used for storage savings,
you can sometimes get the same effect by using Object. The only disadvantage
is that you are substituting runtime type-checking for compile-time checking.
Where unions are being used for scurrilous casting,
you will have to work around it. For example, where such castings are used
for hiddent bit-manipulations, you'll have to use the appropriate arithmetic
operations, as below. You will have the advantage of having much more portable
code in the end, though, without big-endian or little-endian troubles.
Bit Twiddling in Unions
C++
|
Java
|
// declaring
union Foo {
int i;
char c;
}
// using
x.i = 99;
z = x.c;
|
// declaring
int i;
// using
x = 1066;
z = x & 0xFF; // if C++ was BE
z = x & 0xFF00; // if C++ was LE
|
Directly
to Jail
Well-written C++ code should have very few gotos,
if any. There are, however, times where a goto produces less convoluted
code: where you need to escape from an inner loop. Although Java has completely
eliminated gotos, it has added a construct that replaces their
use, and in a much cleaner and less dangerous way. You can name a loop with
a label, then use break or continue with that label to
escape from an inner block.
Goto end of block
C++
|
Java
|
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (f(i,j)) {
goto done;
}
}
}
done:
|
mainLoop:
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (f(i,j)) {
break mainLoop;
}
}
}
|
- If your gotos don't follow this pattern, then it is still
fairly easy to convert if the gotos don't cross blocks. This is
a bit kludgy, but saves your having to go in and figure out this snarled
code.
Goto higher levels
C++
|
Java
|
{...
{...
{...
goto done;
...
}
...
}
...
}
done:
|
kludgeLoop:
while (true) {...
{...
{...
break kludgeLoop;
...
}
...
}
...
break;
}
|
If your gotos jump into the middle of nested blocks (such as
into a switch statement), then you will have no choice but to try
to untangle the code.
Java
has no friends
Java doesn't have the friend keyword.
You can, however, permit access to your privates by any other class in your
package by making the access package-private. You do this by omitting
the keyword private from your methods or data fields, and ensuring
that the former friends are in the same package.
Replacing Friend
C++
|
Java
|
class Foo {
private int foe;
protected int fii;
friend class Bar;
}
class Bar {
private Foo foo;
public method() {
...
y = foo;
z = fii;
...
}
}
|
class Foo {
int foe;
protected int fii;
int getFii() {...}
}
class Bar {
private Foo foo;
public method() {
...
y = foo;
z = getFii();
...
}
}
|
Notes
- If you need to allow access to protected fields or methods, then you
have to write cover methods that allow package-private access.
- If you need to have friend access from two different
packages, then you are out of luck. Your only choices are:
- to make the methods or fields public
- copy the class into both packages (this works
for small classes)
Introduction,
Basics, Next Steps,
Well-Mannered Objects, Esoterica,
Background, Index
|