CS120 - Day 14: C++ I/O & Operator Overloading ---------------- IO BASICS ------------------------------------------------ file class hierarchy: ios istream ostream ifstream iostream ofstream fstream #include #include #include - open modes for text files same as in C: app, in, out ifstream ifile("files.cpp", ios::in); ofstream ofile("out.txt", ios::app); char ch; int num; do { ifile.get(ch); ifile >> num; ofile << ch << " " << num; } while (!ifile.eof()); ifile.close(); ofile.close(); - random access (block I/O) files are treated same as in C - member functions, manipulators & operators for iostreams can be used with iofstreams for sequential files also, not random access files Output formatting - several different styles ---------------------- - in-line manipulators - #include - setw(#) - cout << setw(8) << 100/29; // right just in 8 char field - cout << setw(6) << "jo" ; // right just in 6 field width - setw returns to default (not persistent) - default is 0 - makes field as small as possible - setfill(char) - cout << setfill('*') << setw(5) << "jo" ; // ***jo - persistent, so remains until reset or changed - cout << setfill(' ') ; // sets back to space cout << setprecision(3) << 100/29; // <=3 digits after decimal cout << fixed; // forces fixed precision # of digits cout << showpoint; // force decimal when precision=0 - I/O member functions for flag setting - flags determine how output is displayed - non-parameterized flag setting (persistent changes) cout.setf(ios::fixed); cout.setf(ios::showpoint); cout.precision(3); // 3 digits after decimal point cout << 12.3 << endl; cout.unsetf(ios::fixed); - to save fill flag before changing and restore: char oldfill = cout.fill('*'); cout << setw(4) << "jo" ; // **jo cout.fill(oldfill); cout << setw(4) << "jo" ; // jo - do same with precision OPERATOR OVERLOADING -------- BagOp, Rational ------------------- - can define any typical operator to have meaning for your class - sometimes need to define as friend functions - often need to return *this - function name is operatorS where S is the operator symbol(s) - be consistent with usual meanings of operators Assignment = does member copy unless overloaded (does not call copy constructor) - Bag example: const Bag & Bag::operator= (const Bag & right) // no const here - const return prevents (s1=s2)=s3 - non-const function allows (s1 = s2 = s3) - no implicit overloading of +=, etc. - must be done explicitly - when overloading () [] -> or any assignment, it must be member - use reference returns to create lvalues - eg: int & Bag :: operator[] (int subscript) - allows: Bag[1] = 23; - overload again for constant Bags const int & Bag :: operator [] (int subscript) const - implicit/explicit type conversions with classes - conversion constructors (single param) - convert into class type - conversion (cast) operator - convert from class type - cannot be friend, must be non-static member - do not specify return type - it is type of conversion - if defined, can be called implicitly Rational :: operator double() const; // Rational to real number Fraction :: operator Rational() const; // Fraction to Rational - string operators operators: == != < > <= >= because of operator overloading in C++ does Unicode comparisons!! int f = s1.compare(s2); (- if s1s2) overloaded substring versions of compare MISC CLASS DETAILS --------------------------------------------- - explicit constructor calls to create constant temporary object - use Classname(params) - eg: Rational r2 = 3 + Rational(3,4); - more on storage, lifetimes, scope and references - if function returns non-reference value, it is a temporary object - if function returns reference value, it is a name for something else - something else must have a lifetime outside the function - global objects - static objects - class members w/suitable lifetime - reference arguments to function - NOT a local automatic function variable - NOT a formal value argument - example: #include int globalint; int & mult(int & x, int y) { int z; static int s; z = x * y; s = z; x = z; y = z; globalint = z; // return z; not allowed // return y; not allowed // return x * y; not allowed // return x; ok // return s; ok return globalint; ok } main () { int m, x = 3, y = 5; m = mult(x, y); globalint = 0; cout << "m=" << m << " gi=" << globalint << endl; } - could have function return something by reference but constant so that it can't be changed - particularly useful for classes: class Point { public: void display() const; void setX(int); ... }; class Rectangle { public: const Point & getTL() { return topleft; }; private: Point topleft; }; // in main Rectangle r1(1,1,4,4); Point p1; r1.getTL().setX(3); // not allowed p1 = r1.getTL(); // ok r1.getTl().display(); // ok because display is const