ADT is Abstract Data Type. How can we use OOP to make ADT as primitive data structure in programming?
Three steps:
define a ADT class
overload operators
optimize visualization to downstream clients
Throw exception
throw exception in function will stop execution; catch exception in main function will show error message; add return 1 in exception catch will stop execution.
NOTE: Dynamic Exception (throw (const char*)) is no longer supported in C++17.
classRational{ public: // constructor Rational(int num = 0, int deno = 1) throw(constchar*);
// accessor and mutator intgetNumerator()const; intgetDenominator()const; voidsetNumerator(constint num); voidsetDenominator(constint deno)throw(constchar*); //Enables operator>> to have access to the private data members friend istream& operator>> (istream& sin, Rational& r);
private: int _numerator; int _denominator;
}; // Arithmetic operators overloading Rational operator+ (const Rational a, const Rational b); Rational operator- (const Rational a, const Rational b); Rational operator* (const Rational a, const Rational b); Rational operator/ (const Rational a, const Rational b) throw(constchar*); // other operators overloading booloperator== (const Rational a, const Rational b); ostream& operator<< (ostream& sout, const Rational& r); ..........
ostream& operator<< (ostream& sout, const Rational& r){ //1. Grabbing the reference to the output stream buffer
//2. Attach the output strings to the buffer based on my likings sout << r.getNumerator() << "/" << r.getDenominator();
//3. Return the reference of the modified output stream buffer return sout; }
istream& operator>> (istream& sin, Rational& r){ //1. Grabbing the reference to the input stream buffer
//2. Acquire the num and the denom from the input and save it to r char slash; sin >> r._numerator>> slash >> r._denominator;
//3. Clear slash, return the reference of the modified input stream buffer returnsin; }
Add _reduce() helper functioin as a private member of the class; _reduce() means reduce fraction form
_reduce() is only be added in Rational(), setNumenator(), getDominator() and operator>>. Because other operator(+, -, *, /) will construct a Rational result automatically which will invoke Rational(). operator<< will not call Rational() but Rational() is always called before <<.
classRational{ public: // constructor explicitRational(int num = 0, int deno = 1)throw(constchar*);
// accessor and mutator intgetNumerator()const; intgetDenominator()const; voidsetNumerator(constint num); voidsetDenominator(constint deno)throw(constchar*); //Enables operator>> to have access to the private data members friend istream& operator>> (istream& sin, Rational& r);
private: int _numerator; int _denominator; void _reduce();
}; ......
Rational::Rational(int num, int deno) throw(constchar*){ if(deno == 0) { throw"denominator is not supposed to be zero!"; return; }
_numerator = num; _denominator = deno;
_reduce(); }
void Rational::_reduce() { int gcd = 1; for(int i = 1; i <= _numerator && i <= _denominator ; i++){ if((_numerator%i == 0) && (_denominator%i == 0)) gcd = i; }
_reduce() in function operator>> is different, because it’s a non-member function but it’s a firend function.
c++ exmple
1 2 3 4 5 6 7 8 9 10 11
istream& operator>> (istream& sin, Rational& r){ //1. Grabbing the reference to the input stream buffer
//2. Acquire the num and the denom from the input and save it to r char slash; sin >> r._numerator>> slash >> r._denominator;
r._reduce(); //3. Clear slash, return the reference of the modified input stream buffer returnsin; }
Because r has been saved in stack, in order to change r, we have to refer r to invoke _reduce().
Invoke _reduce() instead of r._reduce() will result in compile error, although operator>> is a friend function which have access to the private members. why?
Keyword: virtual and final
virtual – permits child ADT to override the implementation of these functions; The client programmer can use the keyword override to override the base implementations
final – prohibits child ADT to override these functions
classRational { public: // constructor explicitRational(int num = 0, int deno = 1)throw(constchar*);
// accessor and mutator intgetNumerator()const; intgetDenominator()const; voidsetNumerator(constint num); voidsetDenominator(constint deno)throw(constchar*); //Enables operator>> to have access to the private data members friend istream& operator>> (istream& sin, Rational& r);
private: int _numerator; int _denominator; void _reduce();
}; // Arithmetic operators overloading Rational operator+ (const Rational a, const Rational b); Rational operator- (const Rational a, const Rational b); Rational operator* (const Rational a, const Rational b); Rational operator/ (const Rational a, const Rational b) throw(constchar*); // other operators overloading booloperator== (const Rational a, const Rational b); ostream& operator<< (ostream& sout, const Rational& r);
Rational::Rational(int num, int deno) throw(constchar*){ if(deno == 0) { throw"denominator is not supposed to be zero!"; return; }
_numerator = num; _denominator = deno;
_reduce(); }
void Rational::_reduce() { int gcd = 1; for(int i = 1; i <= _numerator && i <= _denominator ; i++){ if((_numerator%i == 0) && (_denominator%i == 0)) gcd = i; }
Reference material: Book: Thinking in C++, Volume 1, 2nd Edition, Bruce Eckel. Lectures: University of Waterloo, CS 247 (Software Abstraction and Specificati), 2020 spring term, professor Scott Chen.
Author:Run Zeng
Slogan:Be my own hero. Never never never give up...