Presentation is loading. Please wait.

Presentation is loading. Please wait.

800 Class Templates Templates are like advanced macros. They are useful for building new classes that depend on already existing user defined classes or.

Similar presentations


Presentation on theme: "800 Class Templates Templates are like advanced macros. They are useful for building new classes that depend on already existing user defined classes or."— Presentation transcript:

1 800 Class Templates Templates are like advanced macros. They are useful for building new classes that depend on already existing user defined classes or built-in types. Example: stack of int or stack of double Until compilers and linkers are integrated better, the template classes definitions as well as code are placed in header file. You include a template file (i.e. header file) in your source program. You should never compile a template file alone. member functions must be template functions.

2 801 An example template class SomeNewClass { public: SomeNewClass(const T1& t1); ~SomeNewClass(); T1& SetData(const T2& t2, int n); : private: T1 a; T2 b; } Code for all functions are placed here.

3 802 Instantiation of Template class #include int main() { SomeNewClass x; SomeNewClass y; : } Compiler will create automatically two sets for functions based on the template code.

4 803 Template List Class template class List { public: List(); ~List(); bool IsEmpty(); void Insert(int pos, const ListItem& item, bool& success); void Delete(int pos, bool& success); :

5 804 Template List Class (contd) private: struct ListNode; typedef ListNode* ListNodePtr; struct ListNode { ListItem item; ListNodePtr next; }; ListNodePtr head; int size; }

6 805 Template List Class (contd) template List ::List() { : } template List ::Insert(int pos, const ListItem& item, bool& success) { : }

7 806 Operator Overloading Standard Operators in C++ can be overloaded to have a different meaning when applied to operands of a new user defined class. The associativity or precedence of the operators remain the same. Operators such as + - * / = == >= | || & [] e.t.c. are all candidates for overloading. When overloading these operators we should maintain the intuitive meaning of these operators. We should also try to be consistent with their usage on built-in types. –a + b does not change a or b. –a = b, changes a but not b. It has value so that we can do c = a = b;

8 807 Operators as member functions If you define an operator using a member function, then the left operand must be an object of the class for which the overloading is done. Operator funtions can be overloaded. e.g. Complex a,b,c; c = a + b; is same as c = a.operator+(b); which in turn is same as c.operator=(a.operator+(b)); Will c = a + 2 work? –Yes!! if Complex class has a constructor that takes an integer as parameter. Compiler will create a temporary object using this constructor and add with a. Then the temporary object is destroyed. Thus, there is implicit casting done on rhs.

9 808 Operator as member function Will c = 2 + a work? –No!! Compiler will not cast 2 into Complex obj. –Casting is done only for function parameters, not for the implicit object. When you define a operator as member function, the lhs operand MUST be an obj of the class. The type of rhs operand can be anything as long as you provide an operator function that takes that type or else there is a constructor function. Casting is done only if it can’t find a matching function. It is not a good idea to depend on casting. If there is more than one way to cast, it leads to confusion.

10 809 Operator as non-member function It is also possible to define the operator functions as non-member functions. Non-member function do not have implicit operand. Both operands are passed. Both operands are defined as const ref parameters. Non-member function can’t access private variables of the class, unless it is defined as friend function inside the class (prototype). If non-member function is defined as friend, it serves as the prototype or else give an explicit prototype anyway. Avoid friend functions as much as possible.

11 810 Operator as non-member function With non-member function operator+ will the following work? –Complex a,b; –b = 2 + a; –Yes!! 2 will be cast as Complex object by compiler Non-member function is preferable to member functions when defining operators. Provide sufficient access functions in the class so that there is no need to give friend status to the function.

12 811 Operator Overloading (contd) class Foo { public: : bool operator<(const Foo& rhs) const; Foo operator+(const Foo& rhs) const; Foo& operator=(const Foo& rhs); bool operator==(const Foo& rhs) const; : } Note the use of const as necessary in defining the operator functions. For templates, Foo becomes, say Foo.

13 812 operator = The left hand side operand is the implicit object. The left-hand side object is assigned the value of right hand side object. The code for operator= should first check for self- assignment. The code should also free the existing values for left hand side object before copying rhs. The return value should be a reference to the left hand side object (which is implicit). This can be done by return(*this). The right hand side object should not change and hence is a const parameter.

14 813 Operator + + means addition for numbers. + can mean concatenation for strings. + can mean Union for sets. + can mean pair-wise addition for arrays or matrix The return value must be a new object. A local variable is needed to create the new object before it can be returned. return statement will invoke copy constructor. Can be very inefficient if a large object creation and copy is made. Inherent problem in C++. We need to depend on compiler to optimize this.

15 814 Operator >> We can define this operator so that we can read an object using iostream. –e.g. Complex a; cin >> a; Notice that the lhs operand is not of type Complex Member function is NOT possible. Always pass iostream objects by reference. Not even const (unless you don’t do io in the fn). Invariably, these functions will need access to private variables and hence the friend access may be needed for this function. The return value should be reference to the stream object passed.

16 815 mutable Suppose we want to implement a class in which we have some private variables that are used for efficiency but not quite associate with the class itself. –e.g. iterators for list use a private pointer curr. –string class can have two variables dataLength and lengthValid flag to compute the length of string and store so that subsequent calls can use this for efficiency instead of recomputing. Length function uses these variables. Should Length be const fn? These functions should be allowed on const objects, but the compiler will not treat them as const functions. Soln: Define these variables as mutable.

17 816 Stream Input Consider reading an integer from cin. –int sum, m, n; –cin >> m >> n; –sum = 0; –while (cin >> m) –{ – sum += m; –} The value of cin >> m should be cin itself so that we can read n in cin >> m >> n; What should the value of cin >> m in while loop? –If the value is cin, which is not NULL, it is always true and hence the loop should be infinite!!!

18 817 Stream Input (Contd) while loop expects an integer. The steam class provides an operator to cast cin to an int. That function ignores the pointer and returns the status of the stream (good or bad). The status of the stream should be bad after reading past end of file or after reading a bad input If the status of a steam is bad, no further input is possible until you clear the stream. When you open a file, if the file does not exist or it could not be opened, the stream is placed in a bad state. Thus, you cannot perform io. If you do, you will get garbage.

19 818 Stream Input (contd) iostream has 4 bits. –enum io_state { goodbit = 0x00, eofbit = 0x01, failbit = 0x02, badbit = 0x04 }; Member Functions: –int good() -- All ok –int eof() -- stream encountered eof –int fail() -- operation not successful –int bad() -- operation invalid –int rdstate() -- read current state –void clear() -- restore to good state –int operator!(); true if fail or bad bit is set. e.g. if (!cin) or if (! (cin >> n))

20 819 Operator>> The operator>> is intended to read an object. If it sees end of file or it sees bad input, it should place the stream in a bad state. It is possible that the stream is placed in a bad state when doing io to read a subpart of the object. In that case, there is nothing to do. If the input read does not meet the expectation, we want to place the stream in bad state by doing –fis.setstate(ios_base::failbit); To clear a stream, you can do –fis.clear();

21 820 Operator++ (or --) ++ and -- are unary operators. The impicit object is the operand. Since there are two types: pre and post, we need a way to distinguish between them. The pre-increment operator for a class Foo is written as –Foo& operator++(); The post-increment operator for a class Foo is written as –Foo& operator++(int); –int argument is not used in the code and hence there is no need to specify the variable name.

22 821 Casting Operators You can write casting operators for a class Foo so that an object of type Foo can be converted to an object of another type. These are special member functions that have the syntax: operator (); –Note that there is no return type. –Note that there is no parameter. –class Foo { : operator int(); : } –Foo a; int b; b = (int)a; – can be any type. e.g. int *, void *, char *, double, etc.

23 822 operator [] This operator overloading is meaningful for an object that has container objects. [] can be used to retrieve individual objects. For example, if we have a vector object, we can access or change individual members. The syntax is: – & operator[](int index) const The return value is a reference object which can be used on lhs or rhs of an assignment statement. The return type can include the keyword const to prevent changes done on the object. Then, we can only retrieve the object but not change it.

