Chapter 12: Operator Overloading

Quiz Solutions

Solution to Question 12-1. Operator overloading is the process of writing methods for your class that allow clients of your class to interact with your class using standard operators (such as + and ==).

Solution to Question 12-2. Operators are implemented as static methods.

Solution to Question 12-3. To overload an operator, you use the keyword operator along with the operator you’re overloading. For example, to overload the addition operator, you would use the keyword operator+.

Solution to Question 12-4. The compiler interprets the statement as a call to the method:

public static Fraction operator+(f2, f1)

Solution to Question 12-5. This answer is subjective, but it seems likely that choices A and D are the most reasonable. Choices B and C are not completely unreasonable, but aren’t intuitive, and would be difficult for later developers to maintain.

Solution to Question 12-6. The < and > operators are paired, as are the <= and >= operators. If you overload one of the operators in a pair, you must overload the other.

Solution to Question 12-7. If you overload the == operator, you must also overload the != operator, and the Equals( ) method.

Solution to Question 12-8. The Equals( ) method is used to ensure that your class is compatible with other .NET languages that do not allow operator overloading, but do allow method overloading.

Solution to Question 12-9. To overload the conversion operators, you use either the keyword implicit or the keyword explicit, along with the keyword operator, and the name of the type you’re converting to.

Solution to Question 12-10. Use implicit conversion when you know the conversion will succeed without the risk of losing information. Use explicit conversion if information might be lost.

Exercise Solutions

Solution to Exercise 12-1. Create a class Invoice, which has a string property vendor and a double property amount, as well as a method to output the two properties of the invoice. Overload the addition operator so that if the vendor properties match, the amount properties of the two invoices are added together in a new invoice. If the vendor properties do not match, the new invoice is blank. Include some test code to test the addition operator.

This exercise is fairly straightforward. The Invoice class is simple enough to create; you just need to write the two private members, a constructor, and an output method. Then you need to create an overloaded addition operator for your class. The operator should first make sure the vendor fields match, and if they do, should create a new Invoice (using the constructor) with the greater amount. Example A-30 shows one solution.

Example A-30. One solution to Exercise 12-1

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Exercise_12_1
{
    public class Invoice
    {
        private string vendor;
        private double amount;
        // constructor

        public Invoice(string vendor, double amount)
        {
            this.vendor = vendor;
            this.amount = amount;
        }
        // Overloaded operator + takes two invoices.
        // If the vendors are the same, the two amounts are added.
        // If not, the operation fails, and a blank invoice is returned.
        public static Invoice operator+ (Invoice lhs, Invoice rhs)
        {
            if (lhs.vendor == rhs.vendor)
            {
                return new Invoice(lhs.vendor, lhs.amount + rhs.amount);
            }
            Console.WriteLine("Vendors don't match; operation failed.");
            return new Invoice("", 0);
        }
        public void PrintInvoice(  )
        {
            Console.WriteLine("Invoice from {0} for ${1}.", vendor, amount);
        }
    }

    public class Tester
    {
        public void Run(  )
        {
            Invoice firstInvoice = new Invoice("TinyCorp", 345);
            Invoice secondInvoice = new Invoice("SuperMegaCo", 56389.53);
            Invoice thirdInvoice = new Invoice("SuperMegaCo", 399.65);
            Console.WriteLine("Adding first and second invoices.");
            Invoice addedInvoice = firstInvoice + secondInvoice;
            addedInvoice.PrintInvoice(  );
            Console.WriteLine("Adding second and third invoices.");
            Invoice otherAddedInvoice = secondInvoice + thirdInvoice;
            otherAddedInvoice.PrintInvoice(  );
        }
        static void Main(  )
        {
            Tester t = new Tester(  );
            t.Run(  );
        }
    }
}

Solution to Exercise 12-2. Modify the Invoice class so that two invoices are considered equal if the vendor and amount properties match. Test your methods.

Starting with the previous code is easy enough. The first change you need to make is to override the == operator, exactly as we showed you in the chapter. Once you’ve done that, you also need to override the != operator and the Equals( ) method. Add some test cases in Run( ) to make sure this works. Example A-31 has our solution.

