Thursday 30 March 2017

The Differences Between C++ and Java & Eliminating Pointers - Java Tutorials

The Differences Between C++ and Java

Before we look at specific situations, let’s review the basic differences between C++ and Java. The differences fall into three categories:
  • C++ features not supported by Java
  • Features unique to Java
  • Shared features which differ between C++ and Java

Each is examined here.


What Java Has Removed from C++

There are a number of C++ features that Java does not support. In some cases, a specific C++ feature simply didn’t relate to the Java environment. In other cases, the designers of Java eliminated some of the duplication of features that exists in C++. In still other instances, a feature of C++ is not supported by Java because it was deemed too dangerous for Internet applets.

Perhaps the single biggest difference between Java and C++ is that Java does not support pointers. As a C++ programmer you know that the pointer is one of C++’s most powerful and important language features. It is also one of its most dangerous when used improperly. Pointers don’t exist in Java for two reasons:
  • Pointers are inherently insecure. For example, using a C++-style pointer, it is possible to gain access to memory addresses outside a program’s code and data. A malicious program could make use of this fact to damage the system, perform unauthorized accesses (such as obtaining passwords), or otherwise violate security restrictions.
  • Even if pointers could be restricted to the confines of the Java run-time system (which is theoretically possible), the designers of Java believed that they were inherently troublesome. 
Since pointers don’t exist in Java, neither does the -> operator.

Here are a few more of the most important “omissions”:
  • Java does not include structures or unions. These were felt to be redundant since the class encompasses them.
  • Java does not support operator overloading. Operator overloading is sometimes a source of ambiguity in a C++ program, and the Java design team felt that it causes more trouble than benefit.
  • Java does not include a preprocessor nor does it support the preprocessor directives. The preprocessor plays a less important role in C++ than it does in C. The designers of Java felt that it was time to eliminate it entirely.
  • Java does not perform any automatic type conversions that result in a loss of precision. For example, a conversion from long integer to integer must be explicitly cast.
  • All the code in a Java program is encapsulated within one or more classes. Therefore, Java does not have what you normally think of as global variables or global functions.
  • Java does not allow default arguments. In C++, you may specify a value that a parameter will have when there is no argument corresponding to that parameter when the function is invoked. This is not allowed in Java.
  • Java does not support the inheritance of multiple superclasses by a subclass.
  • Although Java supports constructors, it does not have destructors. It does, however, add the finalize( ) function.
  • Java does not support typedef.
  • It is not possible to declare unsigned integers in Java.
  • Java does not allow the goto.
  • Java does not have the delete operator.
  • The << and >> in Java are not overloaded for I/O operations.
  • In Java, objects are passed by reference only. In C++, objects may be passed by value or by reference.


New Features Added by Java

There are a number of features in Java that have no equivalent in C++. Perhaps the three most important are multithreading, packages, and interfaces, but there are several others that enrich the Java programming environment as well.
  • As explained earlier, multithreading allows two or more pieces of the same program to execute concurrently. Further, this approach to concurrence is supported at the language level. There is no parallel for this in C++. If you need to multithread a C++ program, you will need to do so manually, using operating system functions. While both methods allow for concurrent execution of two or more threads, Java’s approach is cleaner and easier to use.
  • There is no feature in C++ that directly corresponds to a Java package. The closest similarity is a set of library functions that use a common header file. However, constructing and using a library in C++ is completely different from constructing and using a package in Java.
  • The Java interface is somewhat similar to a C++ abstract class. (An abstract class in C++ is a class that contains at least one pure virtual function.) For example, it is impossible to create an instance of a C++ abstract class or a Java interface. Both are used to specify a consistent interface that subclasses will implement. The main difference is that an interface more cleanly represents this concept.
  • Java has a streamlined approach to memory allocation. Like C++, it supports the new keyword. However, it does not have delete. Instead, when the last reference to an object is destroyed, the object, itself, is automatically deleted the next time that garbage collection occurs.
  • Java “removes” the C++ standard library, replacing it with its own set of API classes. While there is substantial functional similarity, there are significant differences in the names and parameters. Also, since all of the Java API library is object-oriented, and only a portion of the C++ library is, there will be differences in the way library routines are invoked.
  • The break and continue statements have been enhanced in Java to accept labels as targets.
  • The char type in Java declares 16-bit-wide Unicode characters. This makes them similar to C++’s wchar_t type. The use of Unicode helps ensure portability.
  • Java adds the >>> operator, which performs an unsigned right shift.
  • In addition to supporting single-line and multiline comments, Java adds a third comment form: the documentation comment. Documentation comments begin with a /** and end with a */.
  • Java contains a built-in string type called String. String is somewhat similar to the standard string class type provided by C++. Of course, in C++ string is only available if you include its class declarations in your program. It is not a built-in type.


