140 likes | 156 Views
Review: What = and & Mean. In C++ the = symbol means either initialization or assignment If it ’ s used with a type declaration , it means initialization If it ’ s used without a type declaration, it means assignment int j(7); // j is initialized with value 7
E N D
Review: What = and & Mean • In C++ the = symbol means either initialization or assignment • If it’s used with a type declaration, it means initialization • If it’s used without a type declaration, it means assignment int j(7); // j is initialized with value 7 int k = 4; // k is initialized with value 4 j = 3; // j is assigned value 3 • In C++ the & symbol also has a similar “dual nature” • If it’s used inside a type declaration, it means a reference (an alias) • Arguments to function are always declared along with their types • If it’s used outside a type declaration, it means “address of” int swap (int & i, int & j); // references to int int & s = j; // reference s initialized to refer to j int * p = & j; // pointer p initialized w/ j’s address
Review: Parameter/Variable Declarations • Hint: read parameter and variable declarations right to left int i;“i is an integer” int & r = i;“r is a reference to an integer (initialized with i)” int * p;“p is a pointer to an integer” int * & q = p;“q is a reference to a pointer to an integer (initialized with p)” • Read function declarations inside out “function main takes an integer and an array of pointers to char, and returns an integer” int main (int argc, char * argv[]); “function usage takes a pointer to char, and returns void (nothing)” void usage (char * program_name); “function setstring takes a reference to a (C++) string, and returns void” void setstring (string & s);
How Function Calls Work • A function call uses the “program call stack” • Stack frame is “pushed” when the call is made • Execution jumps to the function’s code block • Function’s code block is executed • Execution returns to just after where call was made • Stack frame is “popped” (variables in it destroyed) • This incurs a (small) performance cost • Copying arguments, other info into the stack frame • Stack frame management • Copying function result back out of the stack frame
Review: Pass By Value void foo () { int i = 7; baz (i); } void baz (int j) { j = 3; } 7 local variable i (stays 7) Think of this as declaration with initialization, along the lines of: int j = what baz was passed; parameter variable j (initialized with the value passed to baz, and then is assigned the value 3) 7 → 3
Review: Pass By Reference void foo () { int i = 7; baz (i); } void baz (int & j) { j = 3; } again declaration with initialization int & j = what baz was passed; 7 → 3 local variable i j is initialized to refer to the variable that was passed to baz: when j is assigned 3, the passed variable is assigned 3. 7 → 3 argument variable j
What About Pointers as By-Value Arguments? void foo () { int i = 7; baz (&i); } void baz (int * j) { *j = 3; } j is initialized with the address (value) that was passed to baz local variable i 7 → 3 address-of operator dereferencing j gives the location to which it points, so the variable whose address was passed is assigned 3. 0x74bead00 argument variable j dereference operator
What About Passing Pointers By-Reference? void foo () { int i = 7; int j = 4; int *p = &i; baz (p, j); } void baz (int * & q, int & k) { q = &k; } local variable i local variable j 7 4 0x74bead04 0x74bead00 &i → &k argument variable q argument variable k q references p and k references j: when q is assigned the address of k, the effect is to make p point to j instead of i
Pass By const Reference void foo () { int i = 7; baz (i); } void baz (const int & j) { cout << j << endl; } again declaration with initialization Const int & j = what baz was passed; and it is read only. local variable i 7 j is initialized to refer to the variable that was passed to baz: j can not be changed. 7 argument variable j
Default Arguments • Some functions can take several arguments • Can increase function flexibility • Can reduce proliferation of near-identical functions • But, callers must supply all of these arguments • Even for ones that aren’t “important” • We can provide defaults for some arguments • Caller doesn’t have to fill these in
Required vs. Default Arguments • Function with required argument // call as foo(2); (prints 2) void foo(int a); void foo(int a) {cout << a << endl;} • Function with default argument • Notice only the declaration gives the default value // can call as foo(2); (prints 2) // or can call as foo(); (prints 3) void foo(int a = 3); void foo(int a) {cout << a << endl;}
Defaults with Multiple Arguments • Function with one of two arguments defaulted // can call as foo(2); (prints 2 3) // or can call as foo(2, 4); (prints 2 4) void foo(int a, int b = 3); void foo(int a, int b) {cout << a << “” << b << endl;} • Same function, with both arguments defaulted // can call as foo(); (prints 1 3) // or can call as foo(2); (prints 2 3) // or can call as foo(2, 4); (prints 2 4) void foo(int a = 1, int b = 3); void foo(int a, int b) {cout << a << “” << b << endl;}
Default Argument Limitations • Watch out for ambiguous signatures • foo(); and foo(int a = 2); for example • Can only default the rightmost arguments • Can’t declare void foo(int a = 1, int b); • Caller must supply leftmost arguments • Even if they’re the same as the defaults
VaryingParameters initializer_list<T> parameters; void foo(initializer_list<string> coffee){ for (auto beg = coffee.begin(); beg != coffee.end(); ++beg) { cout << *beg << “”; } cout << endl; } //print out all 4 coffees foo(“latte”, “mocha”, “eggnog latte”, “peppermint mocha”); //print out only 2 coffees foo(“latte”, “mocha”);
Function Overload // can call errMsg with 1 or 2 integers or a string void errMsg(int & errCode) {cout << “Error code is: ” << errCode<< endl;} void errMsg(const int & errCode) {cout << “Error code is: ” << errCode<< endl;} void errMsg(int & errCode, string msg) {cout << “Error --” << msg << “Error code: ” errCode << endl;} Void errMsg(string msg) {cout << “Error --” << msg << endl;} int err5 = 5; err1 = 1; const int outOfRange = 3; errMsg (err5); errMsg (err1, “can’t open file”); errMsg (“dividing by 0”); errMsg (outOfRange);