3.8. Operator Overloading

 < Day Day Up > 

Built-in operators such as + and - are used so instinctively that one rarely thinks of them as a predefined implementation for manipulating intrinsic types. In C#, for example, the + operator is used for addition or concatenation depending on the data types involved. Clearly, each must be supported by different underlying code. Because the compiler knows what a numeric and string type represent, it is quite capable of doing this. It makes sense then that these operators cannot be applied to custom classes or structures of which the compiler has no knowledge.

It turns out that C# provides a mechanism referred to as operator overloading that enables a class to implement code that determines how the class responds to the operator. The code for overloading an operator is syntactically similar to that of a method:

 public static <return type> operator <op> ( parameter list) { implementation code} 

Several rules govern its usage:

  • The public and static modifiers are required.

  • The return type is the class type when working with classes. It can never be void.

  • op is a binary, unary, or relational operator. Both equals (==) and not equals (!=) must be implemented in a relational pair.

  • Binary operators require two arguments; unary operators require one argument.

Operator overloading with classes does not have to be limited to geometric or spatial objects. The example shown in Listing 3-14 demonstrates how to use the concept to maintain stocks in a portfolio. It contains two classes: one that represents a stock (defined by its price, number of shares, and risk factor) and one that represents the portfolio of stocks. Two overloaded operators (+ and -) add and remove stocks from the portfolio.

Listing 3-14. Operator Overloading for Classes
 using System; class Portfolio {    public decimal risk;    public decimal totValue;    // Overloaded operator to add stock to Portfolio    public static Portfolio operator + (Portfolio p,Stock s)    {       decimal currVal  = p.totValue;       decimal currRisk = p.risk;       p.totValue = p.totValue + s.StockVal;       p.risk = (currVal/p.totValue)*p.risk +          (s.StockVal/p.totValue)* s.BetaVal;       return p;    }    // Overloaded operator to remove stock from Portfolio    public static Portfolio operator - (Portfolio p,Stock s)    {       p.totValue = p.totValue - s.StockVal;       p.risk = p.risk - ((s.BetaVal-p.risk)                        *(s.StockVal/p.totValue));       return p;    } } class Stock {    private decimal value;    private decimal beta; // risk increases with value    public  Stock(decimal myBeta, decimal myValue,                  int shares)    {       value = (decimal) myValue * shares;       beta = myBeta;    }    public decimal StockVal       { get {return value; } }    public decimal BetaVal       { get {return beta; } } } class MyApp {    public static void Main()    {       Portfolio p = new Portfolio();       // 200 shs of HPQ at $25, 100 shs of IBM @ $95       Stock hpq  = new Stock(1.1M, 25M, 200);       Stock ibm  = new Stock(1.05M, 95.0M, 100);       p += hpq;   // Add hpq       p += ibm;   // Add ibm       Console.Write("value:{0} ",p.totValue.ToString());       Console.WriteLine(" risk: {0}",                         p.risk.ToString("#.00"));       // value = 14,500 and risk = 1.07       p -= ibm;   // Remove ibm from portfolio       Console.Write("value:{0} ",p.totValue.ToString());       Console.Write(" risk: {0}",p.risk.ToString("#.00"));       // value = 5000 and risk = 1.10    } } 

The addition or deletion of a stock causes the portfolio total value and weighted risk factor to be adjusted. For example, when both stocks are added to the portfolio, the risk is 1.07. Remove ibm and the risk is 1.10, the risk of hpq alone.

When choosing to implement operator overloading, be aware that .NET languages are not required to support it. The easiest way to provide interoperability for those languages (such as Visual Basic.NET) lacking this feature is to include an additional class member that performs the same function:

 public static Portfolio AddStocks ( Portfolio p, Stock s) { return p + s; } 

In this case, the code exposes a public method whose implementation calls the overloaded method.

Another approach is to take advantage of the fact that language interaction occurs at the Intermediate Language level and that each operator is represented in the IL by a hidden method. Thus, if a language knows how to invoke this method, it can access the operator.

The ECMA standard provides a list of method names that correspond to each operator. For example, the + and & used in the preceding code are represented by op_Addition and op_BitwiseAnd, respectively. A language would access the overloaded + operator with its own syntactic variation of the following code:

 newPortfolio = P.op_Addition(P, s) 

Either approach works, but relying on assembly language is probably less appealing than providing a custom public method.

Although the discussion has been on classes, operator overloading also can be applied to simple data types. For example, you could define your own exponentiation operator for integers.

     < Day Day Up > 

    Core C# and  .NET
    Core C# and .NET
    ISBN: 131472275
    EAN: N/A
    Year: 2005
    Pages: 219

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