250 likes | 375 Vues
This discussion explores critical topics in C++ programming, focusing on parameter passing methods—by value, pointer, and reference. We delve into function overloading and operator overloading, demonstrating how to redefine operators for custom classes. The importance of constructors, destructors, and the Big Three principles (copy constructor, copy assignment operator, and destructor) is emphasized. Through practical code examples, we illustrate correct and incorrect usages of parameter passing and the implications of each method on memory management and program integrity.
E N D
CS 225Data Structures & Software Principles Section 2 More C++
Discussion Topics • Parameter passing & returning • Value, Pointer, Reference • Overloading • Functions, Operators • Constructors • Assignment Operator • Destructor • Big three “law”
Parameter passing:by value #include <iostream> void swap (int a, int b) { int temp = a; a = b; b = temp; } void main() { int x = 1, y = 2; swap(x, y); std::cout << x << " " << y << std::endl; } Semantically INCORRECT
Parameter passing:by pointer #include <iostream> void swap (int* ap, int* bp) { int temp = *ap; *ap = *bp; *bp = temp; } void main() { int x = 1, y = 2; swap(&x, &y); std::cout << x << " " << y << std::endl; } Semantically CORRECT
Parameter passing:by reference #include <iostream> void swap (int& renamed_x, int& renamed_y) { int temp = renamed_x; renamed_x = renamed_y; renamed_y = temp; } void main() { int x = 1, y = 2; swap(x, y); std::cout << x << " " << y << std::endl; } Semantically CORRECT
References • An alternative name for an object • Must be initialized at declaration int i = 1; int& ref = i; // NOT the address-of operator • Can’t reassign reference later on • Not an object in the traditional sense • No operator operates on a reference (instead operates on what it refers to) • Can’t have a pointer to a reference • Can’t create an array of references
Return by value #include <iostream> int glob; int f() { return glob; } void main() { glob = 5; std::cout << f() << std::endl; } • f() returns the value of glob
Return by pointer #include <iostream> int glob; int* f() { return &glob; } void main() { glob = 5; std::cout << *(f()) << std::endl; } • f() returns the address of glob
Return by pointer #include <iostream> int* f() { int loc = 5; return &loc; } void main() { std::cout << *(f()) << std::endl; } • BAD! Dangling pointer
Return by reference #include <iostream> int glob; int& f() { return glob; } void main() { glob = 5; f() = 10; std::cout << f() << std::endl; } • Function call to f becomes the new name for the memory location of glob
Function Overloading • Different functions of the same name • Differentiation is based on signature • Number of parameters • Type of parameters • const keyword • Just changing the return type is NOT enough!
Function Overloading Example // complex.h class complex { private: double real; double comp; public: complex(double x, double y); complex add(complex b); complex add(double d); void print(); };
Operator Overloading • Exploit intuitive meaning of operators like + and – • Customize the meaning of an operator for your particular class • Only overload these if it makes obvious sense! • typeoperatorsign(parameters); • List of all overloadable operators • + - * / = < > += -= *= /= << >> <<= >>= == != <= >= ++ -- % & ^ ! |~ &= ^= |= && || %= [] () new delete
Operator Overloading Example // complex.h class complex { private: float real; float comp; public: complex (float x, float y); complex operator+(complex b); complex operator+(double d); void print(); };
Operator Overloading Example // complex.cpp #include "complex.h" complex::complex(float x, float y) { real = x; comp = y; } complex complex::operator+(complex b) { complex result(0,0); result.real = real + b.real; result.comp = comp + b.comp; return result; } complex complex::operator+(double d) { return complex(real + d, comp); } // …
Operator Overloading Example // main.cpp #include "complex.h" void main() { complex *c1 = new complex(1,2); complex *c2 = new complex(7,3); complex c3 = *c1 + *c2; // prev line is same as: // c3 = (*c1).operator+(*c2); c3.print(); } // output will be 8 + 5i
Jason’s String Class • Things to note: • 2 different string header files in string.cpp • Where const & references are used • Overloaded operators • Two operator[]’s • String comparison operators • Member data • Change history comments
Operator Overloading:friend Function Example • String class overloads the << operator so we can use Strings with cout: String s; cout << s; // re: cout is an ostream obj • To make String data accessible to an ostream object, we declare this function a friend • Declared in the class in which it is a friend • operator<< is not a member function of String class • Not scoped to class in implementation • Example: from string.h friend ostream& operator<<(ostream& Out, String const & ouputString);
Constructor • Called when • instantiating an object locally • Allocating an array of objects • new is used (dynamic) • Default constructor provided by compiler • Unless we implement any constructor class Animal { private: char *name; public: Animal(); Animal(char *name); };
Copy Constructor • Called when • you pass an object by value • you explicitly create a new object by passing in an old object to the constructor • Default provided by compiler • memberwise copy • Declaration example: from Jason’s string.h String(String const & origVal);
Assignment Operator • a = b = c; • Default provided by compiler • memberwise copy • Implementation differs from copy constructor • Must catch assigning an object to itself • Clean up any existing dynamic memory in use • Declaration example: from string.h String const & operator=( String const & origVal); • Usage example: String s1("foo"), s2("bar"); s1 = s2; // same as… s1.operator=(s2); // …this one
Destructor • Called when • Local object leaves scope • delete is used • Object is member of an object being destroyed • Used to cleanup (e.g. free dynamic memory, close file handles) • Default provided by compiler that destroys member variables class Example { Example(); //constructor ~Example(); //destructor }
Law of the Big Three • Assignment Operator, Copy Constructor and Destructor are inseparable • Generally, if you write one, you have to write the other two. • Clue: if you use anew in a constructor delete in destructor copy properly in copy constructor copy properly in operator= • Side effect: no compiler-supplied default constructor if we implement copy constructor
Big Three in the String Class • Things to note: • Class has a pointer as a member • Use of new in constructors • delete in destructor • Compare implementations of operator= and copy constructor
Jason’s IntArray class • Things to notice / remember: • An “array wrapper” just like String • Member data • Indices can now be any set of consecutive integers • Probably should use member functions lower() and upper() when iterating • Check out the Big Three • Dual operator[] usage