640 likes | 664 Views
C++ Review. CS 302 – Data Structures. Review Topics. Calling functions by value or reference Pointers and reference variables Static and dynamic arrays Constructors, destructors and copy-constructors Operator overloading. Functions. Section 2.2. Two ways to call a function:.
E N D
C++ Review CS 302 – Data Structures
Review Topics • Calling functions by value or reference • Pointers and reference variables • Static and dynamic arrays • Constructors, destructors and copy-constructors • Operator overloading
Functions Section 2.2
Two ways to call a function: • Call by “value” • Useful for “protecting” the values of the variables passed to a function. • Call by “reference” • Useful for "returning” multiple values. • Need to define “formal” and “actual” function parameters first …
“FindMax” Example int FindMax(int x, int y) { int maximum; if(x>=y) maximum = x; else maximum = y; return maximum; }
“FindMax” Example (cont.) #include <iostream.h> int FindMax(int, int); // function prototype int main() { int firstnum, secnum, max; cout << "\nEnter two numbers: "; cin >> firstnum >> secnum; max=FindMax( firstnum, secnum); // the function is called here cout << "The maximum is " << max << endl; return 0; }
Formal Parameters • The argument names in the function header are referred to as formal parameters. int FindMax(int x, int y) { int maximum; if(x>=y) maximum = x; else maximum = y; return maximum; } x,yare called “formal parameters”
Actual Parameters • The argument names in the function call are referred to as actual parameters #include <iostream.h> int FindMax(int, int); // function prototype int main() { int firstnum, secnum, max; cout << "\nEnter two numbers: "; cin >> firstnum >> secnum; max=FindMax( firstnum, secnum); // the function is called here cout << "The maximum is " << max << endl; return 0; } firstnum,secnumare called “actual parameters”
Calling a function by “value” • The formal parameters receive a copy of the actual parameter values. • The function cannot change the values of the actual parameters.
Calling a function by value(cont.) #include <iostream.h> void newval(float, float); // function prototype int main() { float firstnum, secnum; cout << "Enter two numbers: "; cin >> firstnum >> secnum; newval(firstnum, secnum); cout << firstnum << secnum << endl; return 0; } void newval(float xnum, float ynum) { xnum = 89.5; ynum = 99.5; }
Calling a function by “reference” • The formal parameters become an alias for the actual parameters. • The function can change the values of the actual parameters. Note: formal parameters must be declared as “reference” variables.
Calling a function by reference(cont.) #include <iostream.h> void newval(float&, float&); // function prototype int main() { float firstnum, secnum; cout << "Enter two numbers: "; cin >> firstnum >> secnum; newval(firstnum, secnum); cout << firstnum << secnum << endl; return 0; } void newval(float& xnum, float& ynum) { xnum = 89.5; ynum = 99.5; } reference variables!
The "const" modifier • Call by reference is the preferredway to pass a large structure or class instances to functions, since the entire structure need not be copied each time it is used! • C++ provides us with protection against accidentally changing the values of variables passed by reference with the const operator int FindMax(const int& x, const int& y);
Reference variables • A reference variable stores the address of another variable. • Reference variables must be initialized during declaration. #include <iostream.h> void main() { int x = 3; int& y = x; cout << "x= " << x << "y = " << y << endl; y = 7; cout << "x= " << x << "y = " << y << endl; }
Reference variables and pointers • A reference variable is a constant pointer (after initializing a reference variable, we cannot change it again). • Reference variables are dereferenced automatically (no need to use the dereferencing operator *).
Reference variables and pointers (cont.) int b; // using reference variables int& a = b; a = 10; int b; // using pointers int *a = &b; *a = 10;
“Call by reference” - revisited #include <iostream.h> void newval(float&, float&); // function prototype int main() { float firstnum, secnum; cout << "Enter two numbers: "; cin >> firstnum >> secnum; newval(firstnum, secnum); cout << firstnum << secnum << endl; return 0; } void newval(float& xnum, float& ynum) { xnum = 89.5; ynum = 99.5; } no dereferencing !
Same example, using pointers … #include <iostream.h> void newval(float *, float *); // function prototype int main() { float firstnum, secnum; cout << "Enter two numbers: "; cin >> firstnum >> secnum; newval(&firstnum, &secnum); cout << firstnum << secnum << endl; return 0; } void newval(float *xnum, float *ynum) { *xnum = 89.5; *ynum = 99.5; } pass address explicitly dereferencing is required !
Static / DynamicArray Allocation Section 2.2
Two ways to allocate memory for an array: • “Static” array allocation • Could waste memory. • Less efficient when passing a statically allocated array to a function. • “Dynamic” array allocation • More memory efficient. • More efficient to pass a dynamically allocated array to a function.
Static Arrays • When a static array is created, the compiler automatically creates an internal pointer constant (i.e., cannot change its contents). • The name of the array becomes the name of the pointer constant. • The pointer stores the starting address (base address) of the array (i.e., address of first byte)
1D Static Arrays (cont.) intarr[6]; assume arr is of type “int” and that “int” takes 2 bytes Need 12 bytes of contiguous memory!
1D Static Arrays (cont.) • Referring to arr[i] causes the compiler, internally, to make the following address computation: &arr[i] = &arr[0] + (i * sizeof(int)) Example: offset to arr[3] = 3 x 2 = 6 bytes base address offset
2D Static Arrays • Static 2D arrays are always stored in memory as 1D arrays in contiguous memory. e.g,
Dynamic Array Allocation • Allocate memory at run time using the new operator: • Reserves the number of bytes requested by the declaration. • Returns the address of the first reserved location or NULL if sufficient memory is not available. arr = newint[N]; must be a pointer
Dynamic Array Allocation (cont.) cout << "Enter array size: "; cin >> N; int *arr; arr = new int[N]; • Individual elements can be processed using index notation: • e.g., arr[1]=10;
Dynamic Array De-allocation • To de-allocate any memory that has been previously allocated using new, we need to use the delete operator. • Releases a block of bytes previously reserved. • Needs the address of the first location only. delete [ ] arr;
Example: 2D arrays Suppose we need to allocate a 2 x 6 array: arr[2][6] 480 482 484 486 488 490
Example: 2D arrays (cont.) cout << "Enter numRows and numCols: "; cin >> numRows >> numCols; int **arr2D; arr2D = new int* [numRows]; // allocation for(i=0; i<numRows; i++) arr2D[i] = new int[numCols]; for(i=0; i<numRows; i++) // deallocation delete [] arr2D[i]; delete [] arr2D; • Individual elements can be processed using index notation: • e.g., arr2D[0][2]=10;
Static Arrays as Function Arguments • To pass the whole array to a function, you need to specify the name of the array. • In the case of 2D arrays, the number of columns must be specified in the function prototype and heading.
Static Arrays:1D Example #include <iostream.h> float find_average(int [], int); void main() { const numElems = 5; int arr[numElems] = {2, 18, 1, 27, 16}; cout << "The average is " << find_average(arr, numElems) << endl; } float find_average(int vals[], int n) { int i; float avg; avg=0.0; for(i=0; i<n; i++) avg += vals[i]; avg = avg/n; return avg; }
Static Arrays:2D Example #include <iostream.h> float find_average(int [][2], int, int); // function prototype void main() { const numRows = 2; const numCols = 2; int arr2D[numRows][numCols] = {2, 18, 1, 27}; cout << "The average is " << find_average(arr2D, numRows, numCols) << endl; }
Static Arrays:2D Example (cont.) float find_average(int vals[][2], int n, int m) { int i,j; float avg; avg=0.0; for(i=0; i<n; i++) for(j=0; j<m; j++) avg += vals[i][j]; avg = avg/(n*m); return avg; }
#include <iostream.h> float find_average(int *, int); // function proptotype void main() { int *arr, numElems;; cin << numElems; arr = new int[numElems]; // then, initialize array … cout << "The average is " << find_average(arr, numElems) << endl; } Dynamic Arrays:1D Example
float find_average(int *vals, int n) { int i; float avg; avg=0.0; for(i=0; i<n; i++) avg += vals[i]; avg = avg/n; return avg; } Dynamic Arrays:1D Example (cont.)
#include <iostream.h> float find_average(int **, int, int); // function prototype void main() { int **arr2D; arr2D = new int*[numRows]; for(i=0; i<numRows; i++) arr2D[i] = new int[numCols]; // then, initialize array … cout << "The average is " << find_average(arr2D, numRows, numCols) << endl; } Dynamic Arrays:2D Example
float find_average(int **vals, int n, int m) { int i, j; float avg; avg=0.0; for(i=0; i<n; i++) for(j=0; j<m; j++) avg += vals[i][j]; avg = avg/(n*m); return avg; } Dynamic Arrays:2D Example (cont.)
Constructors, Destructorsand Copy-Constructors Section 2.3, p. 140, pp. 360-367
What is a constructor? • A member function which initializes a class. • A constructor has: (i) the same name as the class itself (ii) with or without arguments, no return type
Comments on constructors • A constructor is called automatically whenever a new instance of a class is created. • If you do not specify a constructor, the compiler generates a default constructor for you (expects no parameters and has an empty body).
class rectangle { private: float height; float width; int xpos; int ypos; public: rectangle(float, float); // constructor void draw(); // draw member function void posn(int, int); // position member function void move(int, int); // move member function }; rectangle::rectangle(float h, float w) { height = h; width = w; xpos = 0; ypos = 0; }
void main() { rectangle rc(3.0, 2.0); rc.posn(100, 100); rc.draw(); rc.move(50, 50); rc.draw(); } • Warning: attempting to initialize a data member of a class explicitly in the class definition is a syntax error.
Object Composition class rectangle { private: float height; float width; int xpos; int ypos; properties pr; // another object public: rectangle(float, float, int, int ); // constructor void draw(); // draw member function void posn(int, int); // position member function void move(int, int); // move member function }; A class may have objects of other classes as members.
Object Composition (cont.) class properties { private: int color; int line; public: properties(int, int); // constructor }; properties::properties(int c, int l) { color = c; line = l; }
Object Composition (cont.) rectangle::rectangle(float h, float w, int c, int l):pr(c, l) { height = h; width = w; xpos = 0; ypos = 0; }; void main() { rectangle rc(3.0, 2.0, 1, 3); ……… }
What is a destructor? • A member function which deletes an object. • A destructor has: (i) the same name as the class but is preceded by a tilde (~) (ii) no arguments and returns no values
Comments on destructors • A destructor is called automatically whenever an object goes out of scope or when the program terminates. • If you do not specify a destructor, the compiler generates a default destructor for you. • When a class contains a pointer to memory you allocate, it is your responsibility to release the memory before the class instance is destroyed.
class string { private: char *s; int size; public: string(char *); // constructor ~string(); // destructor }; string::string(char *c) // constructor { size = strlen(c); s = new char[size+1]; strcpy(s,c); } string::~string() // destructor { delete []s; }
What is a copy constructor? • It is a member function which initializes an object using another object of the same class. • A copy constructor has the following general function prototype: class_name (const class_name&);