Κληρονομικότητα

Διομήδης Σπινέλλης
Τμήμα Διοικητικής Επιστήμης και Τεχνολογίας
Οικονομικό Πανεπιστήμιο Αθηνών
dds@aueb.gr

Εισαγωγή

Οι σχέσεις αυτών των κλάσεων μπορούν να παρασταθούν στο παρακάτω διάγραμμα.

Κάθε κλάση κληρονομεί τις ιδιότητες της μητρικής της κλάσης.

Κληρονομικότητα σε κλάσεις

Δυναμική διεκπεραίωση

Αφηρημένες κλάσεις

Για παράδειγμα, ένας σχεδιασμός του πληροφοριακού συστήματος του Πανεπιστημίου μπορεί να ορίσει την ιδεατή κλάση person ως βασική κλάση για τις υποκλάσεις student, employee και visitor. Αν και δε θα μπορεί να ένα νέο αντικείμενο με βάση την αφηρημένη κλάση person, αυτή μπορεί να περιέχει ορισμένα βασικά χαρακτηριστικά όπως birth_date και να επιβάλει την υλοποίηση συγκεκριμένων μεθόδων όπως home_page_URL() ορίζοντάς τις ως ιδεατές.

Παράδειγμα

Το παρακάτω παράδειγμα ορίζει τη βασική κλάση Shape και τις υποκλάσεις της Circle και Rectangle. Η μέθοδος area μπορεί να οριστεί για τις υποκλάσεις και κατά την εκτέλεση του προγράμματος να εκτελεστεί η σωστή έκδοσή της. Η συνάρτηση toString της Shape εκμεταλλεύεται τη δυνατότητα αυτή και μπορεί να κληθεί (και να δουλέψει σωστά) με όρισμα οποιαδήποτε από τις υποκλάσεις της shape.
import gr.aueb.dds.BIO;

abstract class Shape {
        private double x, y;            // Position
        protected double getX() { return x; }
        protected double getY() { return y; }
        public void setposition(double px, double py) {
                x = px;
                y = py;
        }
        public abstract double area();
        public String toString() {
                return "Shape(x=" + x + ", y=" + y + ", area=" + area() + ")";
        }
}

class Circle extends Shape {
        private double radius;
        public void setradius(double r) {
                radius = r;
        }
        public double area() {
                return 2 * Math.PI * radius * radius;
        }
        public String toString() {
                return super.toString() + ": Circle(" + radius + ")";
        }
}

class Rectangle extends Shape {
        private double height, width;
        public void setdimensions(double h, double w) {
                height = h;
                width = w;
        }
        public double area() {
                return height * width;
        }
        public String toString() {
                return super.toString() + ": Rectangle(" + height + " x " + width + ")";
        }
}

class Test {
        static public void main(String args[])
        {
                Circle c = new Circle();
                Rectangle r = new Rectangle();
                Shape s[] = new Shape[2];

                s[0] = r;
                r.setposition(12);
                r.setdimensions(5050);

                s[1] = c;
                c.setposition(34);
                c.setradius(10);
                for (int i = 0; i < s.length; i++)
                        BIO.println(s[i]);
        }
}
Το παραπάνω πρόγραμμα θα τυπώσει:
Shape(x=1.0, y=2.0, area=2500.0): Rectangle(50.0 x 50.0)
Shape(x=3.0, y=4.0, area=628.3185307179587): Circle(10.0)

Ασκήσεις

  1. Να υλοποιηθούν σε Java οι κλάσεις AndGate, OrGate, NotGate. Οι κλάσεις αυτές θα προσομοιάζουν τις αντίστοιχες λογικές πύλες. Κάθε κλάση να έχει μεθόδους που να θέτουν τις εισόδους (π.χ. setA, setB) και μέθοδο που να επιστρέφει την τιμή της εξόδου (π.χ. getOutput).
  2. Με τη χρήση των παραπάνω κλάσεων (και μόνο) να υλοποιήσετε μια κλάση που να προσομοιάζει έναν ημιαθροιστή. Η κλάση αυτή να έχει μεθόδους που να θέτουν τις δύο εισόδους και μεθόδους που να επιστρέφουν το άθροισμα (getSum) και το κρατούμενο (getCarryOut).
  3. Να γράψετε ένα πρόγραμμα σε Java που να τυπώνει τους πίνακες αλήθειας για τις παραπάνω κλάσεις.
  4. (Προαιρετικά) Με τη χρήση των παραπάνω κλάσεων να υλοποιήσετε μια κλάση που να προσομοιάζει έναν πλήρη αθροιστή. Η κλάση αυτή πρέπει να έχει μεθόδους που να θέτουν τις δύο εισόδους και το κρατούμενο εισόδου (setCarryIn) καθώς και μεθόδους που να επιστρέφουν το άθροισμα και το κρατούμενο εξόδου. Με τη χρήση του πλήρη αθροιστή και τους τελεστές bit της Java μπορεί να υλοποιηθεί μια κλάση αθροιστή ακεραίων αριθμών (wordadder) με τον παρακάτω τρόπο:
    /*
     * wordadder.java
     *
     * D. Spinellis, February 2000, December 2001
     */

    import gr.aueb.dds.BIO;

    class WordAdder {
            private int a, b;
            public void setA(int v) { a = v;}
            public void setB(int v) {b = v;}
            public int getSum() {
                    FullAdder fa[] = new FullAdder[32];
                    int i, bit;
                    int result = 0;

                    for (i = 0; i < 32; i++)
                            fa[i] = new FullAdder();

                    fa[0].setCarryIn(false);
                    // bit is the bit position to add
                    for (i = 0, bit = 1; i < 32; bit <<= 1, i++) {
                            fa[i].setA((a & bit) != 0);
                            fa[i].setB((b & bit) != 0);
                            // Propagate carry
                            if (i < 31)
                                    fa[i + 1].setCarryIn(fa[i].getCarryOut());
                            // Merge adder output into result
                            if (fa[i].getSum())
                                    result |= bit;
                    }
                    return (result);
            }

            // Test harness
            public static void main(String args[]) {
                    int a, b;
                    WordAdder wa = new WordAdder();

                    BIO.print("a=");
                    wa.setA(a = BIO.readInt());
                    BIO.print("b=");
                    wa.setB(b = BIO.readInt());
                    BIO.println(a + " + " + b + " = " + wa.getSum());
            }
                                    
    }
    Δοκιμάστε το!

Βιβλιογραφία