200 likes | 302 Views
EECS498-006 Lecture 23. Savicth: N/A Misc. Topics. Something New (Sort Of). Consider the following line of code from a program I wrote: Any ideas as to what this odd syntax does? Consider, instead this line of code: Now, we see that the above line is a function call
E N D
EECS498-006 Lecture 23 Savicth: N/A Misc. Topics
Something New (Sort Of) • Consider the following line of code from a program I wrote: • Any ideas as to what this odd syntax does? • Consider, instead this line of code: • Now, we see that the above line is a function call • retval is the return value of the function call • addEmUp is the name of the function we are calling • mainary is the the first parameter to the function • arySize is the second parameter to the functions • Notice the second example is the same as the first, with "opList[whichOp]" replaced with "addEmUp" retVal = opList[whichOp] (mainary, arySize); retVal = addEmUp(mainary, arySize); Andrew M Morgan
Intro To Function Pointers • In C++ function names in your program actually represent the address where the executable code for that function starts • This means that we can set a pointer variable to the address of a function, and call it via the pointer • These are called "function pointers" • There are many potential uses for function pointers: • Function pointers can be placed in an indexed array, thus allowing you to call a specific function depending on value used as index • Function pointers can be passed as parameters to functions, allowing one function to call different functions in different circumstances • Function pointer can be updated in a loop to perform several operations (function calls) on the same data, with only one LOC Andrew M Morgan
Use Of Function Pointers • Any variable in C++ must be declared. • Function pointer variables are no exception • What type is a function pointer? • Type must describe the return value and params of the function • Now, variables we declare to be of type "operFn" are function pointers, with the described signature typedef int (*operFn) (int[], int); | ^ ^ \__________/ | | | | | | | This is the param list for the func ptr | | This is the name of the type we are creating | return type of function being pointed to Says that we are defining a new type (for our function ptr) Andrew M Morgan
Use Of Function Pointers, Cot'd • Let's assume we have the following functions defined: • All of the above functions have the same parameter types and return type • We can define a type for pointers to such functions • Now, declare a function pointer variable: • The variable "fptr" can be assigned to the above functions int addEmUp (const int ary[], int size); int multEmUp (const int ary[], int size); int findMin (const int ary[], int size); int findMax (const int ary[], int size); typedef int (*operFn) (int[], int); operFn fptr; fptr = addEmUp; // or fptr = multEmUp; etc... Andrew M Morgan
Interesting (and useful) C++ Stuff • There are many elements of the C++ language not discussed • This lecture is just a collection of C++ information • These items are NOT necessarily related in any way • More importantly, you should not assume that everything covered should be used often • Remember, just because you are a good programmer, using good style, does not mean everyone else is • You should know many features even if you don't plan on using them all, in case you come across them in code • Every feature has a place where it is a good feature, and most have a place where it is a bad feature Andrew M Morgan
The Ternary Operator • There is an operator in C++ called the ternary operator • It is somewhat widely used in certain circumstances • Can make your code more compact • Avoid using it too much, though, as it could get hard to trace • The ternary operator can replace the "if-then-else" structure in some situations • The operator is "?:" • Place an expression before the question mark • Place a value to be used is the expression is true between the question mark and colon • Place a value to be used otherwise after the colon • Often used when assigning different values depending on a condition Andrew M Morgan
The Ternary Operator, Example int main(void) { int i = 7, j = 10, k = 4, s = 0; //Assign s to i if i is less than j. //Otherwise, assign s to j; //Method 1 if (i < j) s = i; else s = j; cout << "First - s: " << s << endl; //Method 2 s = (i < j)?i:j; cout << "Second - s: " << s << endl; cout << "Max(" << i << "," << j << ") = " << ((i > j)?i:j) << endl; cout << "Max(" << i << "," << k << ") = " << ((i > k)?i:k) << endl; return (0); } First - s: 7 Second - s: 7 Max(7,10) = 10 Max(7,4) = 7 Andrew M Morgan
The Comma Operator • The comma is another operator allowed in C++ • A comma expression is a series of expressions separated by commas • Since a comma expression is, in fact, an expression, it has a value - the value of the rightmost expression • Each expression in a comma expression is evaluated in order from left to right • Use of the comma can lead to major headaches in trying to interpret a program in some cases • Use of the comma in a for loop is quite common though Andrew M Morgan
The Comma Operator, Example int i, j, k = 0, l = 0, m = 0; for (i = 0, j = 5; i < 5; i++, j--) cout << "i: " << i << " j: " << j << endl; if (k == 3) //FALSE m = k = 1; l = 2; cout << "k: " << k << " l: " << l << " m: " << m << endl; if (k == 0) //TRUE m = k = 3; l = 4; cout << "k: " << k << " l: " << l << " m: " << m << endl; if (k == 17) //FALSE m = (k = 5, l = 6); cout << "k: " << k << " l: " << l << " m: " << m << endl; if (k == 3) //TRUE m = (k = 7, l = 8); cout << "k: " << k << " l: " << l << " m: " << m << endl; i: 0 j: 5 i: 1 j: 4 i: 2 j: 3 i: 3 j: 2 i: 4 j: 1 k: 0 l: 2 m: 0 k: 3 l: 4 m: 3 k: 3 l: 4 m: 3 k: 7 l: 8 m: 8 Andrew M Morgan
Function Objects • You've used the ( ) operator many times when you make a function call • Normally, it would be a bad idea to overload this operator • However, there are cases where it might make sense to overload the function call operator • When a class overloads ( ), an object of that class is called a "function object" • I stress again - this is usually a bad idea • Still, it is pretty interesting • When using an overloaded ( ) operator, it appears you are calling a function • Since the function call is actually a method of the class, it acts different, depending on the values of data members of the object Andrew M Morgan
Function Object, Example class compareClass { public: int cmpWith; char cmpOp; bool operator() (int check) { bool res; if (cmpOp == '<') res = (cmpWith < check); else if (cmpOp == '>') res = (cmpWith > check); return res; } }; int main(void) { bool a; compareClass compare; compare.cmpWith = 9; compare.cmpOp = '>'; a = compare(5); cout << "1: " << (a?"true":"false") << endl; a = compare(12); cout << "2: " << (a?"true":"false") << endl; compare.cmpOp = '<'; a = compare(5); cout << "3: " << (a?"true":"false") << endl; a = compare(12); cout << "4: " << (a?"true":"false") << endl; return (0); } 1: true 2: false 3: false 4: true Andrew M Morgan
Labels • Labels are exactly that - a way to identify (label) an area of your code • If unreferenced, they are ignored during execution • A label is just an identifier with a colon after it - see below int main(void) { cout << "Welcome to a label program" << endl; label1: cout << "Labels can appear in programs" << endl; blah: cout << "They do not interfere with" << endl; cout << "the flow or execution!" << endl; blip: cout << "The End!" << endl; exit(0); blop: cout << "See ya" << endl; return (0); } Welcome to a label program Labels can appear in programs They do not interfere with the flow or execution! The End! Andrew M Morgan
Goto (gasp!) • Labels by themselves are pretty boring, as they serve no purpose • C++ does provide a goto statement although it is rarely used and always results in a nasty sneer by most programmers • Still, there are situations, where you might see a goto in someone else's code (of course, you would never use one) • "goto" is a C++ keyword • The keyword is followed by a label, making a "goto statement" • When a goto statement is reached, the flow of your program immediately jumps to the next statement after the label • Using goto results in jumpy code that is difficult to trace and follow. Avoid the use of goto!! Andrew M Morgan
Goto (gasp!), Example (double gasp!) int main(void) { int fact = 1; int value = 5; goto mult; printRes: cout << "result is: " << fact << endl; goto alldone; mult: fact *= value; value--; goto whatnext; cout << "Current Val: " << fact << endl; alldone: cout << "Hope you had fun! Bye" << endl; return (0); whatnext: if (value >= 1) goto mult; else goto printRes; return (5); } result is: 120 Hope you had fun! Bye (Yes, it actually works, but it is far from clear. This is a horrible use of goto - many uses are not so blatant and difficult) Andrew M Morgan
Bitwise Operators • You all know that a byte is a collection of 8 bits • Bits are just values that are either 0 or 1 • Since an integer is a 4 byte value (usually) it contains 32 bits • Each of those 32 bits can store a 0/1 value • C++ provides bitwise operators, often used for storing flags, or attributes, of an object • ~: Bitwise not - negates each bit in an expression • &: Bitwise and - "multiplies" each bit in one expression with the corresponding bit in another expression • |: Bitwise or - "adds" each bit in one with corresponding bit in other • >>: Bitwise shift right - Shifts each bit to the right • <<: Bitwise shift left - Shifts each bit to the left Andrew M Morgan
Bitwise Operators, Example const unsigned int ATR1 = 0x0001; //2^0 => 0001 const unsigned int ATR2 = 0x0002; //2^1 => 0010 const unsigned int ATR3 = 0x0004; //2^2 => 0100 const unsigned int ATR4 = 0x0008; //2^3 => 1000 printEnv(int env) { //here, the & is used as a MASK cout << "ATR1: " << ((env & ATR1)?"on":"off") << endl; cout << "ATR2: " << ((env & ATR2)?"on":"off") << endl; cout << "ATR3: " << ((env & ATR3)?"on":"off") << endl; cout << "ATR4: " << ((env & ATR4)?"on":"off") << endl; } int main(void) { int e = 0; //Initially empty environment e = e | ATR1; //Set attribute 1 e = e | ATR3; //Set attribute 3 printEnv(e); e = ~e; //Invert all attributes printEnv(e); e = e & ~ATR2; //Clear attribute 2 printEnv(e); return (0); } ATR1: on ATR2: off ATR3: on ATR4: off ATR1: off ATR2: on ATR3: off ATR4: on ATR1: off ATR2: off ATR3: off ATR4: on Andrew M Morgan
More Interesting Stuff • Did you ever wonder why you could check for a file being in fail state with just the name of the object? • What is the "value" of an object (i.e. myfile, or an object of a user-defined class)? int main() { ifstream myfile("in.txt"); int i; int j; myfile >> i >> j; if (!myfile) { cout << "myfile is in fail state!" << endl; } return (0); } Andrew M Morgan
Conversion Operator • An object doesn't not result in any value unless you, the programmer, tell it what to evaluate to • You can do so via the special member functions called "conversion operators" • Conversion operators have NO return type • The name of the function is "operator <type>() • To have your object evaluate to a boolean value, implement the following member function: • operator bool(); //No return type! • Even though there is no return type, this function should return a value of type bool • Other conversion operators must return the appropriate type • The fstream class has a boolean conversion operator. • When the file is in fail state, the conversion operator returns false, otherwise it returns true Andrew M Morgan
Conversion Operator, Cot'd int main() { IntClass ic1(13); IntClass ic2(0); int x; x = 4 + ic1; cout << "x: " << x << endl; cout << "IC1 WAS " << (ic1?"TRUE":"FALSE") << endl; cout << "IC2 WAS " << (ic2?"TRUE":"FALSE") << endl; return (0); } class IntClass { public: IntClass(int inVal):val(inVal) { ; } operator int() { return (val); }; operator bool() { return (val == 0?false:true); }; private: int val; }; x: 17 IC1 WAS TRUE IC2 WAS FALSE Andrew M Morgan