24 823 Temporary Object It is possible to create temporary objects that can be useful in expressions. These temporary objects are automatically created and deleted by the compiler. We can create a temporary object by simply using the name of the class. Let us say we have a class called Rational that has a constructor function that takes an integer. Then, we can use it as follows: –Rational a(1,2), b(1,4), c; –c = a + b + Rational(2); –The value of c will be 1/2+1/4+2 = 2 3/4 –c = (int) a; // Need operator int().

25 824 Inheritance If you define a class based on a previously defined class, the derived (or descendant) class is said to inherit many properties of the base (or ancestor) class. It is possible to have an hierarchy of classes arranged in a tree like structure. Inheritance describes the ability of a class to inherit information from ancestor classes. A class can be based on more than one base class in which case we are said to have multiple inheritance. We will avoid it in this course. It is complex and can lead to confusion if not used properly.

26 825 Why Inheritance? Inheritance enables the reuse of existing classes. Inheritance reduces the effort needed to add new features to an existing object. For example, we can have a class called Person and then create a new class called Student and yet another class called Faculty both of which are derived from Person. Features that are common to both classes are placed in Person and hence reduces the need for duplication of information in classes. When an object is created for a class, it is also considered to be an object of all super classes.

27 826 What is inherited? All member of the base class are inherited except the constructors and destructors. The derived class can add new members (both variables and functions) You cannot revise the ancestor’s members. You can redefine member functions to have a different meaning in a derived class. You cannot redefine data members. When an object is created, remember that we need to initialize all variables and this will involve the constructor functions for ancestor classes.

28 827 Inheritance vs Access? The derived class inherits the private variables of the base class but cannot access them directly. Thus, we need to depend on constructor and member functions to deal with these variables. Inheritance does not mean accessibility. The member functions of a derived class can call public member functions of the base class. The member functions of a derived class cannot call private member functions of the base class. What if a function name, say Foo, is common to both classes? An object of a derived class will use the one in derived class and an object of the base class will use the one in base class.

29 828 Protected Members A class can have protected members in addition to public and private. protected members are not accessible to clients of the class. protected members are accessible to derived class. protected category helps to share information among the classes in a single path of the hierarchy without sharing that information with other clients In general, one should place variables in private section. Place them in protected if it is essential to share them with derived classes.

30 829 Kinds of Inheritance Public Inheritance: –Both public and protected members of the base class remain public and protected members of the derived class. (i.e Keep same type of access) Protected Inheritance: –Both public and protected members of the base class become protected members of the derived class. Private Inheritance: –Both public and protected members of the base class become private members of the derived class. Note that the derived class keeps the same access or more stringent access (not more liberal access)

31 830 Data Initialization Since the derived class inherits all data members of the base class, we need to initialize them all. When an object of the derived class is created, we call the constructor function of the derived class. The constructor function of the derived class will automatically call the constructor function of the base class. Thus constructor functions are executed starting from the farthest ancestor to the derived class. Thus, a constructor function of a class is only responsible for initializing variables explicitly defined in that class not for those inherited.

32 831 Is-A Relationship If you find that two classes share “is-a” relationship, then it indicates that you can use public inheritance. An object of the derived class can be substituted for an object of the base class. (Object Type Compatibility). Thus, if a function expects a formal parameter to be of base type class, you can call it with derived class object. Object compatibility applies both to reference and value parameters. This leads to the issue of static vs dynamic (late) binding.

33 832 Has-A relationship A ball-point pen has ball has its point. You wouldn’t want to use a ball wherever a pen is expected! You may not even want to use inheritance here. Make the ball as an object in the pen class. i.e it is a member of the pen class. has-a ==> containment When an object of type pen is created, an object of type ball is indirectly created and hence the constructor function for this should be called. This is done in the initializer list. Destructors are executed in reverse order.

34 833 As-A relationship You can implement stack as a list. When there is “as-a” relationship, consider private inheritance. Both “has-a” and “as-a” relationships are possible when public inheritance in inappropriate. When you have private inheritance, the public and protected members of the base class become private and hence are not accessible to any new derived classes. “has-a” is the simplest to use and is preferable if it is sufficient for your needs.

