15.14 EXTENDING CLASSES IN JAVA


15.14 EXTENDING CLASSES IN JAVA

What is accomplished by making a public derivation from a class in C++(see Section 15.1) is achieved by using the "extends" clause in Java, as in the following Employee-Manager example:

 
class Employee { // BASE private String firstName, lastName; public Employee (String fnam, String lnam) { firstName = fnam; lastName = lnam; } public void print () { System.out.print (firstName + " " + lastName); } } class Manager extends Employee { // DERIVED private short level; public Manager( String fnam, String lnam, short lvl) { super (fnam, lnam); //(A) level = lvl; } public void print () { super.print (); //(B) System.out.println( "level: " + level); } }

Note how the constructor for Manager calls the constructor of the base class by invoking super (fnam, lnam) in line (A). As was pointed out earlier in Chapter 3, invocation of a base constructor has to be the first line in a derived class constructor. In common with C++, if the base constructor is not invoked explicitly in a derived class constructor, the system will automatically try to invoke the no-arg constructor for the base class. But, recall that the base class will possess a no-arg constructor either because you provided it with one, or because it has no constructors at all, in which case the system will supply the class with a default no-arg constructor.

Object construction in Java has one feature that is not shared by object construction in C++: Instead of invoking, explicitly or implicitly, a base-class constructor, a derived-class constructor is allowed to invoke another one of the constructors for the derived class by using the this invocation.

We demonstrate the above with the following version of the Manager class. In this version, we have a 2-arg constructor besides the regular 3-arg constructor. Note how the 2-arg constructor invokes in line (C) the 3-arg constructor using the this () construct.

      class Manager extends Employee {          private short level;          public Manager(String fnam, String lnam, short lvl) {              super(fnam, lnam);              level = lvl;          }          public Manager(String fnam, String lnam) {              this(fnam, lnam, 10);                                   //(C)          }          public void print() {              super.print()                                           //(D)              System.out.println("level: " + level);          }      } 

As with C++, when you extend a class in Java to create a derived class, all the protected and public data members of the base class become directly available in the derived class. Also directly visible in the derived class are those protected and public methods of the base class that are are not overridden in the derived class. In the example above, the print() function in the Manager class overrides the print () function in the Employee class. Nonetheless, the base-class print can still be invoked in the derived class using the keyword super, as we show in lines (B) and (D).

As already mentioned, one great difference between C++,and Java is that while only those functions that are declared virtual behave polymorphically in C++,in Java all member functions are polymorphic. (And, that'why, as we have mentioned before, all member functions in Java aremethods.)

With regard to the base-class functions that are available in a derived class, another very important difference between C++,and Java is as follows: As mentioned in Section 15.1, in C++,a derived-class function of a given name hides all base-class functions of the same name, regardless of their signatures; the hidden names can only be accessed through the scope operator in the derived class. That is not the case in Java. This is illustrated with the help of the following two programs that are meant to do exactly the same thing. The first program shown below, in Java, compiles and runs fine with the output shown in the commented out portions of the code in Test. main, but the C++,program shown after that does not even compile.

In the program below, the class Base possesses three overloaded definitions of the function name foo: a no-arg foo in line (A), a one-arg foo in line (B), and a two-arg foo in line (C). The class Derived possesses its own foo—a no-arg version in line (D). Line (E) of Test.main invokes a no-arg foo on an object of type Derived. As the output shown in the same line indicates, the function definition used for this call is the one defined for Derived. But when we invoke a one-arg foo on the same Derived object in line (F) and a two-arg foo in line (G), the definitions used are those for Base. What this establishes is that the use the function name foo in Derived does not hide all functions of name foo in Base—contrary to what happens in C++.

 
//NameLookup.java class Base { public void foo() { //(A) System.out.println( "Base's foo() invoked"); } public void foo(int i) { //(B) System.out.println( "Base's foo(int) invoked"); } public void foo( int i, int j ) { //(C) System.out.println( "Base's foo( int, int ) invoked" ); } } class Derived extends Base { public void foo() { //(D) System. out. println ("Derived's foo() invoked"); } } public class Test { public static void main(String[] args) { Derived d = new Derived(); d.foo(); //Derived's foo() invoked //(E) d.foo( 3); // Base's foo(int) invoked //(F) d.foo(3, 4); // Base's foo(int, int) invoked //(G) } }

Now compare the above Java program with its C++ version shown below. The C++ version does not even compile. The error message returned by the compiler is

     in function 'int main()':         no matching function for call to 'Derived::foo (int)'         candidates are: void Derived::foo()         no matching function for call to ’Derived::foo(int, int)'         candidates are: void Derived::foo() 

which shows the function foo() defined in Derived in line (D) below hides all versions of foo defined in Base. So Base' foo (int) and foo (int, int) defined in lines (B) and (C) below are simply not available in Derived—at least not available for unqualified access—even though they are not being overridden.

 
//NameLookup.cc // WILL NOT COMPILE #include <iostream> using namespace std; class Base { public: void foo() { //(A) cout << "Base's foo() invoked" <<endl; } void foo(int i) { //(B) cout << "Base's foo(int) invoked" << endl; } void foo(int i, int j) { //(C) cout << "Base's foo(int, int) invoked" << endl; } }; class Derived : public Base { public: void foo(){ cout << "Derived's foo() invoked" << endl; } //(D) }; int main() { Derived d; d.foo(); //(E) d.foo(3); //(F) d.foo(3, 4); //(G) }

To capture in C++ the name lookup behavior of Java that we showed in the program NameLookup. java, we would need to change the code in mainabove to:

     int main()     {         Derived d;         d.foo();         d.Base::foo(3);         d.Base::foo(3,4);     } 

where we used the scope operator to access the hidden function names of Base.




Programming With Objects[c] A Comparative Presentation of Object-Oriented Programming With C++ and Java
Programming with Objects: A Comparative Presentation of Object Oriented Programming with C++ and Java
ISBN: 0471268526
EAN: 2147483647
Year: 2005
Pages: 273
Authors: Avinash Kak

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net