Introduction to Object Oriented Programming, 3rd Ed

Timothy A. Budd

Chapter 15

Overloading

Outline

  1. Roadmap
  2. Definition of Overloading
  3. Overloading Based on Scopes
    1. Florist Example from Chapter 1
    2. Resolving Overloaded Names
  4. Overloading Based on type Signatures
    1. Resolution Performed at Compile Time
    2. Stream Output in C++
    3. Easy to Extend
    4. Conversion and Coercison
  5. Redefinitions
    1. Example Illustrating Redefinition Models
  6. Optional Parameters
    1. Arbitrary Number of Arguments in C#
  7. Chapter Summary

Other Material

Intro OOP, Chapter 15, Outline

Roadmap

In this chapter we will investigate the idea of overloading.
Intro OOP, Chapter 15, Slide 01

A Definition of Overloading

We say a term is overloaded if it has two or more meanings.

Most words in natural languages are overloaded, and confusion is resolved by means of context.

Same is true of OO languages. There are two important classes of context that are used to resolve overloaded names

Intro OOP, Chapter 15, Slide 02

Overloading Based on Scopes

A name scope defines the portion of a program in which a name can be used, or the way it can be used. Scopes are introduced using lots of different mechanisms: An advantage of scopes is that the same name can appear in two or more scopes with no ambiguity.
Intro OOP, Chapter 15, Slide 03

Florist Example from Chapter 1

Procedure Friend.sendFlowersTo (anAddress : address);
begin
	go to florist;
	give florist message sendFlowersTo(anAddress);
end;

Procedure Florist.sendFlowersTo (anAddress : address);
begin
	if address is nearby then
		make up flower arrangement
		tell delivery person sendFlowersTo(anAddress);
	else
		look up florist near anAddress
		phone florist
		give florist message sendFlowersTo(anAddress)
end;
Intro OOP, Chapter 15, Slide 04

Resolving Overloaded Names

This type of overloading is resolved by looking at the type of the receiver.

Allows the same name to be used in unrelated classes.

Since names need not be distinct, allows short, easy to remember, meaningful names.

Intro OOP, Chapter 15, Slide 05

Overloading Based on Type Signatures

A different type of overloading allows multiple implementations in the same scope to be resolved using type signatures.
class Example {
		// same name, three different methods
	int sum (int a) { return a; }
	int sum (int a, int b) { return a + b; }
	int sum (int a, int b, int c) { return a + b + c; }
}
A type signature is the combination of argument types and return type. By looking at the signature of a call, can tell which version is intended.
Intro OOP, Chapter 15, Slide 06

Resolution Performed at Compile Time

Note that resolution is almost always performed at compile time, based on static types, and not dynamic values.
class Parent { ... };

class Child : public Parent { ... };

void Test(Parent * p) { cout << "in parent" << endl; }
void Test(Child * c) { cout << "in child" << endl }

	Parent * value = new Child();

	Test(value); 
Example will, perhaps surprizingly, execute parent function.
Intro OOP, Chapter 15, Slide 07

Stream Output in C++

Stream output in C++ is a good example of the power of overloading. Every primitive type has a different stream output function.
	ostream & operator << (ostream & destination, int source);
	ostream & operator << (ostream & destination, short source);
	ostream & operator << (ostream & destination, long source);
	ostream & operator << (ostream & destination, char source);
	ostream & operator << (ostream & destination, char *  source);
	// ... and so on

	double d = 3.14;
	cout << "The answer is " << d << '\n';
Intro OOP, Chapter 15, Slide 08

Easy to Extend

Since output uses overloading, it is very easy to extend to new types.
class Fraction {
public:
	Fraction (int top, int bottom) { t = top; b = bottom; }

	int numerator() { return t; }
	int denominator() { return b; }

private:
	int t, b;
};

ostream & operator << (ostream & destination, Fraction & source)
{
	destination << source.numerator() << "/" << source.denominator();
	return destination;
}

Fraction f(3, 4);
cout << "The value of f is " << f << '\n';
Intro OOP, Chapter 15, Slide 09

Conversion and Coercisons

When one adds conversions into the mix, resolving overloaded function or method calls can get very complex. Many different types of conversions: See text for illustration of the complex rules.
Intro OOP, Chapter 15, Slide 10

Redefinitions

A redefinition occurs when a child class changes the type signature of a method in the parent class.
Two different types of rules are used to resolve name:
Intro OOP, Chapter 15, Slide 11

Example Illustrating Redefinition Models

The following example will illustrate the difference in these two models.
class Parent {
	public void example (int a) 
		{ System.out.println("in parent method"); }
}

class Child extends Parent {
	public void example (int a, int b)
		{ System.out.println("in child method"); }
}

	Child aChild = new Child();
	aChild.example(3);
Will execute parent method in Java and C# (Merge model) and give error in C++ (hierarchical model). Delphi allows programmer control over this.
Intro OOP, Chapter 15, Slide 12

Optional Parameters

Some languages allow the programmer to create optional parameters, usually only at the end of the parameter list:
function Count (A, B : Integer; C : Integer = 0; D : Integer = 0);
begin
		(* Result is a pseudo-variable used *)
		(* to represent result of any function *)
	Result := A + B + C + D;
end

begin
	Writeln (Count(2, 3, 4, 5)); // can use four arguments
	Writeln (Count(2, 3, 4)); // or three
	Writeln (Count(2, 3)); // or two
end
Such a program will have more than one type signature.
Intro OOP, Chapter 15, Slide 13

Arbitrary Number of Arguments in C#

The language C# has an interesting way to include arbitrary number of arguments:
class ParamsExample {
	public void Write (int x) {
		// use this with one argument
		WriteString("Example one "); 
		WriteString(x.ToString());
	}

	public void Write (double x, int y) {
		// use this with two arguments
		WriteString("Example two ");
		WriteString(x.ToString()); 
		WriteString(y.ToString());
	}

	public void Write (params object [ ] args) {
		// use this with any other combination 
		WriteString("Example three ");
		for (int i = 0; i < args.GetLength(0); i++)
			WriteString(args[i].ToString());
	}
}

	ParamsExample p;
	p.Write(42);
Example one 42
	p.Write(3.14,159);
Example two 3.14159
	p.Write(1,2,3,4);
Example three 1234
	p.Write(3.14);
Example three 3.14
	p.Write(3,"abc");
Example three 3abc

Intro OOP, Chapter 15, Slide 14

Chapter Summary

In this chapter we have looked at various aspects of overloading
Intro OOP, Chapter 15, Slide 15