Example A-31. Our solution to Exercise 12-2

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Exercise_12_2
{
    using System;

    public class Invoice
    {
        private string vendor;
        private double amount;

        // constructor
        public Invoice(string vendor, double amount)
        {
            this.vendor = vendor;
            this.amount = amount;
        }

        // Overloaded operator + takes two invoices.
        // If the vendors are the same, the two amounts are added.
        // If not, the operation fails, and a blank invoice is returned.
        public static Invoice operator +(Invoice lhs, Invoice rhs)
        {
            if (lhs.vendor == rhs.vendor)
            {
                return new Invoice(lhs.vendor, lhs.amount + rhs.amount);
            }
            Console.WriteLine("Vendors don't match; operation failed.");
            return new Invoice("", 0);
        }

        // overloaded equality operator
        public static bool operator ==(Invoice lhs, Invoice rhs)
        {
            if (lhs.vendor == rhs.vendor && lhs.amount == rhs.amount)
            {
                return true;
            }
            return false;
        }

        // overloaded inequality operator, delegates to ==
        public static bool operator !=(Invoice lhs, Invoice rhs)
        {
            return !(lhs == rhs);
        }

        // method for determining equality; tests for same type,
        // then delegates to ==
        public override bool Equals(object o)
        {
            if (!(o is Invoice))
            {
                return false;
            }
            return this == (Invoice)o;
        }

        public void PrintInvoice(  )
        {
            Console.WriteLine("Invoice from {0} for ${1}.", this.vendor,
                              this.amount);
        }
    }

    public class Tester
    {
        public void Run(  )
        {
            Invoice firstInvoice = new Invoice("TinyCorp", 399.65);
            Invoice secondInvoice = new Invoice("SuperMegaCo", 56389.53);
            Invoice thirdInvoice = new Invoice("SuperMegaCo", 399.65);
            Invoice testInvoice = new Invoice("SuperMegaCo", 399.65);
            if (testInvoice == firstInvoice)
            {
                Console.WriteLine("First invoice matches.");
            }
            else if (testInvoice == secondInvoice)
            {
                Console.WriteLine("Second invoice matches.");
            }
            else if (testInvoice == thirdInvoice)
            {
                Console.WriteLine("Third invoice matches.");
            }
            else
            {
                Console.WriteLine("No matching invoices.");
            }
        }
        static void Main(  )
        {
            Tester t = new Tester(  );
            t.Run(  );
        }
    }
}

Try changing the values of testInvoice to make sure all the cases work.

Solution to Exercise 12-3. Modify the Invoice class once more so that you can determine whether one invoice is greater than or less than another. Test your methods.

In this exercise, you’ll need to overload a couple of methods that you haven’t seen in the chapter: the greater-than and less-than operators. Fortunately, overloading those methods isn’t much more difficult than overloading the equality operator. However, you need to be sure you override both operators. Remember that you can’t simply define the less-than operator as the opposite of the greater-than operator, the way you can with == and !=, because if the operands are equal, both less-than and greater-than should return false. Example A-32 shows a possible solution.

