Questions

  1. What is the keyword used to call the constructor from the base class?

    • this.
    • the name of the base class.
    • base
    • over
    • inherits
  2. Inheritance is …

    • … a way of implementing a class by re-using another class’ code.
    • … impossible to represent in a UML diagram.
    • … achieved using the ; (semicolon) symbol.
    • … a way of connecting a basic class with a derived class.

    Comment

    The class inherited from is called the base, superclass or parent class, but not basic.

  3. Suppose your are given an ElectricDevice class and a WallDecor class. You would like to write a Clock class that represents at the same time an electric device and a wall decor. This is possible only if the ElectricDevice and WallDecor classes are…

    • Sealed
    • Interfaces
    • Protected
    • Constructors
  4. An abstract class…

    • … can be instantiated.
    • … can contain a constructor.
    • … can contain abstract and non-abstract methods.
    • … is represented in a UML diagram by prefixing its name with <<Abstract>>.
  5. In a UML diagram, an abstract method is …

    • … underlined.
    • … impossible to distinguish from a non-abstract method.
    • … necessarily part of an abstract class.
    • … in italics.
  6. A class Student inheriting from an abstract class Person

    • … must override all of Person’s methods.
    • … must implement all the methods marked abstract in Student.
    • … can be instantiated.
    • … is connected to Person using an open triangle end and a continuous line (⇽) on the UML diagram.
    • … is connected to Person using an open triangle end and a dashed line (◁┈) on the UML diagram.
  7. A method with header public virtual void Test(int a, out int b) will…

    • Return a value
    • Set the value of b
    • Require two arguments
    • Be overrideable
  8. A method with header public abstract string Test() will…

    • Have an empty body
    • Need to be inside an abstract class
    • Not be overriden
  9. A method …

    • … can be accessed from any class if it is marked protected.
    • … can be accessed from its derived classes if it is marked private.
    • … is recursive if it terminates.
    • … is recursive if it calls itself.
    • … must be overridden if it is marked abstract.
    • … cannot be overriden if it is marked sealed.
  10. Give at least two differences between an abstract class and an interface.

    Solution

    A possible list includes:

    • An abstract class can contain private methods.
    • An abstract class is inherited by another class, while an interface is realized by another class.
    • An class can inherit from only one abstract class, but it can realize multiple interfaces.
    • Interfaces do not need to explicitly mark their methods and properties as public or abstract, since they are always public and abstract.
    • Abstract methods in an abstract class need to be explicitly overridden by methods in the class inheriting from them, while classes realizing interfaces need not to mark the methods as explicitely overriding methods from the interface.