Features That Differ

There are some features common to both C++ and Java that each language handles a bit differently:
  • While both C++ and Java support a Boolean data type, Java does not implement true and false in the same way as C++. In C++, true is any nonzero value. False is zero. In Java, true and false are predefined literals, and these are the only values that a boolean expression may have. While C++ also defines true and false, which may be assigned to a bool variable, C++ automatically converts nonzero values into true and zero values into false. This does not occur in Java.
  • When you create a C++ class, the access specifiers apply to groups of statements. In Java, access specifiers apply only to the declarations that they immediately precede.
  • C++ supports exception handling that is fairly similar to Java’s. However, in C++ there is no requirement that a thrown exception be caught.

With these additions, deletions, and differences as a backdrop, the rest of this chapter will look closely at a few of the key issues that you must deal with when converting code from C++ to Java.




Eliminating Pointers

When you convert a C++ program into Java, perhaps the greatest number of changes will be caused by pointers. Most C++ code is heavily dependent upon pointers for its operation. You can’t program anything very significant in C++ without using a pointer. There are four general categories of pointer usage that you will encounter in C++ code:
  • As parameters to functions. Although C++ supports the reference parameter, there is a large base of legacy code that was originally written in C. C does not support reference parameters. In C, if a function needs to change the value of an argument, it is necessary to explicitly pass a pointer to that argument. Therefore, it is still common to find pointer parameters used in C++ code that was originally ported from C. Also, in some cases the same function library will need to be shared by both C and C++ code, which prevents the use of reference parameters. Additionally, many of the standard library functions supported by C++ are holdovers from C. When one of these C-based functions requires the address f an argument, a pointer to the argument is used. Inside the function, the argument is then accessed through its pointer.
  • To provide a more efficient means of implementing certain constructs—especially array indexing. For example, it is often more efficient to sequentially move through an array using a pointer rather than an array index. While modern compilers implement highly efficient optimizations, pointers can still provide a significant performance boost. Thus, the use of pointers to access arrays is ubiquitous in C++ code.
  • To support memory allocation. In C++, when you allocate memory, an address (that is, a pointer) to that memory is returned. This address must be assigned to a pointer variable. Once this has been done, the pointer can point to any part of the allocated memory—or anywhere else, for that matter—by means of pointer arithmetic. In Java, when an object is allocated by new, a reference to the object is returned. This reference must be assigned to a reference variable of a compatible type. While Java reference variables do implicitly point to the object that was allocated by the new operator, they cannot be manipulated in the same way as C++ pointers. And they cannot point to memory outside of the Java run-time context.
  • To provide access to any arbitrary machine address, possibly to call a ROM routine or to read/write directly to memory. Since Java purposely disallows such actions, this use of pointers has no direct parallel. If you are writing applications, not applets, you can always use Java’s native capabilities (described in Part One) to gain access to native code routines that would be allowed access to such system resources. 


Let’s look at two situations in which pointer-based C++ code is converted to Java.


Converting Pointer Parameters

For the most part, it is quite easy to convert a C++ function that uses pointer parameters into its equivalent Java method. Since Java passes all objects by reference, sometimes the conversion simply requires the removal of C++’s pointer operators. For example, consider this C++ program that reverses the signs of a Coord object, which stores a pair of Cartesian coordinates. The function reverseSign( ) is passed a pointer to the Coord object that will be reversed. As you can see, C++’s *, &, and -> pointer operators are used to perform the operation.

  // Reverse the signs of a coordinate - C++ version.
  #include <iostream>
  using namespace std;

  class Coord {
  public:
    int x;
    int y;
  };

  // Reverse the sign of the coordinates.
  void reverseSign(Coord *ob) {
    ob->x = -ob->x;
    ob->y = -ob->y;
  }

  int main()
  {
    Coord ob;

    ob.x = 10;
    ob.y = 20;

    cout << "Original values for ob: ";
    cout << ob.x << ", " << ob.y << "\n";

    reverseSign(&ob);

    cout << "Sign reversed values for ob: ";
    cout << ob.x << ", " << ob.y << "\n";

    return 0;
  }