Example A-32. One solution to Exercise 12-3

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Exercise_12_3
{
    public class Invoice
    {
        private string vendor;
        private double amount;

        // constructor
        public Invoice(string vendor, double amount)
        {
            this.vendor = vendor;
            this.amount = amount;
        }

        // Overloaded operator + takes two invoices.
        // If the vendors are the same, the two amounts are added.
        // If not, the operation fails, and a blank invoice is returned.
        public static Invoice operator +(Invoice lhs, Invoice rhs)
        {
            if (lhs.vendor == rhs.vendor)
            {
                return new Invoice(lhs.vendor, lhs.amount + rhs.amount);
            }
            Console.WriteLine("Vendors don't match; operation failed.");
            return new Invoice("", 0);
        }

        // overloaded equality operator
        public static bool operator ==(Invoice lhs, Invoice rhs)
        {
            if (lhs.vendor == rhs.vendor && lhs.amount == rhs.amount)
            {
                return true;
            }
            return false;
        }

        // overloaded inequality operator, delegates to ==
        public static bool operator !=(Invoice lhs, Invoice rhs)
        {
            return !(lhs == rhs);
        }

        // method for determining equality; tests for same type,
        // then delegates to ==
        public override bool Equals(object o)
        {
            if (!(o is Invoice))
            {
                return false;
            }
            return this == (Invoice)o;
        }

        public static bool operator< (Invoice lhs, Invoice rhs)
        {
            if (lhs.amount < rhs.amount)
            {
                return true;
            }
            return false;
        }

        public static bool operator> (Invoice lhs, Invoice rhs)
        {
            if (lhs.amount > rhs.amount)
            {
               return true;
            }
            return false;
        }

        public void PrintInvoice(  )
        {
            Console.WriteLine("Invoice from {0} for ${1}.", this.vendor,
                               this.amount);
        }
    }

    public class Tester
    {

        public Invoice WhichIsGreater(Invoice invoice1, Invoice invoice2)
        {
            if (invoice1 > invoice2)
            {
                return invoice1;
            }
            else
            {
                return invoice2;
            }
        }

        public void Run(  )
        {
            Invoice firstInvoice = new Invoice("TinyCorp", 399.65);
            Invoice secondInvoice = new Invoice("SuperMegaCo", 56389.53);
            Invoice thirdInvoice = new Invoice("SuperMegaCo", 399.65);
            Invoice tempInvoice;

            if (!(firstInvoice == secondInvoice))
            {
                Console.WriteLine("Greater Invoice:");
                tempInvoice = WhichIsGreater(firstInvoice, secondInvoice);
                tempInvoice.PrintInvoice(  );
            }
            else
            {
                Console.WriteLine("firstInvoice and secondInvoice are equal");
            }

            if (!(secondInvoice == thirdInvoice))
            {
                Console.WriteLine("Greater Invoice:");
                tempInvoice = WhichIsGreater(secondInvoice, thirdInvoice);
                tempInvoice.PrintInvoice(  );
            }
            else
            {
                Console.WriteLine("secondInvoice and thirdInvoice are equal");
            }

        }

        static void Main(  )
        {
            Tester t = new Tester(  );
            t.Run(  );
        }
    }
}

We didn’t implement the <= or >= methods in this example, but you should go ahead and try it on your own.

Solution to Exercise 12-4. Create a class Foot and a class Meter. Each should have a single parameter that stores the length of the object, and a simple method to output that length. Create a casting operator for each class: one that converts a Foot object to a Meter object, and one that converts a Meter object to a Foot object. Test these operators to make sure they work.

First, it should be said that the Foot and Meter classes don’t make a lot of sense in the real world. It would most likely be better to create a class Measurement, or something similar, that could output the length in either feet or meters. Still, you’ve got two classes, so you should be able to convert between them. Since you’re using two user-defined classes here, you won’t be able to write an implicit conversion. Therefore, Foot needs an explicit conversion to Meter, and Meter needs an explicit conversion to Foot. For example, here’s the declaration for the Foot class’s conversion to Meter:

public static explicit operator Meter(Foot theFoot)

Note that this operator is public, static, and explicit. The body of the operator method isn’t really challenging, but remember that it should return an object of class Meter. The Meter class operator is similar. Example A-33 shows one way to do it.

Example A-33. One solution to Exercise 12-4

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Exercise_12_4
{
    public class Foot
    {
        private double length;

        public static explicit operator Meter(Foot theFoot)
        {
            return new Meter(theFoot.length * 0.3048);
        }

        public void OutputFoot(  )
        {
            Console.Write("{0} feet", length);
        }

        // constructor
        public Foot(double length)
        {
            this.length = length;
        }
    }

    public class Meter
    {
        private double length;

        public static explicit operator Foot (Meter theMeter)
        {
            return new Foot(theMeter.length * 3.28);
        }

        public void OutputMeter(  )
        {
            Console.Write("{0} meters", length);
        }

        // constructor
        public Meter(double length)
        {
            this.length = length;
        }
    }

    class Tester
    {
        public void Run(  )
        {
            Foot myFoot = new Foot(5);
            Meter myMeter = new Meter(3);

            Console.Write("Length of myFoot = ");
            myFoot.OutputFoot(  );
            Console.Write(", ");
            ((Meter)myFoot).OutputMeter(  );
            Console.WriteLine(  );

            Console.Write("Length of myMeter = ");
            myMeter.OutputMeter(  );
            Console.Write(", ");
            ((Foot)myMeter).OutputFoot(  );
            Console.WriteLine(  );

        }

        static void Main(string[] args)
        {
            Tester t = new Tester(  );
            t.Run(  );
        }
    }
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset