Oop Presentation

1,983 views

Published on

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,983
On SlideShare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
66
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Oop Presentation

  1. 1. Object Oriented Programming - Essential Techniques S G Ganesh sgganesh@gmail.com
  2. 2. Language Pragmatics  A language is not just syntax and learning a language isn’t just learning to program.  Mastering a language requires good understanding of language semantics, pragmatics, traps and pitfalls with considerable experience in programming and design using that language.
  3. 3. Five Specific OO Tips and Techniques  We’ll see 5 specific tips/techniques  Based on understanding, experience and usage of language features  Tips are about pragmatics of using language features  The mistakes covered in the tips are errors in usage  Examples in C++ and Java (sometimes in C#)
  4. 4. 1. Avoid calling virtual functions in constructors  Constructors do not support runtime polymorphism fully as the derived objects are not constructed yet when base class constructor executes.  So, avoid calling virtual functions from base- class constructors, which might result in subtle bugs in the code.
  5. 5. C++ resolves virtual function calls to base type struct base { base() { vfun(); } virtual void vfun() { cout << “Inside base::vfunn”; } }; struct deri : base { virtual void vfun() { cout << “Inside deri::vfunn”; } }; int main(){ deri d; }
  6. 6. C++ resolves virtual function calls to base type struct base { base() { vfun(); } virtual void vfun() { cout << “Inside base::vfunn”; } }; struct deri : base { virtual void vfun() { cout << “Inside deri::vfunn”; } }; int main(){ deri d; } // prints:Inside base::vfun
  7. 7. Java/C# resolves virtual function calls dynamically // Java example class base { public base() { vfun(); } public void vfun() { System.out.println(quot;Inside base::vfunquot;); } } class deri extends base { public void vfun() { System.out.println(quot;Inside deri::vfunquot;); } public static void main(String []s) { deri d = new deri(); } }
  8. 8. Java/C# resolves virtual function calls dynamically // Java example class base { public base() { vfun(); } public void vfun() { System.out.println(quot;Inside base::vfunquot;); } } class deri extends base { public void vfun() { System.out.println(quot;Inside deri::vfunquot;); } public static void main(String []s) { deri d = new deri(); } } // prints: Inside deri::vfun
  9. 9. In C++, pure virtual methods might get called struct base { base() { base * bptr = this; bptr->bar(); // even simpler ... ((base*)(this))->bar(); } virtual void bar() =0; }; struct deri: base { void bar(){ } }; int main() { deri d; }
  10. 10. In C++, pure virtual methods might get called struct base { base() { base * bptr = this; bptr->bar(); // even simpler ... ((base*)(this))->bar(); } virtual void bar() =0; }; struct deri: base { void bar(){ } }; int main() { deri d; } // g++ output: // pure virtual method called // ABORT instruction (core dumped)
  11. 11. Dynamic method call in Java might lead to trouble // Java code class Base { public Base() { foo(); } public void foo() { System.out.println(quot;In Base's foo quot;); } } class Derived extends Base { public Derived() { i = new Integer(10); } public void foo() { System.out.println(quot;In Derived's foo quot; + i.toString() ); } private Integer i; } class Test { public static void main(String [] s) { new Derived().foo(); } }
  12. 12. Dynamic method call in Java might lead to trouble // Java code class Base { public Base() { foo(); } public void foo() { System.out.println(quot;In Base's foo quot;); } } class Derived extends Base { public Derived() { i = new Integer(10); } public void foo() { System.out.println(quot;In Derived's foo quot; + i.toString() ); } private Integer i; } class Test { public static void main(String [] s) { new Derived().foo(); } } // this program fails by throwing a NullPointerException
  13. 13. 2. Preserve the basic properties of methods while overriding  Overriding the methods incorrectly can result in bugs and unexpected problems in the code.  Adhering to Liskov’s Substitution Principle is possible only when overriding is done properly.  Make sure that the method signatures match exactly while overriding is done  Provide semantics similar to the base method in the overridden method.
  14. 14. In C++, provide consistent default parameters struct Base { virtual void call(int val = 10) { cout << “The default value is :”<< endl; } }; struct Derived : public Base { virtual void call(int val = 20) { cout << “The default value is :”<< endl; } }; // user code: Base *b = new Derived; b->call();
  15. 15. In C++, provide consistent default parameters struct Base { virtual void call(int val = 10) { cout << “The default value is :”<< endl; } }; struct Derived : public Base { virtual void call(int val = 20) { cout << “The default value is :”<< endl; } }; // user code: Base *b = new Derived; b->call(); // prints: // The default value is: 10
  16. 16. In Java, final might be removed while overriding class Base { public void vfoo(final int arg) { System.out.println(quot;in Base; arg = quot;+arg); } } class Derived extends Base { public void vfoo(int arg) { arg = 0; System.out.println(quot;in Derived; arg = quot;+arg); } public static void main(String []s) { Base b = new Base(); b.vfoo(10); b = new Derived(); b.vfoo(10); } }
  17. 17. In Java, final might be removed while overriding class Base { public void vfoo(final int arg) { System.out.println(quot;in Base; arg = quot;+arg); } } class Derived extends Base { public void vfoo(int arg) { arg = 0; System.out.println(quot;in Derived; arg = quot;+arg); } public static void main(String []s) { Base b = new Base(); b.vfoo(10); b = new Derived(); b.vfoo(10); } } // prints: // in Base; arg = 10 // in Derived; arg = 0
  18. 18. Provide consistent exception specification struct Shape { // can throw any exceptions virtual void rotate(int angle) = 0; // other methods }; struct Circle : public Shape { virtual void rotate(int angle) throw (CannotRotateException) { throw CannotRotateException(); } // other methods }; // client code Shape *shapePtr = new Circle(); shapePtr->rotate(10); // program aborts!
  19. 19. 3. Beware of order of initialization problems.  Many subtle problems can happen because of order of initialization issues.  Avoid code that depends on particular order of implementation as provided by the compiler or the implementation.
  20. 20. In C++, such init can cause unintuitive results // translation unit 1 int i = 10; // translation unit 2 extern int i; int j = i; // j is 0 or 10? // depends on the compiler/link line.
  21. 21. In Java, such init can cause unintuitive results class Init { static int j = foo(); static int k = 10; static int foo() { return k; } public static void main(String [] s) { System.out.println(quot;j = quot; + j); } }
  22. 22. In Java, such init can cause unintuitive results class Init { static int j = foo(); static int k = 10; static int foo() { return k; } public static void main(String [] s) { System.out.println(quot;j = quot; + j); } } // prints // j=0
  23. 23. 4. Avoid switch/nested if-else based on types  Programmers from structured programming background tend to use extensive use of control structures.  Whenever you find cascading if-else statements or switch statements checking for types or attributes of different types to take actions, consider using inheritance with virtual method calls.
  24. 24. C# code to switch based on types public enum Phone { Cell = 0, Mobile, LandLine } // method for calculating phone-charges public static double CalculateCharges(Phone phone, int seconds){ double phoneCharge = 0; switch(phone){ case Phone.Cell: // calculate charges for a cell case Phone.Mobile: // calculate charges for a mobile case Phone.LandLine: // calculate charges for a landline } return phoneCharge; }
  25. 25. C# code with if-else using RTTI abstract class Phone { // members here } class Cell : Phone { // methods specific to cells } // similar implementation for a LandLine public static double CalculateCharges(Phone phone, int seconds){ double phoneCharge = 0; if(phone is Cell){ // calculate charges for a cell } else if (phone is LandLine){ // calculate charges for a landline } return phoneCharge; }
  26. 26. C# code: Correct solution using virtual functions abstract class Phone { public abstract double CalculateCharges(int seconds); // other methods } class Cell : Phone { public override double CalculateCharges(int seconds){ // calculate charges for a cell } } // similar implementation for a LandLine // Now let us calculate the charges for 30 seconds Phone ph = new Cell (); ph.CalculateCharges(30);
  27. 27. 5. Avoid hiding of names in different scopes.  Hiding of names in different scopes is unintuitive to the readers of the code  Using name hiding extensively can affect the readability of the program.  Its a convenient feature; avoid name hiding as it can result in subtle defects and unexpected problems.
  28. 28. Hiding of names can happen in different situations  The name in the immediate scope can hide the one in the outer scope (e.g. function args and local variables)  A variable in a inner block can hide a name from outer block (no way to distinguish the two)  Derived class method differs from a base class virtual method of same name in its return type or signature - rather it is hidden.  Derived member having same name and signature as the base-class non-virtual non-final member; the base member is hidden (e.g. data members)
  29. 29. C++ examples for name hiding // valid in C++, error in Java/C# void foo { // outer block int x, y; { // inner block int x = 10, y = 20; // hides the outer x and y } } // C++ Code int x, y; // global variables x and y struct Point { int x, y; // class members x and y Point(int x, int y); // function arguments x and y };
  30. 30. C++/Java/C# example for a bug with hiding // Bug in C++, Java and C# Point(int x, int y) { x = x; y = y; } // C++ Point(int x, int y) { this->x = x; this->y = y; } // Java and C# Point(int x, int y) { this.x = x; this.y = y; }
  31. 31. C++: No overloading across scopes struct Base { void foo(int) { cout<<quot;Inside Base::foo(int)quot;; } }; struct Derived : public Base { void foo(double) { cout<<quot;Inside Derived::foo(double)quot;; } }; Derived d; d.foo(10);
  32. 32. C++: No overloading across scopes struct Base { void foo(int) { cout<<quot;Inside Base::foo(int)quot;; } }; struct Derived : public Base { void foo(double) { cout<<quot;Inside Derived::foo(double)quot;; } }; Derived d; d.foo(10); // prints: // Inside Derived::foo(double)
  33. 33. Java: Overloading across scopes! class base { public void foo(int i) { System.out.println(quot;In Base::foo(int)quot;); } } class deri extends base { public void foo(double i) { System.out.println(quot;Inside deri::foo(double)quot;); } public static void main(String []s) { deri d = new deri(); d.foo(10); } }
  34. 34. Java: Overloading across scopes! class base { public void foo(int i) { System.out.println(quot;In Base::foo(int)quot;); } } class deri extends base { public void foo(double i) { System.out.println(quot;Inside deri::foo(double)quot;); } public static void main(String []s) { deri d = new deri(); d.foo(10); } } // prints: Inside Base::foo(int)
  35. 35. How to write robust code and avoid defects?  Many of the language rules, semantics and pragmatics are unintuitive  What can help in detecting bugs early?  Tools (but of limited extent)  Extensive testing  Peer review  Good knowledge and experience  No other approach can create robust code than passion towards writing excellent code
  36. 36. Q&A
  37. 37. Thank you!

×