This program can be recoded into the following Java version. As you can see, most of the conversion involves the deletion of the C++ pointer operators. Since Java passes objects by reference, changes to the parameter automatically affect the argument.

  // Reverse the signs of a coordinate - Java version.
  class Coord {
    int x;
    int y;
  };

  class DropPointers {
    // Reverse the sign of the coordinates.
    static void reverseCoord(Coord ob) {
      ob.x = -ob.x;
      ob.y = -ob.y;
    }
    public static void main(String args[]) {
      Coord ob = new Coord();

      ob.x = 10;
      ob.y = 20;

      System.out.println("Original values for ob: " +
        ob.x + ", " + ob.y);

      reverseCoord(ob);

      System.out.println("Sign reversed values for ob: " +
        ob.x + ", " + ob.y);
    }
  }

The output from both of these programs is the same and is shown here:

  Original values for ob: 10, 20
  Sign reversed values for ob: -10, -20


Converting Pointers that Operate on Arrays

Conceptually, converting C++-style pointer-based array accessing into the equivalent Java-compatible array indexing is straightforward—simply substitute the appropriate array-indexing statements. However, in practice this may require some thought. Pointer-based array accessing can be a bit difficult to follow, because the normal C++ coding style encourages rather dense, complex expressions. For example, this short C++ program copies the contents of one array to another. It uses 0 to mark the end of the arrays. Pay special attention to the pointer expressions. Even in this simple example, if you did not know that this program copied the contents of nums to copy (and later displayed the arrays), it would require some careful thought before you were completely sure that you knew what the code was doing.

  // Copy an array in C++ using pointers.
  #include <iostream>
  using namespace std;

  int main()
  {
    int nums[] = {10, 12, 24, 45, 23, 19, 44,
                  88, 99, 65, 76, 12, 89, 0};
    int copy[20];

    int *p1, *p2; // integer pointers

    // copy array
    p1 = nums; // p1 points to start of nums array
    p2 = copy;
    while(*p1) *p2++ = *p1++;
    *p2 = 0; // terminate copy with zero

    // Display contents of each array.
    cout << "Here is the original array:\n";
    p1 = nums;
    while(*p1) cout << *p1++ << " ";
    cout << endl;

    cout << "Here is the copy:\n";
    p1 = copy;
    while(*p1) cout << *p1++ << " ";
    cout << endl;

    return 0;
  }

Even though it is quite simple for C++ code, at first glance the line

  while(*p1) *p2++ = *p1++;

still requires a moment of thought to decipher its exact operation. One of the advantages of Java is that it does not encourage the creation of such expressions in the first place. Here is the Java version of the program. As you can see, its purpose and effects are transparent.

  // Array copy without pointers using Java.
  class CopyArray {
    public static void main(String args[]) {
      int nums[] = {10, 12, 24, 45, 23, 19, 44,
                    88, 99, 65, 76, 12, 89, 0};
      int copy[] = new int[14];
      int i;

      // copy array
      for(i=0; nums[i]!=0; i++)
        copy[i] = nums[i];
      nums[i] = 0; // terminate copy with zero

      // Display contents of each array.
      System.out.println("Here is the original array:");
      for(i=0; nums[i]!=0; i++)
        System.out.print(nums[i] + " ");
      System.out.println();

      System.out.println("Here is the copy:");
      for(i=0; nums[i]!=0; i++)
        System.out.print(copy[i] + " ");
      System.out.println();
    }
  }

Both versions of the program produce the following results:

  Here is the original array:
  10 12 24 45 23 19 44 88 99 65 76 12 89
  Here is the copy:
  10 12 24 45 23 19 44 88 99 65 76 12 89

Much C++ code is sprinkled with obscure, difficult to understand pointer expressions. While these expressions do tend to increase speed of execution, they are one of the most troubling issues associated with the maintenance of C++ programs. They will also present difficulty when you convert the code to Java. When you are confronted with a complex pointer expression, it is sometimes useful to begin by breaking it into its subexpressions so that its exact operation becomes clear.

No comments:

Post a Comment