Problems

  1. Assume given the following class implementation:

    class Computer
    {
      private string brand;
     
      public void SetBrand(string brandP)
      {
        brand = brandP;
      }
     
      public Computer(string bP)
      {
        SetBrand(bP);
      }
     
      public override string ToString()
      {
        return $"Brand: {brand}";
      }
    }

    Write a Laptop class that

    1. Inherits from Computer,

    2. Has one single (automatic) property, called ScreenSize, of type int,

    3. Has a constructor that takes 2 parameters of appropriate datatypes, and use them to set brand and ScreenSize,

    4. Has a ToString method that returns a string containing the brand and screen size.

      Solution

      class Laptop : Computer
      {
        public int ScreenSize { get; set; }
       
        public Laptop(int ssP, string bP)
          : base(bP)
        {
          ScreenSize = ssP;
        }
       
        public override string ToString()
        {
          return base.ToString()
            + $"\nScreen size: {ScreenSize}\"";
        }
      }

      (Download this code)

  2. Consider the diagram representing the “Room”, “ClassRoom”, “Office” classes and their relations.

    A UML diagram for the Room ⇽ ClassRoom class (text version, image version, svg version)

    Suppose you are given an implementation of the Room class, such that

        Room test = new Room("UH", 243);
        Console.WriteLine(test);

    displays

    UH 243
    1. Write an implementation of the ClassRoom class. Your ToString method should display the room’s building and number, in addition to whether it has AV set-up.

      Solution

      class ClassRoom : Room
      {
        private bool av;
       
        public ClassRoom(string bP, int nP, bool aP)
          : base(bP, nP)
        {
          av = aP;
        }
       
        public override string ToString()
        {
          return base.ToString() + "av? " + av;
        }
      }
    2. Write a SameBuilding static method to be placed inside the Room class such that

      Office test1 = new Office("UH", 127, "706 737 1566");
      ClassRoom test2 = new ClassRoom("UH", 243, true);
      Office test3 = new Office("AH", 122, "706 729 2416");
      Console.WriteLine(Room.SameBuilding(test1, test2));
      Console.WriteLine(Room.SameBuilding(test2, test3));

      Would display “true” and “false”.

      Solution

        public static bool SameBuilding(Room a, Room b)
        {
          return a.building == b.building;
        }
  3. Consider the diagram representing the “Room”, “BedRoom”, “BathRoom” classes and their relations.

    A UML diagram for the Room ⇽ BedRoom class (text version, image version, svg version)
    1. Write an implementation of the SurfaceArea property for the Room class, assuming you are given an implementation of the Width and Length properties.

      Solution

        public double SurfaceArea
        {
          get { return Width * Length; }
        }

      (Download this code)

    2. Check the statements that would compile, assuming that rTest is a Room object, beTest is a BedRoom object, and baTest is a BathRoom object.

      • rTest.Capacity = 12;
      • baTest.Width = 12;
      • beTest.capacity = 3;
      • rTest.SurfaceArea = -2;
      • baTest.Capacity = 3;
      • beTest.Shower = true;
      • Console.WriteLine(baTest.ToString());
    3. Write a complete implementation of the BedRoom class.

      • Your Capacity property should use the capacity attribute, and throw an exception if the argument given is strictly less than 1.
      • Your ToString method should complement the Room’s ToString by appending to its string the capacity (in person) of the BedRoom object.

      Solution

      using System;
       
      class BedRoom : Room
      {
        private int capacity;
        public int Capacity
        {
          set
          {
            if (value < 0)
            {
              throw new ArgumentException(
                "A capacity must be positive or 0."
              );
            }
            else
            {
              capacity = value;
            }
          }
        }
       
        public BedRoom(double wP, double lP, int cP)
          : base(wP, lP)
        {
          Capacity = cP;
        }
       
        public override string ToString()
        {
          return base.ToString() + "Capacity: " + capacity;
        }
      }

      (Download this code)

    4. Write the ToString method of the BathRoom class, knowing that a disclaimer should be part of the string returned if the BathRoom has a shower or a bathtub but no hot water.

      Solution

        public override string ToString()
        {
          string equipement = "";
          if (Shower)
          {
            equipement += "a shower";
          }
          if (Shower && Bathtub)
          {
            equipement += " and ";
          }
          if (Bathtub)
          {
            equipement += "a bathtub";
          }
          if (!Shower && !Bathtub)
            equipement += "no shower nor bathtub";
          equipement += ".";
          if (!hotWater && (Shower || Bathtub))
          {
            equipement += " However, it does not have hot water";
          }
       
          return base.ToString()
            + "\nThis bathtub has "
            + equipement;
        }

      (Download this code)

  4. Consider the diagram representing the “Article”, “Book” classes and their relations.

    A UML diagram for the Article ⇽ Book class (text version, image version, svg version)
    1. Write a (partial) implementation of the Article abstract class:

      1. Write an implementation for the price attribute: you can either use a getter and a setter (as pictured in the UML diagram), or a property. However, in both cases, setting the price to a negative value should result in an ArgumentOutOfRangeException exception being thrown.
      2. Write an abstract ShippingCosts() method.

      Solution

      using System;
       
      abstract class Article
      {
        public string Id { get; set; }
        private decimal price;
       
        public void SetPrice(decimal priceP)
        {
          if (priceP < 0)
          {
            throw new ArgumentOutOfRangeException();
          }
          else
          {
            price = priceP;
          }
        }
       
        public decimal GetPrice()
        {
          return price;
        }
       
        public Article(string idP, decimal priceP)
        {
          Id = idP;
          SetPrice(priceP);
        }
       
        public abstract decimal ShippingCosts();
      }
    2. Now, assume given a complete implementation of the Article abstract class. Write a complete implementation of the Book class (header included), containing:

      1. An implementation of the Title property using auto-properties.
      2. A Book constructor that passes the idP and priceP arguments to the Article constructor. The titleP argument should be assigned to the Title property.
      3. A ShippingCosts() method that returns either 5.0, or 10% of the Book’s price, whichever is smallest.

      Solution

      class Book : Article
      {
        public string Title { get; set; }
       
        public Book(string idP, decimal priceP, string titleP)
          : base(idP, priceP)
        {
          Title = titleP;
        }
       
        public override decimal ShippingCosts()
        {
          decimal tenp = .1M * GetPrice();
          if (tenp > 5M)
          {
            tenp = 5M;
          }
          return tenp;
        }
      }
    3. Write statements that, if placed in a Main method, would

      1. Create a Book with Id “AAA001”, price $12.5, titled “What it’s like to be a bird”.
      2. Display (nicely) its shipping costs.
      3. Display its Id (as retrieved from the object).

      Solution

      using System;
       
      class Program
      {
        public static void Main()
        {
          Book test = new Book(
            "AAA001",
            12.5M,
            "What it's like to be a bird."
          );
          Console.WriteLine($"{test.ShippingCosts():C}");
          Console.WriteLine(test.Id);
        }
      }

      (Download this code)

  5. Consider the diagram representing the “Shape”, “Circle” and “Rectangle” classes, as well as their relations.

    A UML diagram for the Shape ⇽ Circle class (text version, image version, svg version)
    1. Write the complete implementation of the Shape abstract class. The ToString method should simply return the string "This shape is ".

      Solution

      public abstract class Shape
      {
        public abstract double GetArea();
       
        public override string ToString()
        {
          return "This shape is ";
        }
      }

      (Download this code)

    2. Write an implementation for the Radius property of the Circle class such that setting the radius to a negative value would result in an ArgumentOutOfRangeException (that you can shorten to AOORE) exception being thrown. Add an attribute if needed.

      Solution

        private int radius;
        public int Radius
        {
          get { return radius; }
          set
          {
            if (value < 0)
              throw new ArgumentException(
                "Radius must be strictly positive."
              );
            else
              radius = value;
          }
        }

      (Download this code)

    3. Write the Diameter property for the Circle class, which should return times the radius. Only the get should be provided: briefly explain why the set is missing.

      Solution

        public int Diameter
        {
          get { return Radius * 2; }
        }

      (Download this code) The set is missing because Diameter must be at all time be equal to Radius times 2. There is no point in storing the diamater separately, since this information can be recovered, and since storing it would require to change the value of Radius every time it is updated.

    4. Write an implementation for the ToString method of the Rectangle class that returns a string containing what was returned by the Shape’s ToString method, the width, length and area of the calling object. For example, for a Rectangle with width 10 and length 5, it should be of the form “This shape is a rectangle (W: 10, L: 5, Area: 50)“.

      Solution

        public override string ToString()
        {
          return base.ToString()
            + " a rectangle (W:"
            + Width
            + ", L:"
            + Length
            + ", Area: "
            + GetArea()
            + ")\n";
        }

      (Download this code)

    5. Write the Equals method for the Rectangle class. It should return true if the calling object and the parameter have the same lengths and same widths, or if one can be obtained by rotating the other.

      Solution

        public bool Equals(Rectangle rP)
        {
          return (rP.Length == Length && rP.Width == Width)
            || (rP.Length == Width && rP.Width == Length);
        }

      (Download this code)

    6. Briefly explain how Shape could be converted into an interface and what would be the benefit(s) and disadvantage(s) of carrying out such a modification.

      Solution

      A Shape interface would be

      • less code,
      • without the need to explicitly list the methods as public and abstract,
      • not capable of specifying what the beginning of the string returned by the ToString method should be, or to give any non-abstract method for that matter.

      Another benefit is that the Rectangle and Circle classes could realize multiple interfaces instead of only inheriting from the Shape class.

      Its implementation would be:

      interface Shape
      {
          double GetArea();
      }

      Note that our interface cannot have a ToString method, for a delicate reason that we explain now, but that was not supposed to be part of the answer. You cannot force the implementation of a ToString with an interface, as discussed for example in this stack exchange post, where an alternative solution is provided (essentially: use an abstract class).

      You can convince yourself that this is the case by downloading and compiling the following two files:

      interface IToString
      {
        string ToString();
      }

      (Download this code)

      class Demo : IToString
      {
        public string Name { get; set; }
       
        public Demo(string nameP)
        {
          Name = nameP;
        }
        // public override string ToString(){return "The name attribute contains:" + Name;}
      }

      (Download this code) This code would indeed compile just fine, even if Demo does not provide the implementation of a ToString method. Of course, Demo already posses a ToString method, the one every class inherits.