Calculating with Rational Numbers Rational numbers ( ◗ ) are of the form n d with n and d in ❩ 17. Structs and Classes I C++ does not provide a built-in type for rational numbers Goal Rational Numbers, Struct Definition, Overlading Functions and We build a C++ -type for rational numbers ourselves! Operators, Const-References, Encapsulation 577 578 Vision A First Struct Invariant: specifies valid How it could (will) look like value combinations (infor- struct rational { mal). // input int n; std::cout << "Rational number r =? "; member variable ( n umerator) int d; // INV: d != 0 rational r; std::cin >> r; }; std::cout << "Rational number s =? "; member variable ( d enominator) rational s; std::cin >> s; struct defines a new type formal range of values: cartesian product of the value ranges of // computation and output existing types std::cout << "Sum is " << r + s << ".\n"; real range of values: rational � int × int . 579 580
Accessing Member Variables A First Struct: Functionality A struct defines a new type , not a variable ! struct rational { int n; // new type rational int d; // INV: d != 0 struct rational { Meaning: every object of the new type is rep- }; int n; resented by two objects of type int the ob- int d; // INV: d != 0 jects are called n and d . rational add (rational a, rational b) }; { rational result; // POST: return value is the sum of a and b result.n = a.n ∗ b.d + a.d ∗ b.n; rational add (const rational a, const rational b) result.d = a.d ∗ b.d; { return result; rational result; } result.n = a.n * b.d + a.d * b.n; = a n · b d + a d · b n result.d = a.d * b.d; r n := a n + b n member access to the int objects of a . return result; r d a d b d a d · b d } 581 582 Input Vision comes within Reach ... // Input r rational r; std::cout << "Rational number r:\n"; std::cout << " numerator =? "; // computation std::cin >> r.n; const rational t = add (r, s); std::cout << " denominator =? "; std::cin >> r.d; // output std::cout << "Sum is " << t.n << "/" << t.d << ".\n"; // Input s the same way rational s; ... 583 584
Struct Definitions Struct Defintions: Examples name of the new type (identifier) struct T { struct rational_vector_3 { T 1 name 1 ; rational x; names of the underlying names of the member T 2 name 2 ; rational y; types variables . . rational z; . . . . }; T n name n ; } ; underlying types can be fundamental or user defined Range of Values of T : T 1 × T 2 × ... × T n 585 586 Struct Definitions: Examples Structs: Accessing Members struct extended_int { expression of struct-type T name of a member-variable of type T . // represents value if is_positive==true // and − value otherwise expression of type T k ; value is the value of unsigned int value; expr.name k the object designated by name k bool is_positive; }; member access operator . the underlying types can be different 587 588
Structs: Initialization and Assignment Structs: Initialization and Assignment Default Initialization: Initialization: rational t; rational t = {5, 1}; Member variables of t are default-initialized Member variables of t are initialized with the values of the list, for member variables of fundamental types nothing happens according to the declaration order. (values remain undefined) 589 590 Structs: Initialization and Assignment Structs: Initialization and Assignment = add (r, s) .n t.n ; t.d .d Assignment: Initialization: rational s; rational t = add (r, s); ... rational t = s; t is initialized with the values of add(r, s) The values of the member variables of s are assigned to the member variables of t . 591 592
Structs: Initialization and Assignment Structs: Initialization and Assignment rational s; member variables are uninitialized Assignment: member-wise initialization: rational t = {1,5}; t.n = 1, t.d = 5 rational t; rational u = t; member-wise copy t = add (r, s); t = u; member-wise copy t is default-initialized The value of add (r, s) is assigned to t rational v = add (u,t); member-wise copy 593 594 Comparing Structs? Structs as Function Arguments void increment(rational dest, const rational src) { dest = add (dest, src ); // modifies local copy only For each fundamental type ( int, double,... ) there are } comparison operators == and != , not so for structs! Why? Call by Value ! member-wise comparison does not make sense in general... ...otherwise we had, for example, 2 3 � = 4 rational a; 6 rational b; a.d = 1; a.n = 2; b = a; increment (b, a); // no effect! std :: cout << b.n << "/" << b.d; // 1 / 2 595 596
Structs as Function Arguments User Defined Operators void increment(rational & dest, const rational src) { dest = add (dest, src ); Instead of } rational t = add(r, s); we would rather like to write Call by Reference rational t = r + s; rational a; rational b; a.d = 1; a.n = 2; This can be done with Operator Overloading . b = a; increment (b, a); std :: cout << b.n << "/" << b.d; // 2 / 2 597 598 Overloading Functions Function Overloading A function is defined by name, types, number and order of arguments double sq (double x) { ... } // f1 int sq (int x) { ... } // f2 Functions can be addressed by name in a scope int pow (int b, int e) { ... } // f3 It is even possible to declare and to defined several functions int pow (int e) { return pow (2,e); } // f4 with the same name the compiler automatically chooses the function that fits “best” for a function the “correct” version is chosen according to the signature of the call (we do not go into details) function. std::cout << sq (3); // compiler chooses f2 std::cout << sq (1.414); // compiler chooses f1 std::cout << pow (2); // compiler chooses f4 std::cout << pow (3,3); // compiler chooses f3 599 600
Operator Overloading Adding rational Numbers – Before // POST: return value is the sum of a and b rational add (rational a, rational b) Operators are special functions and can be overloaded { rational result; Name of the operator op : result.n = a.n ∗ b.d + a.d ∗ b.n; operator op result.d = a.d ∗ b.d; we already know that, for example, operator+ exists for different return result; types } ... const rational t = add (r, s); 601 602 Adding rational Numbers – After Other Binary Operators for Rational Numbers // POST: return value is the sum of a and b // POST: return value is difference of a and b rational operator+ (rational a, rational b) rational operator − (rational a, rational b); { rational result; // POST: return value is the product of a and b result.n = a.n ∗ b.d + a.d ∗ b.n; rational operator ∗ ( rational a, rational b); result.d = a.d ∗ b.d; return result; // POST: return value is the quotient of a and b } // PRE: b != 0 ... rational operator/ (rational a, rational b); const rational t = r + s; infix notation 603 604
Unary Minus Comparison Operators are not built in for structs, but can be defined has the same symbol as the binary minus but only one argument: // POST: returns true iff a == b // POST: return value is − a bool operator== (rational a, rational b) rational operator − (rational a) { { return a.n ∗ b.d == a.d ∗ b.n; a.n = − a.n; } return a; 2 3 = 4 } � 6 605 606 Arithmetic Assignment Operator += First Trial rational operator+= (rational a, rational b) We want to write { a.n = a.n ∗ b.d + a.d ∗ b.n; rational r; a.d ∗ = b.d; r.n = 1; r.d = 2; // 1/2 return a; } rational s; does not work. Why? s.n = 1; s.d = 3; // 1/3 r += s; The expression r += s has the desired value, but because the arguments are std::cout << r.n << "/" << r.d; // 5/6 R-values (call by value!) it does not have the desired effect of modifying r . The result of r += s is, against the convention of C++ no L-value. 607 608
Operator += In/Output Operators rational& operator+= (rational& a, rational b) can also be overloaded. { a.n = a.n ∗ b.d + a.d ∗ b.n; Before: a.d ∗ = b.d; return a; std::cout << "Sum is " } << t.n << "/" << t.d << "\n"; this works After (desired): The L-value a is increased by the value of b and returned as std::cout << "Sum is " L-value << t << "\n"; r += s; now has the desired effect. 609 610 In/Output Operators Input // PRE: in starts with a rational number can be overloaded as well: // of the form "n/d" // POST: r has been read from in // POST: r has been written to out std::istream& operator>> (std::istream& in, std::ostream& operator<< (std::ostream& out, rational& r) rational r) { { char c; // separating character ’/’ return out << r.n << "/" << r.d; return in >> r.n >> c >> r.d; } } writes r to the output stream reads r from the input stream and returns the stream as L-value. and returns the stream as L-value. 611 612
Recommend
More recommend