Question? Leave a message!




How to reuse code

How to reuse code
6.096 Lecture 3: Functions How to reuse code Geza Kovacs include iostream using namespace std; int main() int threeExpFour = 1; for (int i = 0; i 4; i = i + 1) threeExpFour = threeExpFour 3; cout "34 is " threeExpFour endl; return 0; include iostream using namespace std; Copypaste int main() coding int threeExpFour = 1; for (int i = 0; i 4; i = i + 1) threeExpFour = threeExpFour 3; cout "34 is " threeExpFour endl; int sixExpFive = 1; for (int i = 0; i 5; i = i + 1) sixExpFive = sixExpFive 6; cout "65 is " sixExpFive endl; return 0; include iostream using namespace std; Copypaste int main() coding int threeExpFour = 1; for (int i = 0; i 4; i = i + 1) (bad) threeExpFour = threeExpFour 3; cout "34 is " threeExpFour endl; int sixExpFive = 1; for (int i = 0; i 5; i = i + 1) sixExpFive = sixExpFive 6; cout "65 is " sixExpFive endl; int twelveExpTen = 1; for (int i = 0; i 10; i = i + 1) twelveExpTen = twelveExpTen 12; cout "1210 is " twelveExpTen endl; return 0; include iostream With a using namespace std; function // some code which raises an arbitrary integer // to an arbitrary power int main() int threeExpFour = raiseToPower(3, 4); cout "34 is " threeExpFour endl; return 0; include iostream With a using namespace std; function // some code which raises an arbitrary integer // to an arbitrary power int main() int threeExpFour = raiseToPower(3, 4); cout "34 is " threeExpFour endl; int sixExpFive = raiseToPower(6, 5); cout "65 is " sixExpFive endl; return 0; include iostream With a using namespace std; function // some code which raises an arbitrary integer // to an arbitrary power int main() int threeExpFour = raiseToPower(3, 4); cout "34 is " threeExpFour endl; int sixExpFive = raiseToPower(6, 5); cout "65 is " sixExpFive endl; int twelveExpTen = raiseToPower(12, 10); cout "1210 is " twelveExpTen endl; return 0; Why define your own functions • Readability: sqrt(5) is clearer than copypasting in an algorithm to compute the square root • Maintainability: To change the algorithm, just change the function (vs changing it everywhere you ever used it) • Code reuse: Lets other people use algorithms you’ve implemented Function Declaration Syntax Function name int raiseToPower(int base, int exponent) int result = 1; for (int i = 0; i exponent; i = i + 1) result = result base; return result; Function Declaration Syntax Return type int raiseToPower(int base, int exponent) int result = 1; for (int i = 0; i exponent; i = i + 1) result = result base; return result; Function Declaration Syntax Argument 1 int raiseToPower(int base, int exponent) int result = 1; for (int i = 0; i exponent; i = i + 1) result = result base; return result; • Argument order matters: – raiseToPower(2,3) is 23=8 – raiseToPower(3,2) is 32=9 Function Declaration Syntax Argument 2 int raiseToPower(int base, int exponent) int result = 1; for (int i = 0; i exponent; i = i + 1) result = result base; return result; • Argument order matters: – raiseToPower(2,3) is 23=8 – raiseToPower(3,2) is 32=9 Function Declaration Syntax int raiseToPower(int base, int exponent) signature int result = 1; for (int i = 0; i exponent; i = i + 1) result = result base; return result; Function Declaration Syntax int raiseToPower(int base, int exponent) int result = 1; for (int i = 0; i exponent; i = i + 1) result = result base; body return result; Function Declaration Syntax int raiseToPower(int base, int exponent) int result = 1; for (int i = 0; i exponent; i = i + 1) result = result base; return result; Return statement include iostream using namespace std; int raiseToPower(int base, int exponent) Function int result = 1; declaration for (int i = 0; i exponent; i = i + 1) result = result base; return result; Function invocation int main() int threeExpFour = raiseToPower(3, 4); cout "34 is " threeExpFour endl; return 0; Returning a value • Up to one value may be returned; it must be the same type as the return type. int foo() char foo() return "hello"; // error return "hello"; // ok Returning a value • Up to one value may be returned; it must be the same type as the return type. • If no values are returned, give the function a void return type void printNumber(int num) cout "number is " num endl; int main() printNumber(4); // number is 4 return 0; Returning a value • Up to one value may be returned; it must be the same type as the return type. • If no values are returned, give the function a void return type – Note that you cannot declare a variable of type void int main() void x; // ERROR return 0; Returning a value • Return statements don’t necessarily need to be at the end. • Function returns as soon as a return statement is executed. void printNumberIfEven(int num) if (num 2 == 1) cout "odd number" endl; return; cout "even number; number is " num endl; int main() int x = 4; printNumberIfEven(x); // even number; number is 3 int y = 5; printNumberIfEven(y); // odd number Argument Type Matters void printOnNewLine(int x) cout x endl; • printOnNewLine(3) works • printOnNewLine("hello") will not compile Argument Type Matters void printOnNewLine(char x) cout x endl; • printOnNewLine(3) will not compile • printOnNewLine("hello") works Argument Type Matters void printOnNewLine(int x) cout x endl; void printOnNewLine(char x) cout x endl; • printOnNewLine(3) works • printOnNewLine("hello") also works Function Overloading void printOnNewLine(int x) cout "Integer: " x endl; void printOnNewLine(char x) cout "String: " x endl; • Many functions with the same name, but different arguments • The function called is the one whose arguments match the invocation Function Overloading void printOnNewLine(int x) cout "Integer: " x endl; void printOnNewLine(char x) cout "String: " x endl; • printOnNewLine(3) prints “Integer: 3” • printOnNewLine(“hello”) prints “String: hello” Function Overloading void printOnNewLine(int x) cout "1 Integer: " x endl; void printOnNewLine(int x, int y) cout "2 Integers: " x " and " y endl; • printOnNewLine(3) prints “1 Integer: 3” • printOnNewLine(2, 3) prints “2 Integers: 2 and 3” • Function declarations need to occur before invocations int foo() return bar()2; // ERROR bar hasn’t been declared yet int bar() return 3; • Function declarations need to occur before invocations – Solution 1: reorder function declarations int bar() return 3; int foo() return bar()2; // ok • Function declarations need to occur before invocations – Solution 1: reorder function declarations – Solution 2: use a function prototype; informs the compiler you’ll implement it later int bar(); function prototype int foo() return bar()2; // ok int bar() return 3; • Function prototypes should match the signature of the method, though argument names don’t matter int square(int); function prototype int cube(int x) return xsquare(x); int square(int x) return xx; • Function prototypes should match the signature of the method, though argument names don’t matter int square(int x); function prototype int cube(int x) return xsquare(x); int square(int x) return xx; • Function prototypes should match the signature of the method, though argument names don’t matter int square(int z); function prototype int cube(int x) return xsquare(x); int square(int x) return xx; • Function prototypes are generally put into separate header files – Separates specification of the function from its implementation // myLib.h header // myLib.cpp implementation // contains prototypes include "myLib.h" int square(int); int cube(int x) int cube (int); return xsquare(x); int square(int x) return xx; Recursion • Functions can call themselves. • fib(n) = fib(n1) + fib(n2) can be easily expressed via a recursive implementation int fibonacci(int n) if (n == 0 n == 1) return 1; else return fibonacci(n2) + fibonacci(n1); Recursion • Functions can call themselves. • fib(n) = fib(n1) + fib(n2) can be easily expressed via a recursive implementation int fibonacci(int n) if (n == 0 n == 1) base case return 1; else return fibonacci(n2) + fibonacci(n1); Recursion • Functions can call themselves. • fib(n) = fib(n1) + fib(n2) can be easily expressed via a recursive implementation int fibonacci(int n) if (n == 0 n == 1) return 1; else recursive step return fibonacci(n2) + fibonacci(n1); Global Variables • How many times is function foo() called Use a global variable to determine this. – Can be accessed from any function int numCalls = 0; Global variable void foo() ++numCalls; int main() foo(); foo(); foo(); cout numCalls endl; // 3 int numCalls = 0; int raiseToPower(int base, int exponent) Scope numCalls = numCalls + 1; int result = 1; for (int i = 0; i exponent; i = i + 1) • Scope: where a result = result base; variable was declared, return result; determines where it can be accessed from int max(int num1, int num2) numCalls = numCalls + 1; int result; if (num1 num2) result = num1; else result = num2; return result; int numCalls = 0; int raiseToPower(int base, int exponent) Scope numCalls = numCalls + 1; int result = 1; for (int i = 0; i exponent; i = i + 1) • Scope: where a result = result base; variable was declared, return result; determines where it can be accessed from • numCalls has global int max(int num1, int num2) numCalls = numCalls + 1; scope – can be int result; accessed from any if (num1 num2) function result = num1; else result = num2; return result; int numCalls = 0; int raiseToPower(int base, int exponent) Scope numCalls = numCalls + 1; int result = 1; for (int i = 0; i exponent; i = i + 1) • Scope: where a result = result base; variable was declared, return result; determines where it can be accessed from • numCalls has global int max(int num1, int num2) numCalls = numCalls + 1; scope – can be int result; accessed from any if (num1 num2) function result = num1; • result has function else scope – each function result = num2; can have its own separate variable return result; named result int numCalls = 0; int raiseToPower(int base, int exponent) numCalls = numCalls + 1; int result = 1; for (int i = 0; i exponent; i = i + 1) result = result base; // A return result; int max(int num1, int num2) Global scope numCalls = numCalls + 1; int result; if (num1 num2) int numCalls result = num1; else result = num2; // B raiseToPower function scope max function scope return result; int int int int int int exponent base result num1 num2 resultint numCalls = 0; int raiseToPower(int base, int exponent) numCalls = numCalls + 1; int result = 1; for (int i = 0; i exponent; i = i + 1) result = result base; // A • At A, variables marked in return result; green are in scope int max(int num1, int num2) Global scope numCalls = numCalls + 1; int result; if (num1 num2) int numCalls result = num1; else result = num2; // B raiseToPower function scope max function scope return result; int int int int int int A exponent base result num1 num2 resultint numCalls = 0; int raiseToPower(int base, int exponent) numCalls = numCalls + 1; int result = 1; for (int i = 0; i exponent; i = i + 1) result = result base; // A • At B, variables marked in return result; blue are in scope int max(int num1, int num2) Global scope numCalls = numCalls + 1; int result; if (num1 num2) int numCalls result = num1; else result = num2; // B raiseToPower function scope max function scope return result; int int int int int int B exponent base result num1 num2 resultdouble squareRoot(double num) double low = 1.0; double high = num; for (int i = 0; i 30; i = i + 1) double estimate = (high + low) / 2; if (estimateestimate num) squareRoot function scope double newHigh = estimate; high = newHigh; double double double else num low high double newLow = estimate; low = newLow; for loop scope return (high + low) / 2; double int i estimate • Loops and if/else statements also have their own scopes If statement scope else statement scope – Loop counters are in the double double same scope as the body of newHigh newLow the for loop double squareRoot(double num) double low = 1.0; double high = num; for (int i = 0; i 30; i = i + 1) double estimate = (high + low) / 2; if (estimateestimate num) squareRoot function scope double newHigh = estimate; high = newHigh; double double double A else num low high double newLow = estimate; low = newLow; for loop scope // A return estimate; // ERROR double int i estimate • Cannot access variables If statement scope else statement scope that are out of scope double double newHigh newLowdouble squareRoot(double num) double low = 1.0; double high = num; for (int i = 0; i 30; i = i + 1) double estimate = (high + low) / 2; if (estimateestimate num) squareRoot function scope double newHigh = estimate; high = newHigh; double double double A else num low high double newLow = estimate; low = newLow; if (i == 29) for loop scope return estimate; // B double return 1; // A int i B estimate • Cannot access variables If statement scope else statement scope that are out of scope • Solution 1: move the double double newHigh newLow code double squareRoot(double num) double low = 1.0; double high = num; double estimate; for (int i = 0; i 30; i = i + 1) estimate = (high + low) / 2; squareRoot function scope if (estimateestimate num) double newHigh = estimate; double double double double A high = newHigh; estimate num low high else double newLow = estimate; low = newLow; for loop scope return estimate; // A int i • Cannot access variables If statement scope else statement scope that are out of scope • Solution 2: declare the double double newHigh newLow variable in a higher scope Pass by value vs by reference • So far we’ve been passing everything by value – makes a copy of the variable; changes to the variable within the function don’t occur outside the function // passbyvalue void increment(int a) a = a + 1; cout "a in increment " a endl; Output int main() int q = 3; increment(q); // does nothing a in increment 4 cout "q in main " q endl; q in main 3 Pass by value vs by reference main function scope q=3 // passbyvalue void increment(int a) a = a + 1; cout "a in increment " a endl; Output int main() int q = 3; // HERE increment(q); // does nothing a in increment 4 cout "q in main " q endl; q in main 3 Pass by value vs by reference main function scope increment function scope q=3 a=3 // passbyvalue void increment(int a) // HERE a = a + 1; cout "a in increment " a endl; Output int main() int q = 3; increment(q); // does nothing a in increment 4 cout "q in main " q endl; q in main 3 Pass by value vs by reference main function scope increment function scope q=3 a=4 // passbyvalue void increment(int a) a = a + 1; // HERE cout "a in increment " a endl; Output int main() int q = 3; increment(q); // does nothing a in increment 4 cout "q in main " q endl; q in main 3 Pass by value vs by reference • If you want to modify the original variable as opposed to making a copy, pass the variable by reference (int a instead of int a) // passbyvalue void increment(int a) a = a + 1; cout "a in increment " a endl; Output int main() int q = 3; increment(q); // works a in increment 4 cout "q in main " q endl; q in main 4 Pass by value vs by reference main function scope q=3 // passbyvalue void increment(int a) a = a + 1; cout "a in increment " a endl; Output int main() int q = 3; // HERE increment(q); // works a in increment 4 cout "q in main " q endl; q in main 4 Pass by value vs by reference main function scope increment function scope q=3 a // passbyvalue void increment(int a) // HERE a = a + 1; cout "a in increment " a endl; Output int main() int q = 3; increment(q); // works a in increment 4 cout "q in main " q endl; q in main 4 Pass by value vs by reference main function scope increment function scope q=4 a // passbyvalue void increment(int a) a = a + 1; // HERE cout "a in increment " a endl; Output int main() int q = 3; increment(q); // works a in increment 4 cout "q in main " q endl; q in main 4 Implementing Swap void swap(int a, int b) int t = a; a = b; b = t; int main() int q = 3; int r = 5; swap(q, r); cout "q " q endl; // q 5 cout "r " r endl; // r 3 Implementing Swap void swap(int a, int b) main function scope int t = a; a = b; b = t; q=3 r=5 int main() int q = 3; int r = 5; // HERE swap(q, r); cout "q " q endl; // q 5 cout "r " r endl; // r 3 Implementing Swap void swap(int a, int b) // HERE main function scope int t = a; a = b; b = t; q=3 r=5 int main() int q = 3; int r = 5; swap function scope swap(q, r); cout "q " q endl; // q 5 cout "r " r endl; // r 3 a bImplementing Swap void swap(int a, int b) main function scope int t = a; // HERE a = b; b = t; q=3 r=5 int main() int q = 3; int r = 5; swap function scope swap(q, r); cout "q " q endl; // q 5 cout "r " r endl; // r 3 a b t=3Implementing Swap void swap(int a, int b) main function scope int t = a; a = b; // HERE b = t; q=5 r=5 int main() int q = 3; int r = 5; swap function scope swap(q, r); cout "q " q endl; // q 5 cout "r " r endl; // r 3 a b t=3Implementing Swap void swap(int a, int b) main function scope int t = a; a = b; b = t; // HERE q=5 r=3 int main() int q = 3; int r = 5; swap function scope swap(q, r); cout "q " q endl; // q 5 cout "r " r endl; // r 3 a b t=3Returning multiple values • The return statement only allows you to return 1 value. Passing output variables by reference overcomes this limitation. int divide(int numerator, int denominator, int remainder) remainder = numerator denominator; return numerator / denominator; int main() int num = 14; int den = 4; int rem; int result = divide(num, den, rem); cout result "" den "+" rem "=" num endl; // 34+2=12 Libraries • Libraries are generally distributed as the header file containing the prototypes, and a binary .dll/.so file containing the (compiled) implementation – Don’t need to share your .cpp code // myLib.h – header // contains prototypes double squareRoot(double num); myLib.dll • Library user only needs to know the function prototypes (in the header file), not the implementation source code (in the .cpp file) – The Linker (part of the compiler) takes care of locating the implementation of functions in the .dll file at compile time // myLib.h – header // contains prototypes myLib.dll double squareRoot(double num); // libraryUser.cpp – some other guy’s code include "myLib.h" double fourthRoot(double num) return squareRoot(squareRoot(num)); Final Notes • You don’t actually need to implement raiseToPower and squareRoot yourself; cmath (part of the standard library) contains functions pow and sqrt include cmath double fourthRoot(double num) return sqrt(sqrt(num)); MIT OpenCourseWare http://ocw.mit.edu 6.096 Introduction to C++ January (IAP) 2011 . For information about citing these materials or our Terms of Use, visit: http://ocw.mit.edu/terms
sharer
Presentations
Free
Document Information
Category:
Presentations
User Name:
Dr.ShaneMatts
User Type:
Teacher
Country:
United States
Uploaded Date:
23-07-2017