Presentation is loading. Please wait.

Presentation is loading. Please wait.

The Quarks of Object-Oriented Development Deborah J. Armstrong, CACM 49(2006), vol.2 p123-128 ConstructConceptDefinition StructureAbstraction creating.

Similar presentations


Presentation on theme: "The Quarks of Object-Oriented Development Deborah J. Armstrong, CACM 49(2006), vol.2 p123-128 ConstructConceptDefinition StructureAbstraction creating."— Presentation transcript:

1 The Quarks of Object-Oriented Development Deborah J. Armstrong, CACM 49(2006), vol.2 p123-128 ConstructConceptDefinition StructureAbstraction creating classes to simplify aspects of reality using distinctions inherent to the problem. Class a description of the organization and the actions shared by one or more similar objects. Encapsulation restricts access to the data and behavior by defining a limited set of messages an object can receive. Inheritance allows the data and behavior of one class to be used as the basis for another class. Object an individual, identifiable item which contains data about itself and descriptions of its manipulations of the data. BehaviorMessage Passing the process by which an object sends data to another object or asks the other object to invoke an action. Method a way to access, set, or manipulate an object's information. Polymorphism the ability of different classes to respond to the same message and each implement it appropriately.

2 Using Objects Internal, and User-defined Data-types (Classes) Declaration, Definition, Initialization Usage via Name, Reference, or Pointer Manipulating Objects in Expressions via Operators or Functions Objects as Function Parameters Scope and Lifetime Automatic, Dynamic and Static Objects

3 Arrays double x[100]; // x[0]... x[99] double x[3] = {1.1, 2.2, 3.3}; double x[] = {1.1, 2.2, 3.3}; double m[3][3], m1[3][3], m2[3][3]; // Code that initializes m1 and m2... // m = m1 * m2 for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { double sum = 0.0; for (int k = 0; k < 3; k++) { sum += m1[i][k] * m2[k][j]; } m[i][j] = sum; }

4  C++ arrays use 0-origin subscripting and the elements are stored row-wise.  Warning: m[1,2] is a valid C++ expression, but it does not access a multidimensional array.  Multidimensional arrays are arrays of arrays. int m[2][3] = { {1,2,3}, {4,5,6} };  m consists of two elements (rows), each a one-dimensional array of three elements. int 1 m[0][0] int 2 m[0][1] int 3 m[0][2] int 6 m[1][2] int 5 m[1][1] int 4 m[1][0]

5 Pointers int* p; int i = 3; p = &i; int j = 4; P = &j; *p = 5; p = 0;... if (p != 0) cout << "Pointer " << p << " points to " << *p << endl; int i int 3 : int* p int* : int j int 4 : int* p int* : int i int 3 : &x address of x *p indirection, value of object pointed to by p

6 Pointers and Arrays float x[5]; x[0]: x[1]: x[2]: x[3]: x[4]: float float float float float float[5] x : float* Conversion Whenever x is used in an expression - except as the operand of &, sizeof or to initialize a reference - it is converted into a pointer to the first element of the array. x is of type array of float, but used as pointer to float.

7 Arithmetic on Pointers x + 2 x points to x[0] x+i points to x[i] *(x+i) is equivalent to x[i] x+i is equivalent to &x[i]  Integers can be added (or subtracted) to a pointer to an array element.  It acts as offset. The result is a pointer of the same type, which points to the element the specified number of elements away. x[0]: x[1]: x[2]: x[3]: x[4]: float float float float float float[5] x : float* Conversion

8 float x[10]; //... initialize x... float* left = &x[0]; float* right = &x[9]; while (left < right) { float temp = *left; *left++ = *right; *right-- = temp; } float x[10]; float* p = &x[10]; while (p != x) *--p = 0.0;

9 const Pointers, Pointers to const Objects const float pi = 3.14159; const float* p = π pi = 2; // Compile Error *p = 2; // Compile Error float a, b; float* const p1 = &a; *p1 = 10; p1 = &b; // Compile Error const float e = 2.718281828; const float* const p2 = &e; Read complex declarations from the identifier back toward the beginning of the statement. C Programmers: Do not use #define to define symbolic constants, use const for individual constants or enum for enumerations.

10 Runtime Array Size // Create arrays with the // desired number of elements int n; cin >> n; double* const x = new double[n]; double* const y = new double[n]; // Read the data points for (int i = 0; i < n; i++) { cin >> x[i] >> y[i]; } // Accumulate sums Sx and Sy // in double precision double sx = 0.0; double sy = 0.0; for (i = 0; i < n; i++) { sx += x[i]; sy += y[i]; } // Compute coefficients double sx_over_n = sx / n; double stt = 0.0; double b = 0.0; for (i = 0; i < n; i++) { double ti = x[i] - sx_over_n; stt += ti * ti; b += ti * y[i]; } b /= stt; double a = (sy - sx * b) / n; delete [] x; delete [] y; cout << a << " " << b << endl;

