120 likes | 226 Views
1 // Rational class interface: support operations for rationals 2 // 3 // CONSTRUCTION: with (a) no initializer, or (b) an integer 4 // that specifies the numerator, or (c) two integers 5 // specifying numerator and denominator, or 6 // (d) another Rational 7 //
E N D
1 // Rational class interface: support operations for rationals 2 // 3 // CONSTRUCTION: with (a) no initializer, or (b) an integer 4 // that specifies the numerator, or (c) two integers 5 // specifying numerator and denominator, or 6 // (d) another Rational 7 // 8 // ************************ OPERATIONS********************** 9 // =, +=, -=, /=, *= --> Usual assignment 10 // +, -, /, * --> Usual binary arithmetic11 // <, <=, >, >=, ==,!= --> Usual relational and equality 12 // ++, --, +, -, ! --> Usual prefix, postfix, unary 13 // >> and << --> Input and output 14 // double LongDecimal( ) --> Return double equivalent 15 16 #include <iostream.h> 17 typedef IntType long; 18 19 class Rational 2O { 21 public: 22 // constructors 23 Rational( const IntType & Numerator = 0) : 24 Numer(Numerator), Denom(1) { } 25 Rational( const IntType & Numerator, 26 const IntType & Denominator ) : 27 Numer(Numerator), Denom(Denominator) 28 { FixSigns( ); Reducs( ); } 29 Rational( const Rational & Rhs) : 3O Numer(Rhs.Numer), Denom(Rhs.Denom) { } 31 32 // Destructor33 ~Rational( ) { } Always use constant reference to pass parameter. Without constant, in the function, we may change the parameter by mistake.
3435 // Assignment Ops 36 const Rational & operator = ( const Rational & Rhs ); 37 const Rational & operator +=( const Rational & Rhs ); 38 const Rational & operator -=( const Rational & Rhs ); 39 const Rational & operator /=( const Rational & Rhs ); 40 const Rational & operator *=( const Rational & Rhs ); 41 42 // Mathematical Binary Ops 43 Rational operator+( const Rational & Rhs ) const; 44 Rational operator-( const Rational & Rhs ) const; 45 Rational operator/( const Rational & Rhs ) const; 46 Rational operator*( const Rational & Rhs ) const; 47 // Relational & Equality Ops 48 int operator< ( const Rational & Rhs ) const; 49 int operator<=( const Rational & Rhs ) const; 50 int operator> ( const Rational & Rhs ) const; 51 int operator>=( const Rational & Rhs ) const; 52 int operator==( const Rational & Rhs ) const; 53 int operator!=( const Rational & Rhs ) const; 54 55 // Unary Operators 56 const Rational & operator++( ); // Prefix57 Rational operator++( int ); // Postfix58 const Rational & operator--( ); // Prefix59 Rational operator --( int ); // Postfix60 const Rational & operator+( ) const;61 Rational operator-( ) const;62 int operator!( ) const; 63 64 // Member function 65 double LongDecimal( ) const // Do the division 66 { return double(Numer) / double (Denom) ; } 67 ie: b=a, b is left hand parameter, which is implied but need to be changed. So you can not add the const key word at the end of the declaration. c=b =a, is the same as c=(b=a). b=a return a constant reference value, which is the reference of b,and act as the right hand parameter of the first =, so and the beginning of the declaration you should add const key word. For example: a=b+c, has three parameter b is implied, c, which is at right hand of +, is Rhs. const means b is a constant parameter, both b and c should not be changed in the function. Ie: j=++ i means i=i+1=> j=i Ie: j=i++ means j=i => i=i+1
68 // I/O friends: privacy is waived 69 friend ostream & operator<< ( ostream & Out, const Rational & Value ); 71 friend istream & operator>> ( istream & In, Rational & Value ); 73 private: 74 // A rational number is represented by a numerator and 75 // denominator in reduced form 76 IntType Numer; // The numerator77 IntType Denom; // The denominator 78 79 void FixSigns( ); // Ensures Denom >= 0 80 void Reduce( ); // Ensures lowest form 81 } ; 1 void Rational:: FixSigns ( ) { 2 if( Denom < 0 ) {4 Denom = -Denom;5 Numer = -Numer; 6 } 7 } 8 9 void Rational::Reduce ( ) { 10 IntType D = 1;1112 if (Denom != 0 && Numer != 0) D = GCD(Numer, Denom)1415 if( D > 1 ){17 Numer /= D;18 Denom /= D;19 }20 }
1 Rational // Return a copy of Answer temporary • 2 Rational::operator+( const Rational & Rhs ) const { • 4 Rational Answer( *this ); // Initialize Answer with *this • 5 Answer += Rhs; // Add the second operand, Answer=Answer+Rhs6 return Answer; // Return Answer by copy7 } • 1 int • 2 Rational::operator==( const Rational & Rhs ) const { • 4 return Numer * Rhs.Denom == Denom * Rhs.Numer; • 5 } • 1 const Rational & // Prefix form • 2 Rational::operator++( ){ • 4 Numer += Denom; • 5 return *this; • 6 } • 7 • 8 Rational // Postfix form • 9 Rational::operator++(int) { • 11 Rational Tmp = *this;12 Numer += Denom;13 return Tmp;14 } Dummy only used to indicate postfix form
1 const Rational & 2 Rational::operator=( const Rational & Rhs ) { 4 if( this != &Rhs ) {6 Numer = Rhs.Numer;7 Denom = Rhs.Denom;8 }9 return *this; 10 } 11 12 const Rational & 13 Rational::operator += (const Rational & Rhs) { 15 Numer = Numer * Rhs.Denom + Rhs.Numer * Denom;16 Denom = Denom * Rhs.Denom;17 Reduce ( );1819 return *this;2O }
1 int 2 Rational::operator! ( ) const { 4 return !Numer; 5 } 6 7 const Rational & 8 Rational::operator+( ) const { 10 return *this; 11 }12 13 Rational 14 Rational::operator-( ) const { 16 return Rational( -Numer, Denom );17 } 1 istream & 2 operator>>( istream & In, Rational & Value ) {4 In >> Value.Numer;56 char Ch;7 In >> Ch; 8 if( Ch == '/’ ) { 10 In >> Value.Denom;11 Value.FixSigns ( );12 Value.Reduce ( );13 }14 else {16 Value.Denom = 1;17 In.putback(Ch ); 18 } 19 return In;20 } Return the Lhs, for example Cin>>x1>>x2 Cin>>x1 returns the reference of Cin, the second step is Cin>>x2
23 ostream & • 24 operator<<( ostream & Out, const Rational & Value ) {26 if ( Value. Denom ! = 0 ) {28 Out << Value.Numer;29 if( Value. Denom != 1 ) Out << '/' << Value. Denom;31 return Out;32 }34 // Messy code for Denom == 035 if (Value.Numer == 0 ) Out << "indeterminate";37 else {39 if( Value.Numer < 0 )Out << '-';41 Out << "infinity";42 } • 43 return Out;44 }
Potential Problems with Macros • #define SQ(X) X * X • expands the code SQ(a + b) • to • a+b*a+b • This problem can be avoided by fully parenthesizing the original macro. However, the solution does not protect against improper types being used. This latter defect is remedied by using inline. • Example: • inline int SQ(int x) { return (x * x); } • //Miles are converted to kilometers. • #include <iostream.h> • const float m_to_k = 1.609; • inline int convert (int mi) { return (mi * m_to_k); } • main () { • int miles; • do { • cout << "Input distance in miles: "; • cin >> miles; • cout << "\nDistance is" << convert(miles) << "km.\n"; • } while (miles > 0); • }
Scope Resolution Operator: In addition to identifying members of a class, it can also be used for accessing global variables. Example: // :: scope resolution operator int i = 1; // external i #include <iostream.h> main() { int i = 2; //redeclares i locally { cout << "enter inner block\n"; int n = i; // the global i is still visible int i = 3; //hides the global i // print the local i and the external i cout << i <<" i <> ::i "<< ::i << "\n"; cout << "n = " << n << "\n"; } cout << "enter outer block\n"; cout << i <<" i <> : :i "<< : :i << "\n"; } The output of this code is enter inner block 3 i <> ::i 1 n = 2 enter outer block 2 i <> ::i 1
Prototypes: double sqrt (double x); void make_str (char*, int); void print (const char* s); int printf (char* format, ...); //variable no. of args default values of parameter: int mult(int n, int k = 2) { //k = 2 is default if (k == 2) return (n * n); else return (mult (n, k - 1) * n); } We assume that most of the time the function is used to return the value of n squared. mult(i + 5) //computes (i + 5) * (i + 5) mult(i + 5, 3) //computes (i + 5) cubed Only the trailing parameters of a function can have default values. Aliases: int n;int& nn = n; //nn is an alternative name for n double a[10];double& last = a[9]; //last is an alias for a[9] char& new_line = '\n';
Dynamic Memory Allocation: //Use of new operator to dynamically allocate an array. #include <iostream.h> main() {int* data; int size; cout << "\nEnter array size: "; cin >> size; data = new int[size]; for (int j = 0; j < size; ++j) cout << (data[j] = j) << "\t"; cout << "\n\n"; delete [ ]data; data = new int[size]; for (j = 0; j < size; ++j) cout << data[j] << "\t"; }
Use of Assertions: The practice of thinking out appropriate assertions frequently causes the programmer to avoid bugs and pitfalls. The C and C++ communities increasingly emphasize the use of such assertions. The standard library assert.h provides the macro void assert(int expression); If the expressi on evaluates as false, then execution is aborted with diagnostic output. The assertions are discarded if the macro NDEBUG is defined. Consider a class vect whose constructor is defined as: vect::vect(int n) { if (n <= 1) { cerr << "illegal vect size" << n << endl; exit(l); } size = n; p = new int[size]; } We replace this with vect::vect(int n) { assert (n > 0); size = n; p = new int[size]; assert (p != 0); } //contractual postcondition Assert macro mainly used to debug the program assert(expression) if the expression is true the program continue, otherwise the program stops with an assertion failed error message