1 / 137

C++ Training Datascope Lawrence D’Antonio

C++ Training Datascope Lawrence D’Antonio. Lecture 7 An Overview of C++: What is Polymorphism? – Parametric Polymorphism. What is polymorphism?. Parametric. Universal. Subtype. Polymorphism. Overloading. Ad-hoc. Coercion.

tieve
Télécharger la présentation

C++ Training Datascope Lawrence D’Antonio

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. C++ TrainingDatascopeLawrence D’Antonio Lecture 7 An Overview of C++: What is Polymorphism? – Parametric Polymorphism

  2. What is polymorphism? Parametric Universal Subtype Polymorphism Overloading Ad-hoc Coercion Different types of objects respond to the same message and use the appropriate method.

  3. Parametric Polymorphism • Parametric polymorphism parametrizes the object type (e.g., a list class, where the type of object stored is parametrized). • Parametric polymorphism in C++ is implemented as templates. • Both classes and functions may be templates.

  4. Template Functions template<class T> T max(T a, T b) { return a > b ? a : b; }

  5. Is this legal? int a,b = 6; const int c = 3; double x,y = 3.2; a = max(b,4); a = max(b,c); x = max(y,3.3); x = max(b,y);

  6. a = max(b,4); //Legal, max<int,int> a = max(b,c); //Legal, max<int,int> x = max(y,3.3); //Legal, max<double,double> x = max(b,y); //Illegal, no max<int,double> A template function is called only when there is an exact match for type parameters (only trivial conversions, such as const int to int are allowed). But the following is legal. x = max<double>(4,4.2);

  7. Better max? template<class S, class T> T max(S a, T b) { return a > b ? a : b; } main() { int a, b = 3; double x, y = 3.2; a = max(b,5); x = max(y,5.4); x = max(b,y); x = max(y,b); return 0; }

  8. a = max(b,5); //Legal, returns 5 x = max(y,5.4); //Legal, returns 5.4 x = max(b,y); //Legal, 3.2 x = max(y,b); //Legal, but //returns 3.0!

  9. Best max? template<class R, class S, class T> R max(S a, T b) { return a > b ? a : b; } main() { int a, b = 3; double x, y = 3.2; a = max(b,5); x = max(y,5.4); x = max(b,y); x = max(y,b); return 0; }

  10. Doesn’t compile. The function max() is supposed to have 3 template parameters. But each call only uses 2 parameters.

  11. Try this max template<class R, class S, class T> R max(S a, T b) { return a > b ? a : b; } main() { int a, b = 3; double x, y = 3.2; a = max<int>(b,5); x = max<double>(y,5.4); x = max<double>(b,y); x = max<double>(y,b); return 0; }

  12. Is this legal? • Return back to the original definition of max. int x = 5, y = 6; int *p = &x, *q = &y; int z = max(p,q);

  13. Legal, but probably not what you want. max(p,q) compares addresses, not data values.

  14. Can we fix this? template<class T> T max(T a, T b) { return a > b ? a : b; } template<class T> T* max<T *a, T *b> { return *a > *b ? a : b; }

  15. Should we fix this? • Probably not. Overloading the max function to compare dereferenced pointers means that we can’t compare addresses using max.

  16. STL version of max template<class T> const T &max(const T &a, const T &b) { return a < b ? b : a; }

  17. Another problem const char *s = “Hello”; const char *t = “World”; std::string s = max(s,t); std::cout << s; What does this print out? Who knows? max returns the char* with the larger memory address.

  18. A Solution • Overload the max function. The second is called a template specialization. template<class T> const T& max(const T&a, const T&b) { return a < b ? b : a; } const char* max(const char *a,const char* b) { return std::strcmp(a,b) < 0 ? b : a; }

  19. STL Solution template<class T> const T& max(const T&a, const T&b) { return a < b ? b : a; } template<class T, class BinPred> const T& max(const T&a, const T&b, BinPred comp) { return comp(a,b) ? b : a; }

  20. Using a predicate bool comp(const char *a, const char *b) { return std::strcmp(a,b) < 0; } const char *s = “Hello”; const char *t = “World”; std::string s = max(s,t,comp);

  21. Functor solution class Comp { public: bool operator()(const char *a, const char *b) { return std::strcmp(a,b) < 0; } }; const char *s = “Hello”; const char *t = “World”; std::string s = max(s,t,Comp());

  22. Is this legal? std::string s1(“apple”); std::string s2(“tomato”); std::max(“apple”,”peach”); std::max(“apple”,”tomato”); std::max(“apple”,s1); std::max(s1,s2);

  23. std::max(“apple”,”peach”); //Legal, both arguments are const char[5] std::max(“apple”,”tomato”); //Illegal, arguments are different types std::max(“apple”,s1); //Illegal, arguments are different types std::max(s1,s2); //Legal, both arguments are type string

  24. Is this legal? template<class T> T foo() { return T(); } template<class T> void bar() { T t; } main() { int x = foo(); bar(); return 0; }

  25. Not legal for two reasons. int x = foo(); Illegal because the compiler doesn’t know which version of foo() to call. It won’t determine that foo() should return an int by looking at the LHS. bar(); Illegal because the compiler doesn’t know which version of bar() to call.

  26. Legal version of example template<class T> T foo() { return T(); } template<class T> void bar() { T t; } main() { int x = foo<int>(); bar<int>(); return 0; }

  27. Template name lookup • Template name resolution involves what is known as “two-phase name lookup”. • Template names are divided into two categories: dependent and non-dependent names. • Dependent and non-dependent names are resolved at different times.

  28. Dependent names • Dependent names have definitions that depend on template parameters, but have no declaration within the template definition. • Dependent names are only resolved at the time of instantiation.

  29. Non-dependent names • Non-dependent names are names that don’t depend on a template parameter, the name of the template itself, and names declared within it (members, friends, and local variables).

  30. Example template<class T> class X { T t; public: X(const T &a):t(a) { t.init(); } template<class U> T foo() { U u = t.begin(); return *u; } };

  31. Name resolution in example • Non-dependent names X, t, a, X(const T &), foo(), U, u • Dependent names T::init(), T::begin()

  32. SFINAE • “Substitution failure is not an error.” • When examining which template function to call from a set of overloaded template functions, there is no error if some substitutions are illegal.

  33. Example template<class Func, class T> void apply(Func f, T x) { f(x); } template <class T> void multi(T) { } template <class T*> void multi(T *) { } main() { apply(multi<int>,5); return 0; }

  34. apply(multi<int>,5) calls multi(T) with int substituting for T. The failure of the substitution of int in multi(T*) does cause an error.

  35. Is this legal? template<int N> int g() { return N; } template<int *P> int g() { return *P; } main() { return g<1>(); }

  36. Yes, this is legal (if odd looking). g<1> binds to g<int>, the failure to bind to g<int *> is not an error.

  37. Is this legal? template <class Alloc> class container_helper { typedef Alloc::value_type value_type; };

  38. Not legal, the compiler has no idea what the dependent name Alloc::value_type represents. Here is the correct version. template <class Alloc> class container_helper { typedef typename Alloc::value_type value_type; };

  39. Is this legal? template <class Alloc> class container_helper { typedef typename Alloc::value_type value_type; typedef std::pair<value_type,value_type> element_type; };

  40. Yes, this is legal. typedef std::pair<value_type,value_type> element_type; This can be resolved in scope.

  41. Is this legal? template <class Alloc> class container_helper { typedef typename Alloc::value_type value_type; typedef std::pair<value_type,value_type> element_type; typedef typename Alloc::rebind<element_type>::other element_allocator; };

  42. Not legal, perhaps surprisingly. The compiler cannot determine from Alloc::rebind<element_type>::other what rebind refers to (is it an object, a function, or Superman?).

  43. ADL • Argument-dependent lookup applies to unqualified names where it appears that a nonmember function is being called. • ADL proceeds by looking up a name in namespaces and classes associated with the types of the function call arguments.

  44. Which functions are called? #include <iostream> namespace X { template <class T> void f(T) { std::cout << "f<T>\n"; } } namespace N { using namespace X; enum E{ e1 }; void f(E) { std::cout << "f(E)\n"; } } void f(int) { std::cout << "f(int)\n"; } main() { ::f(N::e1); f(N::e1); return 0; }

  45. ::f(N::e1); //Qualified name, so calls global f, no ADL used f(N::e1); //Calls N::f. The call argument N::e1 is associated //with namespace N. So this means that N::f is //preferred over ::f. Note that X::f is not considered, //because using directives are ignored in ADL.

  46. Is this legal? template<typename T, typename Alloc = std::allocator<T> > class my_container : private container_helper<Alloc>::element_allocator { //... };

  47. Perhaps surprisingly this is legal. The dependent name container_helper<Alloc>::element_allocator cannot be resolved,. But since it is being used as a base class, the compiler is happy.

  48. What is rebind? • A template typedef. template <class T> class allocator { . . . template <class U> struct rebind { typedef allocator<U> other; }; ... template <class U> allocator(const allocator<U>&); };

  49. Use of rebind template <class T, class Allocator = allocator<T> > class list { private: typedef . . . listnode; typedef typename Allocator::rebind<listnode>::other Node_allocator; Node_allocator alloc_; list_node* make_node() { return new(alloc_.allocate(1)) list_node; } public: list(const Allocator& a = Allocator()) : alloc_(a) { } // implicit conversion . . . };

  50. Template classes • The declaration and definition of a template class “must” be in the same header file.

More Related