Multiple related classes | Java to C++ |
This example uses two classes that reference each other. The key concepts are the use of pointers, the declaration of methods and the use of destructors.
In this program a Course has a name and up to 5 Students. There is a method for adding students to the course and one for printing out all of the information about a course. A Student has a name, an address and a phone number. A Student also has two different kinds of constructors. One with just a name and the other with the name, address and phone number. MainMain.java and Main.cpp are virtually identical. The primary differences are that Main.cpp[3] includes Course.h and Main.cpp[4] includes Student.h. Without these includes the classes could not be used. Java figures this out automatically without the includes. The variable cs132 at Main.java[3] simply receives a new instance of the Course class. In Main.cpp[8] this variable must be declared to be *cs132, which is a pointer. Java implicitly created the pointer and hid it from the programmer. These two behave identically but in C++ the pointer must be explicitly handled. Null stringsIn Java the String class is used to create string objects. Because in Java, all objects are really pointers to objects we must explicitly account for the null pointers, as in Student.java[17,19,21]. In C++ the string class is defined with only a pointer inside the class. This pointer is then used by methods on the string class to manipulate the string itself. This embedding of the pointer inside where it is hidden, makes the C++ string class easier to use. For example in Student.cpp[15,16,17] we do not worry about null pointers. They are handled automatically by the string class to do the right thing. toString()The Student class has a toString() method defined at Student.java[15-24]. When we use a Student as a string (Course.java[19]) the toString() method is automatically called. We also can write a toString() method at Student.cpp[13-19]. However, it does not get called automatically. We must explicitly call the method in Course.cpp[16]. Arrays of pointers to StudentsIn Java every Student variable is actually a pointer to a Student. Arrays are also always pointers. When we declare an array of Students at Course.java[4] we are really declaring a pointer to an array of pointers to Student objects. This means that in our constructor we must actually allocate new space for the array as at Course.java[9]. In C++ arrays and objects do not need to be pointers, even though that is usually the best way to work with them both. When we declare the students variable at Course.h[12] we must explicitly say that we are creating an array ( [MAX_STUDENTS] ) of pointers to students ( Student * ). This array is actually embedded in the Course object. In our situation where there are only 5 possible students, this is OK. However, with a realistic sized array, students should be a pointer to the array rather than just the array itself. Because there is no pointer to the students array, there is no need to allocate space in the constructor Course.cpp[5-8]. We had to do this allocation in Java at Course.java[9]. ConstructorsThe constructors in Java and C++ are virtually identical. The key difference is that the constructor is declared in the .h file and then actually implemented in the .cpp file. DestructorsJava is a memory-managed language. This means that any objects or arrays that are no longer being used are automatically recovered by the system. We never need to worry about such things. C++ is not memory-managed. The programmer is responsible for deleting all memory that is no longer being used. If the programmer does not do this the program will eventually run out of memory and crash. One of the tools provided in C++ for managing memory is the destructor. Destructors look like constructors except that they always start with a tilde (~). The Course class has a destructor that is declared at Course.h[17]. This destructor is implemented at Course.cpp[18-21]. The destructor goes through the students array and deletes every Student that was stored there. The destructor is the way for a class to clean up after itself. When each of the students is deleted at Course.cpp[20] the destructor ~Student is called on each student automatically. The only fields in Student are name, address and phone which are all string objects. The compiler automatically calls their destructors and those destructors clean up the memory associated with those strings. The only things you need to make certain and clean up are when you have stored a pointer to something. You then need your destructor to make sure that nobody else is using that object and then delete it. Objects as parametersIn keeping with Java's view that all objects are actually pointers to objects, we generally pass a pointer to an object rather than the actual object. For example, at Course.cpp[9] the add() method is receiving a pointer to the student rather than the actual student. If you try to pass an actual object it could be very inefficient because the object would need to be copied onto the calling stack. This could be very wasteful. |