11 Pointer Operators *p Indirection &x Pointer to object a[i] Array subscript p->m Class member selection ++p, p++ Pre(Post)increment to next element --p, p-- Pre(Post)decrement to previous element p+=n Increment by n elements p-=n Decrement by n elements p+n Offset by n elements p-n Negative offset by n elements new T Allocate object new T[n] Allocate array of n objects delete p Delete object delete []p Delete array of objects

12 Classes  OO Programming  Two Simple Classes  An Array Class  Class Templates  Function Templates  Exceptions  Nested Classes  Overview of C++ Programs

13 Today  Classes  Memory Management  Classes and Functions in Detail  Inheritance

14 Object-Oriented Programming  Object-oriented programming views a program as collection of agents, termed objects. Each object is responsible for specific tasks.  An object is an encapsulation of state (data members) and behavior (operations).  The behavior of objects is dictated by the object class.  An object will exhibit its behavior by invoking a method (similar to executing a procedure).  Objects and classes extend the concept of abstract data types by adding the notion of inheritance.

15 Variety of Classes  Domain Classes / Data Managers / Materials Classes whose principle responsibility is to maintain data values  Data Sinks or Sources Objects that interface to data generators or consumers, but do not hold data themselves  View or Observer Classes, Tool Classes Classes that provide the graphical display of an object, but are not the object themselves  Helper Classes, Container Classes Classes that maintain little or no state information, but assist in the execution of complex tasks

16 What Do Classes Represent  Classes that directly reflect concepts in the application domain.  Classes that are artifacts of the implementation.  User-level concepts (e.g. cars and trucks)  Generalization of user-level concepts (e.g. vehicles)  Hardware ressources (e.g. memory manager)  System ressources (e.g. output streams)  Helper classes (e.g. lists, queues, locks,...)

17 Two Simple Classes  Classes are programmer-defined types. class class-name ;// Declaration class class-name {// Definition class-body }; class Point {... }; Point a; // creates an object of type Point Point square_vertices[4]; // creates an array of four Points Remember the trailing semicolon in class definitions.

18 Mapping of Abstractions to Software real worldabstractionssoftware entity attributes behaviour class Entity attribute1... function1()...

19 CRC Cards for Class Design CRC Class-Responsibility-Collaborator Class-Name Responsibility 1 Responsibility 2.... Collaborator 1 Collaborator 2...

20 Point Line  Create from coordinates  Compute distance to another point  Compute distance to a line  Get x- and y-coordinates

21 Line Point  Create from two points  Create from point and direction  Intersect with another line  Compute distance to a point

