Function Overloading C++ supports writing more than one function with the same name but different argument lists How does the compiler know which one the programmer is calling? They have different signatures A function s signature is a combination of its name and its argument list the return type is not part of the signature so you can t overload just by changing return type 1
When you use function overloading, ambiguity can happen in 3 cases: 1. if you have call by reference and call by value with the same parameters types: void square (double& x) { x = x * x; void square (double x) { cout << x * x; 2. if there is no matching parameter type for a called function but variables can be automatically converted to appropriate types: int area (int height, int width) { return height * width; double area (double height, double width) { return height * width; 3. if you use default arguments: prototypes: void fcn(int a, int b = 9, double c = 1.33); void fcn(int a, int b); 2
Function Overloading (cont.) Suppose that we have a scenario such as: void swap (int *a, int *b); void swap (double *x, double *y); void swap (bool *p, bool *q); int main() { int i = 4, j = 6; double c = 13.2, d = 43.1; bool flag1 = TRUE, flag2 = FALSE; swap (&i, &j); swap (&c, &d); swap (&flag1, &flag2); with function definitions as shown on the next slide: 3
void swap (int *a, int *b) { int temp; temp = *a; *a = *b; *b = temp; void swap (double *x, double *y) { double temp; temp = *x; *x = *y; *y = temp; void swap (bool *p, bool *q) { bool temp; temp = *p; *p = *q; *q = temp; Each of these functions expects to see pointers as arguments the only difference is what kind of thing the pointer argument is pointing to The compiler matches up the signature in the function definition with the call so that the correct version gets invoked 4
Remember Function Templates No need for 3 different functions We could create a function template definition for swap the function template sets up the framework for the functions we need, then based on how the template is called, the compiler generates the necessary code Example: template <typename T> void swap(t *a, T *b) { T temp; temp = *a; *a = *b; *b = temp; the keyword template tells the compiler it s a function template this is the function s return type here it is void because the original swap functions had void return type everywhere a T occurs in the template, the compiler will substitute the correct type depending on the call to the function 5
One More (trivial) Template Example - template <class T> T square (T x) { return x * x; if called with an int argument, this will return an int result; if called with a double argument, it will return a double. 6
Object Oriented Design Where do we stand now? We ve talked about classes and their definition class definition in <classname>.h file this defines the interfaces for the class implementation of the methods in <classname>.cpp file We ve talked about constructors and destructors default constructor and overloaded constructors issues to consider when a class has a member that is dynamic order of method invocation as a program runs (explored through a trace of what happens in an example using the point class) We discussed copy constructors and saw an example 7
Just to remind you: Constructors: What Happens by Default If you do not define a constructor, the system will define a default constructor the default constructor is supposed to initialize all numeric types to 0, all pointers to null, and all Boolean types to false (but be careful check that it really does this!) If you do define a constructor, yours will be used whenever an object of this type is instantiated that is, whenever an object is declared or new or gcnew is called to create an object of this type If you provide a constructor that takes a nonvoid parameter, you must also provide a default constructor. objects of managed classes must always be declared as tracking handles (otherwise you ll get a compile error) 8
Destructors: What Happens by Default A destructor is a function that: Is automatically invoked when an object is destroyed i.e. at the end of the block in which an object was declared Performs termination housekeeping In particular, it recovers memory to be reused On block exit, destructors for objects declared in the block are called in reverse order of object instantiation (see class example) Takes no arguments and returns no value Has the same name as the class preceded by a ~ There is only one destructor for a class no overloading is possible The system automatically generates a destructor for a class, but Programmers do have to write a destructor when their class dynamically allocates memory (which can happen when data members are pointers or array names or CLI objects) 9
= Operators: What Happens by Default Ordinarily, the compiler will generate a default assignment operator a point class (that has two double data members) is an example of a case in which the = operator is automatically overloaded by the compiler If you define any assignment operator that takes the class as a parameter, the compiler cannot generate a default assignment operator for that class. In these cases, you have to provide an overloaded assignment operator 10
Why do we need a copy constructor? If a copy constructor is missing (for any class), the compiler creates a default one that performs member-by-member copying. For classes that have dynamic members, we need to have appropriate memberwise copy functions (we ve seen an example of why) Let s revisit the class MemberInfo that we looked at before We re going to look at 4 different ways to represent the same information then consider how statements execute differently (and why) 11
#pragma once #ifndef MEMB1 #define MEMB1 using namespace System; Class MemberInfo header: ref class MemberInfo{ public: MemberInfo(); MemberInfo(MemberInfo %); void entername(); void enterage(); String^ getname(); int getage(); void setname(string^); void setage(int); void display(); ~MemberInfo(); private: String ^name; int age; static int count; ; #endif // default constructor // copy constructor // method for entering name // method for entering age // method for extracting name // method for extracting age // method for setting name to a value // method for setting age to a value // method for display of the object s data // destructor 12
// MANAGED CLASS ref class MemberInfo{ public: static int count; MemberInfo(); MemberInfo(MemberInfo %); void entername(); void enterage(); String^ getname(); int getage(); void setname(string^); void setage(int); void display(); ~MemberInfo(); private: String ^name; int age; ; M_Info // STANDARD C++ CLASS // copy constructor w/ ref parameter class MemberInfo{ public: static int count; MemberInfo(); MemberInfo(MemberInfo &); void entername(); void enterage(); string* getname(); int getage(); void setname(string*); void setage(int); void display(); ~MemberInfo(); private: string * name; int age; ; Native M_Info2
// STANDARD C++ CLASS // pointer to string type data member class MemberInfo{ public: static int count; // STANDARD C++ CLASS // string type data member class MemberInfo{ public: static int count; private: ; MemberInfo(); MemberInfo(MemberInfo *); void entername(); void enterage(); string* getname(); int getage(); void setname(string*); void setage(int); void display(); ~MemberInfo(); string * name; int age; private: ; MemberInfo(); MemberInfo(MemberInfo &); void entername(); void enterage(); string getname(); int getage(); void setname(string); void setage(int); void display(); ~MemberInfo(); string name; int age; Native M_Info1 Native M_Info
What happens with = and ==? M_Info Has members MemberInfo(MemberInfo %); String ^name; Does not allow this sequence of statements MemberInfo ^n1, ^n2; *n1 = *n2; // error C2582: 'operator =' function is unavailable Allows this sequence of statements: if (n1 == n2) cout << "equal \n"; Native M_Info Has members MemberInfo(MemberInfo &); string name; Allows this sequence of statements: MemberInfo *n1, *n2; *n1 = *n2; Does not allow if (n1 == n2) cout << "equal \n"; Why should this allow ==? Executes the default assignment operator // error C2678: binary '==' : no operator found which takes a left-hand operand of type 'MemberInfo' (or there is no acceptable conversion)
What happens with = and ==? Native M_Info 1 Has members MemberInfo(MemberInfo *); string * name; int age; Allows MemberInfo *n1, *n2; *n1 = *n2; if (n1 == n2) cout << "equal \n"; Native M_Info 2 Has members MemberInfo(MemberInfo &); string* name; int age; Allows MemberInfo *n1, *n3; *n1 = *n3; if (n1 == n3) cout << "equal \n"; Why should this allow assignment and ==? Why should this allow assignment and ==? Moral of the story: Be sure you know what = (assignment) and == (equality test) really mean for your class!
Overloading Operators in C++ C++ allows the programmer to redefine the function of most built-in operators on a class-by-class basis the operator keyword is used to declare a function that specifies what an operator symbol (such as = or +) means when it is applied to instances of a class this gives the operator more than one meaning, and the compiler determines what meaning is intended by looking at the types of its operands syntax: type operator <operator-symbol> (parameter-list) Example: overloading the addition operator and the assignment operator for a class Complex that is intended to represent complex numbers
Example Class to represent complex numbers: header (class definition file) #pragma once #include <iostream> using namespace System; using namespace std; class Complex { public: Complex (); Complex (double r, double i); Complex operator+ (Complex &other); Complex & Complex::operator = (Complex &n); void display(); private: double re,im; ;
.cpp source (implementation) file for for class Complex #include "stdafx.h" #include " Complex.h" Complex::Complex (){ re = 0.0; im = 0.0; Complex::Complex(double r, double i){ re = r; im = i; Overloaded addition operator Complex Complex::operator + (Complex &other){ return Complex (re + other.re, im + other.im); Complex & Complex::operator = (Complex &n){ re = n.re; im = n.im; return *this; Overloaded assignment operator void Complex::display(){ cout << re << "," << im << endl;
Example of a small program using class Complex: #include "stdafx.h" #include <iostream> #include "Complex.h" using namespace System; using namespace std; int main(array<system::string ^> ^args) { Complex a = Complex(1.2, 3.4); Complex b(3.4, 5.6); Complex c; c = a + b; c.display(); return 0;
Not every operator can be overloaded! Operators that can be overloaded + - * / % ^ & ~! = < > += -= *= /= %= ^= &= = << >> >>= <<= ==!= <= >= && ++ -- ->*, -> [] () new delete new[] delete[] Operators that cannot be overloaded..* ::?: sizeof