35 834 Private Inheritance If class D privately inherits from class B, then we can say that “D is implemented in terms of B”. Object of type D cannot be substituted for objects of type B. Private Inheritance means nothing during Software Design, only during Software implementation. Private inheritance means that implementation only is inherited; interface should be ignored. Example: Suppose we implement stack in terms of list. Clearly an object of type Stack has a different interface from an object of type List. List is used only to implement Stack.

36 835 Inheritance Syntax class Ball: public Sphere { : } class Ball: protected Sphere { : } class Ball: private Sphere { : }

37 836 Constructor Usage Ball::Ball():Sphere(),... { : } Ball::Ball(int n):Sphere(n),... { : } call the base class constructor

38 837 early binding Let us assume that both Sphere and Ball classes have a function called Display. Consider the following examples: Sphere s1(3); Ball b1(4); Sphere *p = &s1; Sphere *q = &b1; s1.Display(); // early binding b1.Display(); // early binding p->Display(); // late binding? q->Display(); // late binding? Since p and q are pointers to Sphere, the last two calls will call Display in Sphere. Even the last one!!

39 838 Virtual Functions and Late Binding In the previous example, if we defined Display in Sphere class as a virtual function, then the last example will call the Display in Ball class rather than the one in Sphere class. Virtual keyword ==> Use the function in derived class if it has one. Assume that Display in sphere is declared as virtual. Sphere *p = &s1; p->Display() will still call Display in Sphere as the object is an instance of Sphere, not Ball. So, the question of considering Display in Ball does not even arise.

40 839 What is Late Binding? Thus, the determination of which function to call for a particular statement in the code is done at run time rather than during compiler time. This is known as “late” or “dynamic” binding. Dynamic binding is possible for functions declared as virtual. Thus a virtual function can be overridden in the derived class. The function Display is called “polymorphic”. A polymorphic function has multiple meanings. If you want the function in derived class to override the one in base class, don’t forger virtual!

41 840 Omission of Virtual keyword What happens if we omit virtual keyword? class Sphere { public: double Area() const; virtual Display() const; : } class Ball:public Sphere { public: double Area() const; } Ball class has Display function.

42 841 Omitting Virtual Keyword Ball b(10); b.Display(); Let us say Display calls Area(). Since Area is not defined as virtual, the call to Area in Display will be interpreted by the compiler as the Area in Sphere (static binding). Thus the area function called will be the one in Sphere not the one in Ball. If we had defined Area as virtual, then the Area() function call in Display will use late binding and will call correctly the Area in Ball class.

43 842 Virtual Method Table The compiler creates a table for each class in which it keeps track of the pointer to the actual function to be called for each virtual function defined in the class. VMT is invisible to the programmer as it is automatically created and managed by the compiler. A call to the constructor establishes this table. Thus, VMT enables late (or dynamic) binding.

44 843 Abstract Class When a class defines a virtual function, normally the code for the function is also given. Virtual function means, use the one in base class unless it is overridden in the derived class. Thus the code for the base class virtual function is the most common use of the function. The code in derived classes are used to capture special cases. A base class can decide not to write the code for a virtual function. Thus, every derived class MUST provide one. Such a virtual function is called a pure virtual function. A class with at least one pure virtual function is called an abstract class. No instantiation allowed.

45 844 Abstract Class (contd) Abstract classes are useful to build an hierarchy of classes. We do not create an instance (i.e an object) of an abstract class. It is not allowed in C++. You declare a virtual function as pure by using = 0 –virtual int Display() = 0; If a class does not have any virtual function, it means that it is meant to be used as a base class. If a class has at least one virtual function, you should normally declare the destructor as a virtual function too. It is highly recommended. If a class has no virtual function, don’t declare destructor function as virtual. Bad idea.

46 845 Destructors and Inheritance When you have inheritance, the destructor functions are called in reverse order. What happens if we try to delete a derived class object using a base class pointer? The compiler will call the destructors starting only from the base class going up in the hierarchy. But,we want to call destructors starting from the most specific class. The solution is to make the destructor function virtual in base classes. One twist: If you want to make a class abstract but you have no pure virtual functions, what do you do? Make the destructor a pure virtual function. But, you must provide code for this destructor fn.


Download ppt "800 Class Templates Templates are like advanced macros. They are useful for building new classes that depend on already existing user defined classes or."

Similar presentations


Ads by Google