22 Point definition typedef double Number; class Line; class Point { public: Point(); // Create uninitialized Point(Number x, Number y); // Create from (x,y) Number distance(Point point); // Distance to another point Number distance(Line line); // Distance to a line Number x(); // Get x-coordinate Number y(); // Get y-coordinate private: Number the_x; // x-coordinate Number the_y; // y-coordinate }; Class members: data members member functions

23 Using Point Objects #include using namespace std; #include "Point.h" int main() { // Read the coordinates of a point and print the distance // from the origin to the point. Point origin(0, 0); Number x; Point p1(1, 2); Number y; Point* p_ptr; cin >> x >> y; p_ptr = &origin; Point p(x, y); cout distance(p1) << e cout << origin.distance(p) << endl; return 0; }

24 Point origin Point : float the_y float 0.0 : float the_x float 0.0 : Data members of a class should be declared private to ensure that they are only accessed from within member functions. class Point { public:... Point(Number x, Number y);... private: Number the_x; Number the_y; }; Point origin(0, 0);

25 Line definition class Line { public: Line(Point p1, Point p2); // Line through p with tangent Line(Point p, Number xDir, Number yDir); Point intersect(Line line); Number distance(Point point); // Smallest nonparallel angle (radians) static Number parallelism_tolerance; private: // ax + by + c = 0 Number a; Number b; Number c; };

26 Using Line Objects // Vertical line through origin Line l1(Point(0,0), Point(0,1)); //"anonymous" point objects are used for this line // Line through (1,2) in direction Line l2(Point(1,2), 1, 1); Point intersection; intersection = l1.intersect(l2); cout << "(" << intersection.x() << "," << intersection.y() << ")" << endl;

27 Member Function Definition Point::Point(Number x, Number y) { the_x = x; the_y = y; } Point::Point() {} Number Point::x() { return the_x; } Number Point::y() { return the_y; } Number Point::distance(Point point) { Number x_dif = the_x - point.the_x; //member – member of the object passed Number y_dif = the_y - point.the_y; return sqrt(x_dif * x_dif + y_dif * y_dif); } Number Point::distance(Line line) { double result = line.distance(*this); return result; }

28 Shared Objects inside Classes: static Point Line::intersect(Line line) { // Intersect with line. If the angle between the two lines // is less than the parallelism_tolerance, return the point // at infinity. The parallelism test computes the square of // the sin of the angle. We assume that the tolerance is // small enough for sin(theta) to be approximately equal to //theta. Number det = a * line.b - line.a * b; Number sinsq = (det * det) / ( (a*a + b*b) * (line.a*line.a + line.b*line.b) ); if (sinsq < parallelism_tolerance * parallelism_tolerance) { return Point(FLT_MAX, FLT_MAX); } else { return Point( (b * line.c - line.b * c) / det, (c * line.a - line.c * a) / det ); } Number Line::parallelism_tolerance =.01745; // 1 degree (in rad) Line::parallelism_tolerance =.02618; // 1.5 degrees (in radians)

29 An Array Class: Operator Member Functions #include #include "SimpleFloatArray.h" void linefit() { // Create arrays with the desired number of elements int n; std::cin >> n; SimpleFloatArray x(n); SimpleFloatArray y(n); // Read the data points for (int i = 0; i < n; i++) { std::cin >> x[i] >> y[i]; } //... same as before... }

30  Runtime sizing with size given as constructor argument.  Access to element i in array x by evaluation of x[i].  Automatic management of dynamically allocated memory associated with the array.  Automatically copy array elements when arrays are copied.  Assign one array to another, and assign one float value to every array element.  Ask array's size and resize an array dynamically.

31 Runtime sizing with size given as constructor argument. class SimpleFloatArray { public: SimpleFloatArray(int n); // Create array of n elements SimpleFloatArray(); // Create array of 0 elements... private: int num_elts; // Number of elements float* ptr_to_data; // Pointer to built-in array of elements }; SimpleFloatArray::SimpleFloatArray(int n) { num_elts = n; ptr_to_data = new float[n]; } SimpleFloatArray::SimpleFloatArray() { num_elts = 0; ptr_to_data = 0; }

32 Access to element i in array x by evaluation of x[i]. class SimpleFloatArray { public:... float& operator[](int i); // Subscripting... private: int num_elts; // Number of elements float* ptr_to_data; // Pointer to built-in array of elements }; float& SimpleFloatArray::operator[](int i) { return ptr_to_data[i]; }

33 Access to element i in array x by evaluation of At(i). class SimpleFloatArray { public:... float& At(int i); // Subscripting... private: int num_elts; // Number of elements float* ptr_to_data; // Pointer to built-in array of elements }; float& SimpleFloatArray::At(int i) { return ptr_to_data[i]; } SimpleFloatArray d(100); cout << d[50] <<.... cout << d.At(50),...

34 Automatic management of dynamically allocated memory associated with the array: destructor class SimpleFloatArray { public:... ~SimpleFloatArray(); // Destructor: destroy array... private: int num_elts; // Number of elements float* ptr_to_data; // Pointer to built-in array of elements }; SimpleFloatArray::~SimpleFloatArray() { delete [] ptr_to_data; } When invoked with a null pointer, delete and delete [] have no effect.

35 Automatically copy array elements when arrays are copied: copy constructor class SimpleFloatArray { public:... SimpleFloatArray(const SimpleFloatArray&); // Copy Constructor... private: int num_elts; // Number of elements float* ptr_to_data; // Pointer to built-in array of elements void copy(const SimpleFloatArray& a); // Copy in elements from a }; SimpleFloatArray::SimpleFloatArray(const SimpleFloatArray& a) { num_elts = a.num_elts; ptr_to_data = new float[num_elts]; copy(a); // Copy a's elements }

36 void SimpleFloatArray::copy(const SimpleFloatArray& a) { // Copy a's elements into the elements of *this float* p = ptr_to_data + num_elts; float* q = a.ptr_to_data + num_elts; while (p > ptr_to_data) *--p = *--q; }; or void SimpleFloatArray::copy(const SimpleFloatArray& a) { // Copy a's elements into the elements of *this for(int i=0; i<num_elts; ++i) ptr_to_data[i] = a.ptr_to_data[i]; }

37 Assign one array to another, and assign one float value to every array element: copy assignment operator class SimpleFloatArray { public:... SimpleFloatArray& operator=(const SimpleFloatArray&);... private: int num_elts; // Number of elements float* ptr_to_data; // Pointer to built-in array of elements void copy(const SimpleFloatArray& a); // Copy in elements from a }; SimpleFloatArray& SimpleFloatArray::operator=(const SimpleFloatArray& rhs) { if ( ptr_to_data != rhs.ptr_to_data ) { setSize( rhs.num_elts ); copy(rhs); } return *this; } Assignment should work correctly when left and right operands are the same object.

38 Ask array's size and resize an array dynamically. class SimpleFloatArray { public:... SimpleFloatArray& operator=(const SimpleFloatArray&); SimpleFloatArray& operator=(float); // Scalar assignment int numElts(); // Number of elements void setSize(int n); // Change size private: int num_elts; // Number of elements float* ptr_to_data; // Pointer to built-in array of elements void copy(const SimpleFloatArray& a); // Copy in elements from a };

39 Class Templates class SimpleFloatArray { public: SimpleFloatArray(int n); SimpleFloatArray(); SimpleFloatArray(const SimpleFloatArray&); ~SimpleFloatArray(); float& operator[](int i); int numElts(); SimpleFloatArray& operator=(const SimpleFloatArray&); SimpleFloatArray& operator=(float); void setSize(int n); private: int num_elts; float* ptr_to_data; void copy(const SimpleFloatArray& a); };

40 Class Template Definition template class SimpleArray { public: SimpleArray(int n); SimpleArray(); SimpleArray(const SimpleArray &); ~SimpleArray(); T& operator[](int i); int numElts(); SimpleArray & operator=(const SimpleArray &); SimpleArray & operator=(T); void setSize(int n); private: int num_elts; T* ptr_to_data; void copy(const SimpleArray & a); };

41 Class Templates: Usage #include #include "SimpleArray.h" void linefit() { // Create arrays with the desired number of elements int n; std::cin >> n; SimpleArray x(n); SimpleArray y(n); // Read the data points for (int i = 0; i < n; i++) { std::cin >> x[i] >> y[i]; } //... same as before... }

42 Member function definition for class templates void SimpleFloatArray::copy(const SimpleFloatArray& a) { // Copy a's elements into the elements of *this float* p = ptr_to_data + num_elts; float* q = a.ptr_to_data + num_elts; while (p > ptr_to_data) *--p = *--q; } template void SimpleArray ::copy(const SimpleArray & a) { // Copy a's elements into the elements of *this T* p = ptr_to_data + num_elts; T* q = a.ptr_to_data + num_elts; while (p > ptr_to_data) *--p = *--q; }

43 Overview of C++ Programs File sys.h File A.h File B.h File main.C #include #include"A.h" #include"B.h" main() {... } File A.C #include"A.h" (Code for A) File B.C #include"B.h" (Code for B) Class A Class B

44 Memory Management Object Life Cycle:  Construction  Allocation  Preinitialization  Initialization  Use  Destruction  Cleanup  Post cleanup  Deallocation  Object Lifetime  Static Objects  Automatic Objects  Dynamic Objects  Preventing Dangling References and Garbage

45 Object Lifetime  Static objects allocated once and not freed until program termination.  Automatic objects allocated when their declarations are executed and freed automatically when the block containing them terminates.  Dynamic objects allocated and freed in arbitary order under the programmers control.

46 Class Noisy to trace object con/de struction #include "Noisy.h" Noisy func(Noisy n) { std::cout<< "inside func\n"; return n;} int main() { Noisy x("x"); std::cout<<"\ncalling func\n"; Noisy c = func(x); std::cout<<"after func\n"; std::cout << '\n'; return 0; }

47 constructing: (name=x id=0) calling func copy construct: (name=x id=1) from: (name=x id=0) inside func copy construct: (name=x id=2) from: (name=x id=1) destroying: (name=x id=1) after func destroying: (name=x id=2) destroying: (name=x id=0)

48 Noisy.h #ifndef NOISY_H #define NOISY_H #include class Noisy { static long objects_created; long id; std::string name; public: Noisy(std::string n=""): id(objects_created++), name(n) { if (name == "") { std::ostringstream n; n << "obj_" << id ; name = n.str(); } std::cout<<"constructing: " << *this << '\n'; }

49 Noisy(const Noisy& n): id(objects_created++), name(n.name) { std::cout<<"copy constuct: " << *this << " from: " << n << '\n'; } ~Noisy() {std::cout<<"destroying: " << *this << std::endl;} Noisy& operator=(const Noisy& rhs) { std::cout<<"assignment: " << *this << " = " << rhs << '\n'; name = rhs.name; return *this; } friend std::ostream& operator<<(std::ostream& os, const Noisy &n) { return os << "(name=" << n.name << " id=" << n.id << ')'; } }; // class Noisy long Noisy::objects_created = 0; #endif

50 Static Objects  are allocated once and are not freed until the program terminates.  Scope:  class scope class A {...; static int a;...}; A::a = 1;  file scope with external linkage extern int a; int a = 1;  file scope with internal linkage static int a;  local scope {...; static int a = 1;...}

51 Use the extern keyword to declare file scope names with external linkage; omit the extern keyword on their definitions. extern int a; // Declaration, external linkage extern Complex a; // Decalration, external linkage int a = 1; // Definition, initialized to 1 Complex c1; // Definition, default constructor Avoid file scope objects with external linkage; use class scop instead. extern const double c; extern const double k; const double c = 3.00e8; const double k = 1.38e-23; namespace PhysicalConstants { public: static const double c;... } const double PhysicalConstants::c = 3.00e8;... Prefer namespace scope names to file scope names.

52 static Noisy s1("s1"); // File scope static object. void fnc(int j) { cout << "-- starting fnc(" << j << ") --" << endl; static Noisy s2("s2"); if (j == 2) { static Noisy s4("s4"); } for (int i = 1; i <= 2; i++) { cout << "-- loop i=" << i << " --" << endl; static Noisy s3("s3"); } cout << "-- returning from fnc(" << j << ") --" << endl; } int main() { cout << "-- main starts --" << endl; fnc(1); fnc(2); cout << "-- main ends --" << endl; return 0; } static Noisy s5("s5"); // File scope static object.

53 Automatic Objects int main() { cout << "-- main starts --" << endl; Noisy a1("a1"); for (int i = 1; i <= 2; i++) { cout << " -- loop i= " << i << " -- " << endl; Noisy a2("a2"); // Object created each loop iteration. if (i == 2) { Noisy a3("a3"); // Object created if i == 2. } cout << "-- loop is done -- " << endl; Noisy a4("a4"); cout << "-- main ends --" << endl; return 0; };

54 void f2() { cout << "-- f2 starts -- " << endl; Noisy c("c"); throw "exception"; cout << "-- f2 ends -- " << endl; } void f1() { cout << "-- f1 starts -- " << endl; Noisy a("a"); f2(); Noisy b("b"); cout << "-- f1 ends -- " << endl; } int main() { cout << "-- main starts --" << endl; try { f1(); } catch(const char*) { cout << "Exception caught." << endl; } cout << "-- main ends --" << endl; return 0; }

55 Dynamic Objects  Construction int* p = new int; int* q = new int(3); Rational* r = new Rational(8,9); int* a = new int[n];  Destruction delete p; delete q; delete r; delete [] a;  The worst problems arise from bad deletions:  deleting an object more than once  deleting a pointer not obtained by new  using the wrong form of new Provide a default constructor for every class possible. Match every invocation of new with exactly one invocation of delete of the same kind.

56 Preventing Dangling References and Garbage  Dangling Class Members class Dangle { public: Dangle() { p = new int(0);} ~Dangle() { delete p; } private: int* p; }; void f() { Dangle a; Dangle b = a; } Dangle a Dangle b : : int 0 int* p : int* int* p : int* Provide a copy constructor and an assignment operator for classes with a pointer data member that is deleted by the destructor.

57  Dangling Pointers to Automatic Objects void dangle(int j) { int* p; if (j < 100) { // Dangling reference created when this block terminates int iarray[100]; p = iarray; } else p = new int[j]; for (int i = 0; i < j; i++) p[i] = i; } Avoid pointers to automatic objects.

58  Pointers Left Dangling by Function Calls void f(int* x) { //... delete [] x; // Causes dangling reference } void dynamic_dangle(int size) { int* iarray = new int [size]; f(iarray); for (int i = 0; i < size; i++) cout << iarray[i]; } Don't delete a functions argument.

59  Garbage Memory / Memory Leaks (failing to delete) is the opposite of the dangling reference problem. Hold pointers in class objects and pair new and delete in the class's constructors and destructors.

60 The Uses Relationship If an object of one class sends a message to an object of another class, the first object is said to have a uses relationship with the second class. How can the first object know the name of the object it wants to use? Car get_gasoline(50€) Where ?

61 get_gasoline(50€, Aral) Car class Car { public: void get_gasoline(GasStation &, double); }; void Car::get_gasoline(GasStation &s, double money) {... gas_received = s.give_gasoline(money);... } GasStation station1(...); Car car1(...); car1.drive(...); car1.get_gasoline(station1, 50); car1.drive(...); by parameter

62 Car1 get_gasoline(50€) The gas station give_gasoline(50€) give_gasoline(40€) Car2 GasStation theGasStation(...); class Car { public: void get_gasoline(double); }; void Car::get_gasoline(double money) {... gas_received = theGasStation.give_gasoline(money);... } Car car1(...); car1.drive(...); car1.get_gasoline(50); by global object

63 class Car { public: void get_gasoline(double); }; void Car::get_gasoline(double money) {... GasStation station(...); gas_received = station.give_gasoline(money);... } Car car1(...); car1.drive(...); car1.get_gasoline(50); create a local station

64 class Car { private: GasStation *station; public: Car(GasStation *s,...): station(s) {...} void get_gasoline(double); }; void Car::get_gasoline(double money) {... gas_received = station->give_gasoline(money);... } GasStation s(...); Car car1(s,...); car1.drive(...); car1.get_gasoline(50); by construction

65 Car get_gasoline(50€) Map get_station() by third-party class class Map { private: GasStation *quadrant[4]; public: GasStation* get_station(int,int); }; GasStation* Map::get_station(int x, int y) { if(x>0) return (y>0) ? quadrant[0]:quadrant[3]; else return (y>0) ? quadrant[1]:quadrant[2]; } class Car { private: Map myMap; public: void get_gasoline(double); }; void Car::get_gasoline(double money) { GasStation *station = myMap.get_station(x,y); gas_received = station->give_gasoline(money);... }

66 by containment class Car { private: GasStation myStation; public: void get_gasoline(double); }; void Car::get_gasoline(double money) { gas_received = station.give_gasoline(money);... } by inheritance class Car: public GasStation { public: void get_gasoline(double); }; void Car::get_gasoline(double money) { gas_received = give_gasoline(money);... }

67 Functions and Classes  Member Functions and Overloading  Initialization  Copying  Conversion  Operator Functions  Assignment  Special Operators  Destruction  Static Member Functions  Friend Functions  I/O Operators for Classes

68 Member Functions and Overloading class Point { public: Point(); // Create uninitialized Point(Number x, Number y); // Create from (x,y) Number distance(Point point) const; // Distance to another point Number distance(Line line) const; // Distance to a line Number& x(); // Reference to x-coordinate Number x() const; // Get x-coordinate Number& y(); // Reference to y-coordinate Number y() const; // Get y-coordinate Number angle(Point p1, Point p3) const; private: Number the_x; // x-coordinate Number the_y; // y-coordinate };

69 Point p1(2, 3); cout << p1.x() << endl; // Uses non-const x() p1.x() = 1; // Uses non-const x() p1.y() = 2; // Uses non-const y() const Point p2 = p1; cout << p2.x() << endl; // Uses const x() p2.x() = 3; // Compile Error p2.y() = 4; // Compile Error Declare member functions that are not meant to alter member data const.

70 Initialization: Constructors class Circle { public: Circle(double radius); // Of specified radius centered at origin Circle(Point center, double radius); // From center and radius Circle(Point p1, Point p2, Point p3);// From three points on circle Circle(LineSegment chord, Point p); // From chord and point on cir. Circle(LineSegment diameter); // From diameter //... private: Point the_center; double the_radius; }; Circle::Circle(double radius) : the_center(0, 0) { the_radius = radius; }

71 A member initializer does not need to be provided for a data member in two cases: 1. The data member is of a built-in type. Its value is undefined. 2. The data member is of a programmer defined type. The default constructor is called. A member initializer must be provided for a data member, if: 1. There is no default constructor for the member's type. 2. The data member is a reference. 3. The data member is declared const. Avoid using the value of one member in the initialization for another member. Member initializations should appear in the order in which the members are declared.

72 Copying: Copy Constructor  Objects can be copied by assignment or by initialization:  operator=(const C&)  Copy constructor: C::C(const C&), C::(C&)  shallow copy versus deep copy  C++ default copy constructor: shallow copy Circle c1(Point(1,2), 10); // No copy Circle c2(c1); // c2 initialized by copying c1 Circle c3 = 10; // Create Circle(10.0) then initialize // c3 from it

73 shallow copy aSimpleFloatArray int 5; float* bSimpleFloatArray int 5; float* float 1.0 float 9.0 float 5.0 float 2.0 float 1.0

74 deep copy aSimpleFloatArray int 5; float* bSimpleFloatArray int 5; float* float 1.0 float 9.0 float 5.0 float 2.0 float 1.0 float 1.0 float 9.0 float 5.0 float 2.0 float 1.0

75 Automatically copy array elements when arrays are copied: copy constructor class SimpleFloatArray { public:... SimpleFloatArray(const SimpleFloatArray&); // Copy Constructor... private: int num_elts; // Number of elements float* ptr_to_data; // Pointer to built-in array of elements void copy(const SimpleFloatArray& a); // Copy in elements from a } SimpleFloatArray::SimpleFloatArray(const SimpleFloatArray& a) { num_elts = a.num_elts; ptr_to_data = new float[num_elts]; copy(a); // Copy a's elements }

76 A class that has built-in pointer member data not referring to data shared with other objects should have a copy constructor. The argument to a copy constructor should be a const reference.

77 Conversions  A constructor that can take a single argument defines a user-defined conversion.  A conversion function is a member function with the target type name following the keyword operator.  Such conversions are used in the argument matching process and in any other context in which C++ does automatic type conversion.

78 class Boolean { public: enum constants { false = 0, true = 1 }; // Construction. Boolean() {} // Construct uninitialized. Boolean(int i) : v(i != 0) {} // Initialize to (i != 0). Boolean(float f) : v(f != 0) {} // Initialize to (f != 0). Boolean(double d) : v(d != 0) {} // Initialize to (d != 0). Boolean(void* p) : v(p != 0) {} // Initialize to (p != 0). operator int() const{ return v; } // Conversion to int. Boolean operator!() const { return !v; } // Negation. private:Boolean b1(Boolean::true); // Boolean(int) char v;Boolean b2(3); // Boolean(int) };int* p_i =new int(3); Boolean b3(p_i); // Boolean(void *) Boolean b4(3.0); // Boolean(float)

79 Boolean has_real_solution(double a, double b, double c) { // Does ax**2 + bx + c = 0 have a real solution? return sqr(b) >= 4 * a * c; } if ( has_real_solution(a, b, c) ) { //... return 1; } Provide conversion from one class to another with either the copy constructor or a conversion function, but not both. class ComplexFloat { public: //... operator ComplexDouble() const; //... }; class ComplexDouble { public: //...ComplexFloat cf; ComplexDouble(const ComplexFloat&);... //...ComplexDouble cd = cf; };

80 class ComplexInt { public: //... }; class ComplexFloat { public: //... ComplexFloat(ComplexInt); //... }; class ComplexDouble { public: ComplexDouble(ComplexInt);ComplexInt ci; ComplexDouble(ComplexFloat);//... //...double a = arg(ci); }; // Principal value of the argument of z extern float arg(ComplexFloat z); // Principal value of the argument of z extern double arg(ComplexDouble z); Minimize the number of user-defined conversions from any given type. Working code can be broken by introducing new classes.

81 class Array { public: Array(int n); // Create n element array of int's Array(const Array&); // Copy array Array& operator=(const Array&); // Assign array //... }; //... Array a(5); a = 5; ComplexDouble toComplexDouble() const; Avoid single argument constructors when possible. Provide few user-defined conversions. Declare single argument constructors when explicit.

82 Operator Functions  Operators in C++ are specified (declared) and implemented (defined) in terms of equivalent functions, but they are used as operators. Complex& Complex::operator*=(const Complex& rhs) { float original_real_part = real_part; real_part = real_part * rhs.real_part - imag_part * rhs.imag_part; imag_part = imag_part * rhs.real_part + original_real_part * rhs.imag_part; return *this; } Complex a(1,1); Complex b(2,3); a *= b; a.operator*=(b);

83  All C++ operators can be defined for class objects, except:..* :: ?: new delete sizeof  No new operator symbols can be invented.  The 'arity', precedence and associativity of programmer-defined operators follows that of built-in operators.  An unary operator can be defined by either a member function with no arguments or as a global function with one argument, etc. Give operators conventional definitions.

84 class Complex{ public:... Complex operator+(const Complex&) const;... } Complex a; Complex b; b = a + 3.0; // 3.0 is converted to Complex(3.0) b = 3.0 + b; // Compile error (3.0).operator+(b) Complex operator+(const Complex&, const Complex&); Complex a; Complex b; b = a + 3.0; // 3.0 is converted to Complex(3.0) b = 3.0 + b; // 3.0 is converted to Complex(3.0) Declare symmetric binary operators as global functions.

85 Declare asymmetric binary operators and unary operators that modify their operand as member functions. Define symmetric binary operators to call their corresponding asymmetric assignment operator. Complex operator*(const Complex& lhs, const Complex& rhs) { Complex result(lhs); return result *= rhs; } Never overload &&, || or,. Function call semantic differs from short-circuit semantic because all parameters must be evaluated and the order of evaluation is unspecified.

86 Assignment Assignment member functions should work correctly when the left and the right operands are the same. A class that has built-in pointer member data that are not meant to point to shared data should have an assignment operator. The argument to an assignment operator should be a const reference. Assignment operator functions should return a reference to their left operand.

87 Static Member Functions class ComplexFloat { public: ComplexFloat(float r, float i); static ComplexFloat fromFile(istream& input = cin); //... }; ComplexFloat ComplexFloat::fromFile(istream& input) { float r; input >> r; float i; input >> i; return ComplexFloat(r, i); } ComplexFloat c = ComplexFloat::fromFile();

88 Friend Functions class A; class B { double g() const; double g(); double g(int); void h(); }; class C { public: friend int f(double); // Global function: int f(double) friend double B::g() const; // Member of B: double g() const // Note: only one of B's g members is a friend friend class D; // All members of D friend A; // All members of A; A already declared private: friend void B::h(); // Member of B: void h() };

89 Friend Usage Example: Container Iterator int main() { // Read list of values and find minimum. List list; float val; float minval = FLT_MAX; // Max float value, from float.h while ( cin >> val) { if (val < minval) minval = val; list.add(val); } // Normalize values and write out. for (ListIterator i(list); i.more(); i.advance()) { cout << i.current() - minval << endl; }...

90 template class List { public: List() : first(0), last(0) {}... void add(T x) { if (first == 0) first = last = new Node(x); else last = last->link = new Node(x); } void remove(T x); //... friend ListIterator ; private: class Node { public: Node(T x) : link(0), datum(x) {} Node* link; T datum; }; Node* first; Node* last; };

91 template class ListIterator { public: ListIterator(const List & list) : cur(list.first) {} bool more() const { return cur != 0; } T current() const { return cur->datum; } void advance() { cur = cur->link; } private: List ::Node* cur; };

92 Exceptions: throw class SubscriptRangeError { public: SubscriptRangeError(int i); int badSubscript(); private: int subscript; }; inline SubscriptRangeError::SubscriptRangeError(int i) { subscript = i; } inline int SubscriptRangeError::badSubscript() { return subscript; }... template T& CheckedSimpleArray ::operator[](int i) { if (i =num_elts) throw SubscriptRangeError(i);...

93 Exceptions: try, catch try { int n; cin >> n; CheckedSimpleArray a(n);... int j; cin >> j; float x = 2.1 * a[j];... } catch(SubscriptRangeError e) { cerr << "Bad subscript = " << e.badSize() << endl; } Use exceptions to decouple the treatment of "errors" from the code dealing with the ordinary processing.

94 Nested Classes class Outer { public:... class Inner1 {... }... private:... class Inner2 {... }... } Within the enclosing class a nested class can be referenced to using just ist name. From outside the enclosing class, a nested class may be refrenced via the scope resolution operator :: Outer::Inner1 Use class nesting to group related classes that work together.

95 Object-Oriented Programming  Object-oriented programming views a program as collection of agents, termed objects. Each object is responsible for specific tasks.  An object is an encapsulation of state (data members) and behavior (operations).  The behavior of objects is dictated by the object class.  An object will exhibit its behavior by invoking a method (similar to executing a procedure).  Objects and classes extend the concept of abstract data types by adding the notion of inheritance.

96 Inheritance in C++ base / derived class public / private inheritance non-virtual / virtual / pure virtual member functions concrete / abstract classes

97 Mammal speak() Dog bark() Cat mew() class Mammal { public: speak(); } class Dog: public Mammal { public: void bark(); } class Cat: public Mammal { public: void mew(); }

98 Public Inheritance, Non-Virtual Members class Mammal { // base class public: void speak() {cout << "can't speak" << endl;} }; class Dog : public Mammal { // derived class public: void speak() {cout << "wouf" << endl;} void bark() {cout << "wouf wouf" << endl;} }; class Cat : public Mammal { // derived class public: void mew() {cout << "mew mew" << endl;} }; Mammal fred; fred.speak(); Dog lassie; lassie.speak(); lassie.bark(); Cat sue; sue.speak(); //since speak is not defined for Cat, //the output is "cant speak" sue.mew(); Mammal* x = new Dog(); // this is allowed ! x->speak(); // "cant speak" x = &sue; x->speak();

99 Public Inheritance, Virtual Members class Mammal { // base class public: virtual void speak() {cout << "can't speak" << endl;} }; class Dog : public Mammal { // derived class public: void speak() {cout << "wouf" << endl;} void bark() {cout << "wouf wouf" << endl;} }; class Cat : public Mammal { // derived class public: void mew() {cout << "mew mew" << endl;} }; Mammal fred; fred.speak(); Dog lassie; lassie.speak(); Cat sue; sue.speak(); Mammal* x = new Dog(); x->speak(); // "wouf" because speak is virtual // x only can use "Mammal" functions // because its a mammal x = &sue; x->speak(); Virtual member functions to support polymorphism.

100 Public Inheritance, Pure Virtual Members class Mammal { // abstract base class public: virtual void speak() = 0; //pure virtual member function }; class Dog : public Mammal { // derived class public: void speak() {cout << "wouf" << endl;} void bark() {cout << "wouf wouf" << endl;} }; class Cat : public Mammal { // derived class public: void speak() {cout << "mew" << endl;} void mew() {cout << "mew mew" << endl;} }; // Mammal fred; // fred.speak(); Dog lassie; lassie.speak(); Cat sue; sue.speak(); Mammal* x[n]; x[0] = &lassie; x[1] = &sue; for(int i=0;i<n;i++) { x[i]->speak(); } x[0]->bark(); // Error Abstract classes serve as interfaces.

101 "abstract" Mammal speak() DogCat

102 Private Inheritance class Mammal { public: void speak() {cout << "can't speak" << endl;} }; class Dog : private Mammal { public: void bark() {speak();} }; class Cat : public Mammal { public: void mew() {cout << "mew mew" << endl;} } Mammal fred; fred.speak(); Dog lassie; lassie.bark(); lassie.speak(); // Error Cat sue; sue.speak(); //this works Private inheritance to share implementation.

103 Public Inheritance, Virtual Members class Mammal { // base class public: virtual void speak() {cout << "can't speak" << endl;} }; class Dog : public Mammal { // derived class public: void speak() {cout << "wouf" << endl;} void bark() {cout << "wouf wouf" << endl;} }; class Cat : public Mammal { // derived class public: void mew() {cout << "mew mew" << endl;} }; Mammal fred; fred.speak(); Dog lassie; lassie.speak(); Cat sue; sue.speak(); Mammal* x = new Dog(); x->speak(); x = &sue; x->speak(); Virtual member functions to support polymorphism.

104 Access to Base Class Members class One { public: int element1; protected: int element2; private: int element3; }; class Two : public One { }; clients of Two clients of Three clients of Four... class Three : private One { }; class Four : protected One { }; class Five : public Three { }; class Six: public Four { };

105 dynamic_cast (), typeinfo #include Dog lassie; Cat sue; Mammal* m[3]; m[0] = &lassie; m[1] = &sue;... for ( i=0;i<3;i++) cout << typeid(m[i]).name() << ", "; cout << endl; for ( i=0;i<3;i++){ Dog* d = dynamic_cast (m[i]);//0 or a valid pointer if(d) d->bark(); // if the pointer is valid, bark }

106 Forms of Inheritance Specialization: The derived class is a subtype, a special case of the base class. Specification : The base class defines behavior that is implemented in the derived class. Construction : The derived class makes use of the behavior provided by the base class, but is not a subtype of the base class. Generalization : The derived class modifies some of the methods of the base. Extension : The derived class adds new functionality to the base, but does not change any inherited behavior. Limitation : The derived class restricts the use of some of the behavior inherited from the base. Variance : The derived class and the base class are variants of each other, and the base/derived class relationship is arbitrary. Combination : The derived class inherits from more than one base class.


Download ppt "The Quarks of Object-Oriented Development Deborah J. Armstrong, CACM 49(2006), vol.2 p123-128 ConstructConceptDefinition StructureAbstraction creating."

Similar presentations


Ads by Google