1 00:00:05,600 --> 00:00:08,800 In this video, we'll see how we can use abstract classes 2 00:00:08,800 --> 00:00:11,100 as interfaces in c++. 3 00:00:12,800 --> 00:00:15,000 An interface class in c++ 4 00:00:15,000 --> 00:00:17,800 is a class that has only pure virtual functions. 5 00:00:18,200 --> 00:00:22,560 These functions provide a general set of services that users of the class can use. 6 00:00:22,960 --> 00:00:27,360 In order to be useful, these pure virtual functions must be declared as public. 7 00:00:27,720 --> 00:00:31,720 Any class that wants to be a concrete class and support the interface 8 00:00:31,720 --> 00:00:33,380 provided by the interface class 9 00:00:33,380 --> 00:00:37,370 can override the pure virtual functions and implement these services as needed. 10 00:00:38,030 --> 00:00:40,390 Remember, every service must be implemented, 11 00:00:40,390 --> 00:00:43,690 and c++ will strictly enforce type information. 12 00:00:43,690 --> 00:00:47,290 So when overriding the function, prototypes must match exactly. 13 00:00:49,090 --> 00:00:51,790 Unlike java, c#, and other languages, 14 00:00:51,790 --> 00:00:54,990 c++ does not provide a specific keyword 15 00:00:54,990 --> 00:00:58,890 or way to create an interface as part of the c++ core language. 16 00:00:59,190 --> 00:01:03,550 So in c++, we use abstract classes with pure virtual functions 17 00:01:03,550 --> 00:01:05,750 to achieve the concept of an interface. 18 00:01:06,550 --> 00:01:09,650 Suppose we want to be able to provide any user-defined object, 19 00:01:09,650 --> 00:01:12,010 the ability to be printed on a stream like cout, 20 00:01:12,310 --> 00:01:15,410 we can do this by creating a printable interface class 21 00:01:15,410 --> 00:01:18,610 that provides the service in terms of a pure virtual function. 22 00:01:19,310 --> 00:01:23,300 And then our user-defined classes can simply be derived from printable 23 00:01:23,300 --> 00:01:25,600 and override this pure virtual function. 24 00:01:27,360 --> 00:01:28,360 Let's see an example. 25 00:01:29,350 --> 00:01:31,850 Here you can see that we have a class name printable, 26 00:01:31,850 --> 00:01:34,350 and it has a pure virtual function named print. 27 00:01:35,150 --> 00:01:37,450 This makes this class an abstract class. 28 00:01:37,950 --> 00:01:40,610 The printable class also adds a friend function 29 00:01:40,610 --> 00:01:45,210 that we'll use to allow us to print any type of object that conforms to this interface. 30 00:01:46,340 --> 00:01:48,700 You can see that the overloaded operator function 31 00:01:49,560 --> 00:01:52,920 You can see that the overloaded operator function at the bottom of the screen, 32 00:01:52,920 --> 00:01:55,120 and it calls obj.print. 33 00:01:55,780 --> 00:01:59,780 This would dynamically bind to the print function of whatever object type was 34 00:01:59,780 --> 00:02:04,380 passed in since we know that that object is printable and we have a reference to it. 35 00:02:05,040 --> 00:02:06,740 That's pretty powerful stuff. 36 00:02:06,740 --> 00:02:11,240 At the end of these slides, we'll head over to the IDE, and I'll show you how we can use this interface 37 00:02:11,240 --> 00:02:14,440 with the account hierarchy as well as with non-account classes. 38 00:02:16,440 --> 00:02:18,940 So for any class to be printable, 39 00:02:19,240 --> 00:02:21,440 it must be derived from printable, 40 00:02:21,440 --> 00:02:26,040 and it must override the pure virtual function print that's in the printable interface. 41 00:02:26,540 --> 00:02:30,740 That's it. So in this case, you can see that any class is derived from printable 42 00:02:31,040 --> 00:02:34,300 and it does override the print pure virtual function. 43 00:02:34,300 --> 00:02:36,500 Now any class is a printable. 44 00:02:38,000 --> 00:02:40,660 So let's create some any class objects and print them. 45 00:02:41,160 --> 00:02:45,760 First, we create ptr as a pointer20 class and create an any class object. 46 00:02:46,260 --> 00:02:48,860 Then we dereference the pointer to get that object, 47 00:02:48,860 --> 00:02:50,740 and we use it in an output statement. 48 00:02:51,500 --> 00:02:54,400 This will call the overloaded insertion operator, 49 00:02:54,400 --> 00:02:57,400 which will, in turn, call the function print of any class, 50 00:02:57,800 --> 00:03:00,800 and this will display "hi from any class". 51 00:03:01,790 --> 00:03:05,150 Now suppose we have two functions, function1 and function2. 52 00:03:05,810 --> 00:03:08,810 Function1 expects an any class object by reference, 53 00:03:09,060 --> 00:03:12,060 and function2 expects a printable object by reference. 54 00:03:12,760 --> 00:03:17,420 Well, we can call both these functions and pass in the object ptr is pointing to, 55 00:03:17,620 --> 00:03:21,120 why, because that object is an instance of any class 56 00:03:21,370 --> 00:03:23,730 and because that object is a printable. 57 00:03:24,430 --> 00:03:26,790 In both cases, we get the same output. 58 00:03:26,790 --> 00:03:29,790 The print function in any class is bound dynamically. 59 00:03:31,590 --> 00:03:36,090 Let's see another example. Here we have a shape class that only has pure virtual functions. 60 00:03:36,590 --> 00:03:40,790 So it's an abstract class, and it can also be used as an interface class. 61 00:03:41,690 --> 00:03:45,290 What we're saying is if you want to be a concrete shape, 62 00:03:45,490 --> 00:03:49,390 then you must be derived from shape and you must override the draw and the 63 00:03:49,390 --> 00:03:52,290 rotate pure virtual functions. So let's do that. 64 00:03:53,930 --> 00:03:56,920 Here we declare a circle class derived from the shape class. 65 00:03:57,820 --> 00:04:00,520 We know that if we want a circle to be a concrete class, 66 00:04:00,520 --> 00:04:03,180 then we must override draw and rotate, 67 00:04:03,180 --> 00:04:05,480 and that's exactly what we're doing in this example. 68 00:04:05,780 --> 00:04:09,780 Sometimes you'll see classes that are intended to be used as interface classes 69 00:04:09,780 --> 00:04:12,380 named with a capital I preceding the class name. 70 00:04:12,930 --> 00:04:17,430 This makes it easy to know just by the name that the class is intended to be used as an interface. 71 00:04:17,930 --> 00:04:21,529 As you can see in this example, shape was renamed to I shape. 72 00:04:23,330 --> 00:04:25,990 Now when you see circle being derived from I shape, 73 00:04:25,990 --> 00:04:28,980 you know that I shape is intended as an interface class. 74 00:04:29,480 --> 00:04:31,980 This isn't a requirement but you tend to see that out there. 75 00:04:33,340 --> 00:04:37,640 So we can now use pointers to I shape objects to use dynamic polymorphism. 76 00:04:38,300 --> 00:04:41,300 Here we create a vector of pointers to I shape objects, 77 00:04:41,300 --> 00:04:46,100 and then we create three pointers and initialize them to point to three different types of shapes. 78 00:04:47,300 --> 00:04:50,550 In order to call the overridden functions in the concrete classes, 79 00:04:50,550 --> 00:04:53,050 we simply loop through the vector and call the functions. 80 00:04:53,410 --> 00:04:56,110 You might be thinking isn't this the same as we did before? 81 00:04:56,510 --> 00:04:58,710 Yes, since we must use inheritance 82 00:04:58,710 --> 00:05:01,410 and pure virtual functions as interfaces in c++. 83 00:05:02,070 --> 00:05:05,270 But there's another difference, and I'll show you that example in live code. 84 00:05:05,270 --> 00:05:07,470 Let's head over to the IDE now and we'll see. 85 00:05:08,670 --> 00:05:13,330 Okay so I'm back in the IDE. I'm in the section 16 workspace in the interfaces 86 00:05:13,330 --> 00:05:14,830 -start project. 87 00:05:15,730 --> 00:05:19,730 We're going to do eventually is to implement that printable interface, 88 00:05:20,030 --> 00:05:23,230 so that we're able to print any kind of class objects 89 00:05:23,230 --> 00:05:28,130 on a stream, any kind of class objects that conform to the printable interface. 90 00:05:28,130 --> 00:05:30,930 So let's use this account hierarchy as a starting point. 91 00:05:31,230 --> 00:05:35,030 This is similar to what we did in the previous sections challenge. 92 00:05:35,030 --> 00:05:37,910 I've gotten rid of a lot of the other stuff that's not necessary, 93 00:05:37,910 --> 00:05:40,210 but let's just look at the key elements here. 94 00:05:40,210 --> 00:05:43,010 Here we've got a class account, right here. 95 00:05:43,610 --> 00:05:45,710 And you can see that we have a friend function 96 00:05:46,210 --> 00:05:50,570 that overloads the insertion operator, it expects an output stream 97 00:05:50,930 --> 00:05:53,730 and an account object by reference, perfect. 98 00:05:54,720 --> 00:05:58,220 Now we're going to implement that, and we're going to implement that right here. 99 00:05:58,220 --> 00:06:01,720 You can see that it's obviously a friend, it's not a member of the class, 100 00:06:02,380 --> 00:06:03,880 and it expects an account. 101 00:06:04,680 --> 00:06:07,680 So if we have an account object and we put it on a stream, 102 00:06:07,680 --> 00:06:10,680 this should fire and print it out, and that absolutely works. 103 00:06:10,680 --> 00:06:12,880 And all it does is just says account display. 104 00:06:13,380 --> 00:06:15,580 Okay. So now let's look at checking account. 105 00:06:15,580 --> 00:06:17,680 You can see the checking account is doing the same thing. 106 00:06:17,680 --> 00:06:20,180 We do we're duplicating this code all over the place, 107 00:06:20,880 --> 00:06:24,880 and it's right here. There's my checking account. It is an account. 108 00:06:24,880 --> 00:06:27,440 Well, I've got to do this now with a checking here. 109 00:06:27,440 --> 00:06:31,100 So I'm implementing it over here. So this definitely works with the checking account, 110 00:06:31,100 --> 00:06:32,900 and it displays checking display. 111 00:06:33,590 --> 00:06:35,950 The reason that we have to do this is because 112 00:06:35,950 --> 00:06:38,350 a friend functions are not inherited. 113 00:06:38,950 --> 00:06:42,950 So even though I've got this guy up here, I'm not getting them down here 114 00:06:42,950 --> 00:06:44,550 or further down the hierarchy. 115 00:06:44,550 --> 00:06:45,910 So that's one issue. 116 00:06:45,910 --> 00:06:50,610 The other issue is that in order for us to implement this operator, the insertion operator, 117 00:06:50,810 --> 00:06:53,810 it really doesn't make sense for it to be a member function. 118 00:06:53,810 --> 00:06:57,610 Remember, if it was a member function, I'd need the object on the left, 119 00:06:57,610 --> 00:07:00,110 followed by insertion operator and then the stream. 120 00:07:00,510 --> 00:07:04,810 Well, that's not how we do it, right. We're doing something like stream object. 121 00:07:05,800 --> 00:07:10,400 So this really would work for sure, but it would feel really clunky, and nobody would ever use it. 122 00:07:11,400 --> 00:07:13,400 So we've run into a problem now. 123 00:07:13,700 --> 00:07:17,300 We're doing the same for the savings account class right here 124 00:07:17,900 --> 00:07:20,100 and the trust account class right here. 125 00:07:20,100 --> 00:07:21,460 So that's all we're doing. We're just 126 00:07:21,460 --> 00:07:25,560 creating these four classes, overloading the insertion operator for each one of them, 127 00:07:25,560 --> 00:07:29,560 and each one of them will display savings display, trust display and so forth. 128 00:07:29,560 --> 00:07:33,660 So we can have a simple main, and this is what main looks like right here. 129 00:07:34,060 --> 00:07:37,860 Give me an account a, put it on the stream. Give me an account c, 130 00:07:38,520 --> 00:07:41,720 same thing, same thing. You get the idea, a c s t. 131 00:07:41,720 --> 00:07:46,280 We should see account display, checking display, savings display, trust display. 132 00:07:46,280 --> 00:07:48,080 So let's run that and, be sure this works. 133 00:07:48,580 --> 00:07:50,780 And that's what we get. We've got our four objects: 134 00:07:50,780 --> 00:07:54,580 the account, the checking, the savings, the trust, everything works like it should, 135 00:07:55,130 --> 00:07:57,830 but it really doesn't. There's one problem here. 136 00:07:59,830 --> 00:08:03,630 And let me copy some code that I've already written in here just to save a little time. 137 00:08:03,630 --> 00:08:05,230 So here's the code we've got now. 138 00:08:05,780 --> 00:08:10,180 We've got p1 is a pointer to an account, right. That's a base class pointer. 139 00:08:10,380 --> 00:08:13,240 And I'm creating an account and pointing to it from p1. 140 00:08:13,640 --> 00:08:15,440 And then I'm going to put 141 00:08:15,440 --> 00:08:19,140 the object, right. So I need to dereference p1 because p1 is a pointer. 142 00:08:19,140 --> 00:08:22,020 So I want the object it's pointing to and I want to put that on the stream. 143 00:08:22,820 --> 00:08:26,120 This will call the overloaded operator for the account. 144 00:08:26,480 --> 00:08:28,980 Now I want to do the same thing with p2. 145 00:08:28,980 --> 00:08:32,340 Except p2 this time is actually pointing to a checking account. 146 00:08:33,000 --> 00:08:35,500 Although again, we're coming at it through a base class pointer. 147 00:08:36,299 --> 00:08:38,500 And I want to dereference p2 and put it on the stream. 148 00:08:38,500 --> 00:08:42,400 So what we expect is to say account display, checking display, 149 00:08:42,400 --> 00:08:45,060 but that's not what happens. And let's see what happens. 150 00:08:46,560 --> 00:08:49,160 You see what happens is account display, account display. 151 00:08:49,460 --> 00:08:52,260 Why does this happen? Well, it happens because 152 00:08:52,260 --> 00:08:56,760 we've got no virtual functions going on right. The only virtual functions we've got are -- 153 00:08:56,760 --> 00:09:01,360 let me close this down so you can see it exactly. Let's go up to my account class. 154 00:09:02,360 --> 00:09:05,160 And the only virtual functions we've got are 155 00:09:05,760 --> 00:09:08,760 withdraw, right. That's it. That's the only virtual function we have. 156 00:09:08,760 --> 00:09:13,260 We have no virtual function that's going to allow us to work with 157 00:09:13,760 --> 00:09:17,760 any kind of account object in the context of this operator here, 158 00:09:18,120 --> 00:09:21,420 and it's really clunky to do so because of the syntax. 159 00:09:21,420 --> 00:09:22,920 So what we could do is 160 00:09:22,920 --> 00:09:26,220 we could certainly add some kind of print function to this account class 161 00:09:26,220 --> 00:09:28,580 and it's inherited all the way down and make it virtual. 162 00:09:28,580 --> 00:09:30,130 And that's kind of what we'll do. 163 00:09:30,130 --> 00:09:33,630 But what we'll do is we'll create a separate interface class 164 00:09:33,630 --> 00:09:35,630 rather than put all the stuff in account. 165 00:09:35,630 --> 00:09:38,390 And what that buys us is that not only am I able to use that 166 00:09:38,390 --> 00:09:40,990 printable interface class that we're going to create 167 00:09:40,990 --> 00:09:44,790 with this account hierarchy, I can use it with any kind of class, 168 00:09:44,790 --> 00:09:46,990 not just these account classes. 169 00:09:46,990 --> 00:09:51,250 So let's do that. What I'm going to do is I'm going to switch over to the interfaces 170 00:09:51,250 --> 00:09:53,500 dash complete project. 171 00:09:53,500 --> 00:09:56,400 Right now it looks just like this one, but what we'll do is we'll modify 172 00:09:56,400 --> 00:09:58,700 it and get this working with the printable interface. 173 00:09:59,000 --> 00:10:02,660 Okay. So I'm back in the interfaces-complete project. 174 00:10:03,160 --> 00:10:06,520 And you can see that right now it's exactly what we did earlier. 175 00:10:06,520 --> 00:10:11,120 I haven't changed this code at all. So this is exactly what was in interfaces-start. 176 00:10:11,520 --> 00:10:15,120 So what we want to do is we want to create an interface class called printable 177 00:10:15,120 --> 00:10:16,120 or i printable. 178 00:10:16,720 --> 00:10:18,720 We want you to find a virtual function in there. 179 00:10:18,720 --> 00:10:22,920 And then we just want to extend this so it makes more sense and it works better. 180 00:10:23,280 --> 00:10:27,270 So first thing we're going to do is we're going to clean up this mess that we've got going on here. 181 00:10:27,270 --> 00:10:30,470 So I'm going to delete all these friend functions right here. 182 00:10:31,470 --> 00:10:35,370 And I'm going to lead their implementations as well. So I'm going to get rid of the account one, 183 00:10:35,370 --> 00:10:39,770 and this will definitely clean up our code a lot. I'll get rid of this guy right here. 184 00:10:40,170 --> 00:10:43,170 I'll get rid of that implementation for the checking account. 185 00:10:44,420 --> 00:10:46,080 I'll get rid of the one in savings. 186 00:10:47,580 --> 00:10:50,780 And I'll delete the implementation for the savings. 187 00:10:52,780 --> 00:10:54,780 And then finally, we'll do the same for trust. 188 00:10:55,680 --> 00:10:58,380 So I'll get rid of that, and I'll get rid of this as well. 189 00:10:58,880 --> 00:11:02,980 Okay. So now we've got a much cleaner look -- let me scroll all the way up here. 190 00:11:02,980 --> 00:11:06,640 So all we have now is the account class with its virtual void withdraw, 191 00:11:06,640 --> 00:11:09,640 virtual destructor, checking with its virtual void withdraw, 192 00:11:10,190 --> 00:11:13,850 virtual destructor and so forth. So we're at a really clean place to start. 193 00:11:13,850 --> 00:11:17,450 So what do we do. Well, the first thing we want to do is we want to create 194 00:11:17,450 --> 00:11:20,450 that printable class interface. So let's do that. 195 00:11:20,450 --> 00:11:25,110 And of course, you would normally do this in .header files and .cpp files, 196 00:11:25,110 --> 00:11:29,470 but I'm going to do it all in one just so it's easier and I don't have to switch between files to 197 00:11:29,470 --> 00:11:30,970 be able to explain this. 198 00:11:31,220 --> 00:11:33,720 So let's do that. So we'll create a class called, 199 00:11:33,720 --> 00:11:37,520 let's just call it I printable. You can call it with or without that I, it's really up to you. 200 00:11:38,020 --> 00:11:39,270 So that's my class. 201 00:11:39,770 --> 00:11:41,370 And I'll close it off down here. 202 00:11:41,370 --> 00:11:45,270 Now what do I want in this class. Well, I need a, friend, right. I have to have a friend because 203 00:11:45,270 --> 00:11:49,270 the way that insertion operator works where the left side is the stream 204 00:11:49,270 --> 00:11:50,870 and the right side is the object. 205 00:11:50,870 --> 00:11:53,870 I really can't have member functions that do that kind of thing. 206 00:11:53,870 --> 00:11:58,170 So what I want to do is I want to have a friend function that's very similar to the ones we had before. 207 00:11:58,170 --> 00:12:01,970 So let's say friend, and it's going to return a std ostream 208 00:12:01,970 --> 00:12:02,970 by reference. 209 00:12:04,970 --> 00:12:07,470 We're going to overload the insertion operator. 210 00:12:08,470 --> 00:12:11,470 And the two parameters are the std ostream and 211 00:12:11,470 --> 00:12:13,960 the printable object, that's where things really change. 212 00:12:13,960 --> 00:12:15,960 So let's create the std ostream 213 00:12:17,160 --> 00:12:18,160 by reference 214 00:12:20,020 --> 00:12:22,680 and a const I printable object 215 00:12:23,180 --> 00:12:24,180 by reference. 216 00:12:27,680 --> 00:12:30,980 We could just call that obj or our right-hand side, whatever you like. 217 00:12:33,640 --> 00:12:35,640 So that's my function prototype. 218 00:12:36,440 --> 00:12:40,040 And now what we want is we want to have a public 219 00:12:41,140 --> 00:12:42,940 pure virtual function 220 00:12:42,940 --> 00:12:47,540 that all classes that conform to this interface must implement. 221 00:12:47,540 --> 00:12:52,200 That's the one that's going to allow them to put whatever they want on the stream, however they want. 222 00:12:52,200 --> 00:12:53,760 So in this case, it'll be virtual, 223 00:12:54,860 --> 00:12:58,220 let's say void, and we'll call it print, we can call it anything we like. 224 00:12:58,470 --> 00:13:00,670 And we're going to put stuff on an ostream. 225 00:13:03,660 --> 00:13:06,960 This should be const since we really don't want it modifying 226 00:13:06,960 --> 00:13:07,950 any objects. 227 00:13:07,950 --> 00:13:11,250 And here's the important piece that's a pure virtual function now. 228 00:13:12,550 --> 00:13:15,150 Okay. So now let's implement that friend function. 229 00:13:15,550 --> 00:13:19,050 I'll copy this so I don't have to type it all out again. 230 00:13:20,150 --> 00:13:24,510 And what we want this function to do is really pretty straightforward. 231 00:13:24,760 --> 00:13:28,760 All we want this function to do is do, let's say, obj, right. 232 00:13:28,760 --> 00:13:32,960 That's the object, and we want to print onto that stream. 233 00:13:33,160 --> 00:13:36,820 That's the virtual function that all of my concrete classes 234 00:13:36,820 --> 00:13:39,720 must implement, and then I just simply return the stream. 235 00:13:40,720 --> 00:13:44,620 That's it. Now notice what's happening here. This function gets called with a printable 236 00:13:44,620 --> 00:13:45,620 or an I printable. 237 00:13:46,720 --> 00:13:49,520 And it's going to call print on that object. So this will -- 238 00:13:49,520 --> 00:13:54,070 we're coming at it with a base class reference, right, if you will, because they're all going to be printable. 239 00:13:54,070 --> 00:13:57,570 And we're going to use dynamic polymorphism to match the appropriate one. 240 00:13:57,570 --> 00:14:00,870 So that's really all we need to do here. So that's a really, really simple 241 00:14:00,870 --> 00:14:02,170 class interface. 242 00:14:02,170 --> 00:14:05,530 We only need to do this with the account class because we've got a hierarchy here, 243 00:14:05,530 --> 00:14:09,030 but I'll show you another way to do it as well in a second. So we could say public 244 00:14:10,180 --> 00:14:11,180 I printable. 245 00:14:11,780 --> 00:14:16,380 So now we're saying that that account class conforms to this I printable protocol, 246 00:14:16,380 --> 00:14:19,980 which means that it must implement this guy right there, that virtual void function. 247 00:14:20,340 --> 00:14:23,340 So we can do that right here. We can say virtual 248 00:14:23,840 --> 00:14:26,200 void print, 249 00:14:27,200 --> 00:14:29,560 right. It expects a std ostream by reference. 250 00:14:32,460 --> 00:14:34,560 We can call it os, 251 00:14:35,330 --> 00:14:37,530 and it is a const method. 252 00:14:39,730 --> 00:14:44,610 And I want to override. I want to definitely put that in there so that the compiler can help me in case I messed up. 253 00:14:45,710 --> 00:14:49,210 That's it. And what do we do here, we just simply say os 254 00:14:51,410 --> 00:14:53,610 account, let's just say display. 255 00:14:56,410 --> 00:14:58,210 That's it. That's all we have to do. 256 00:14:58,210 --> 00:15:01,510 Now for all the other classes that are derived from this account class, 257 00:15:01,510 --> 00:15:04,870 what we need to do is implement that virtual function in them 258 00:15:05,370 --> 00:15:08,670 in whatever way makes sense to display a checking account. 259 00:15:08,670 --> 00:15:10,270 In this case, I'll just say checking, 260 00:15:11,070 --> 00:15:15,270 right. In this case, I'll just say savings. But again, whatever makes sense, 261 00:15:15,270 --> 00:15:20,150 you want to display interest rates whatever, whatever makes sense for a display of 262 00:15:20,810 --> 00:15:23,410 a savings account. And here we'll do the same thing 263 00:15:23,770 --> 00:15:25,670 with the trust account. 264 00:15:25,670 --> 00:15:28,030 Okay. That should do it. So now if we build and run, 265 00:15:28,930 --> 00:15:32,530 you can see that we got what we wanted, right. There's the two pointers. 266 00:15:32,530 --> 00:15:35,890 So p1 now points to an account. And I'm displaying accounts display. 267 00:15:36,250 --> 00:15:40,250 And p2 is pointing to a checking, and I'm getting checking display.That's pretty cool. 268 00:15:40,850 --> 00:15:44,510 Okay. And obviously these guys will still work too since they're -- it's doing static binding, 269 00:15:44,510 --> 00:15:47,410 so that's, that's easy. But here's the difference. 270 00:15:47,410 --> 00:15:51,010 Again, you might still be wondering, so far so what. Well, 271 00:15:51,010 --> 00:15:55,110 the difference here is that suppose we want to create a class called dog, 272 00:15:56,210 --> 00:15:59,210 and that dog class wants to be printable. 273 00:16:00,010 --> 00:16:03,010 So it is derived from printable. 274 00:16:03,010 --> 00:16:07,010 So all this dog class has to do is implement that interface. 275 00:16:07,010 --> 00:16:09,210 So let's do that right here. I'll say public, 276 00:16:10,210 --> 00:16:14,570 and the interface is right up here. I'll just copy this guy to save myself a little time because 277 00:16:14,570 --> 00:16:16,070 it's the same function. 278 00:16:17,950 --> 00:16:21,450 And how does the dog display itself. Well, maybe the dog says woof woof, 279 00:16:24,110 --> 00:16:28,410 simple as that. So now what I can do here is I can create a dog object, 280 00:16:31,210 --> 00:16:34,510 and I can do it dynamically, right. So I need to put a pointer in there. 281 00:16:36,210 --> 00:16:40,010 That's it. And now I can simply put that dog object on the stream. 282 00:16:40,010 --> 00:16:43,010 So I can cut and paste, I'll copy from here. 283 00:16:45,610 --> 00:16:48,210 And rather than p1 this time, it's dog. 284 00:16:48,570 --> 00:16:51,570 I'm de-referencing dog. And when I run now, 285 00:16:52,270 --> 00:16:55,270 there you can see woof woof right there. 286 00:16:55,670 --> 00:16:58,970 So that's pretty powerful. 287 00:16:59,330 --> 00:17:02,690 Okay. Last thing is we can take it a step further. What we can do is we can actually write a function, 288 00:17:03,190 --> 00:17:05,690 and I'll just copy it here so you can see what it would look like 289 00:17:05,990 --> 00:17:10,089 right here.This is just a regular c++ function, and it's called print. 290 00:17:10,490 --> 00:17:13,190 And what does it expect? It expects an i printable, 291 00:17:13,589 --> 00:17:18,190 so it'll take anything. It'll take a dog object, an account object, a savings account object 292 00:17:18,190 --> 00:17:19,550 because they're all printable. 293 00:17:20,450 --> 00:17:25,109 So again, we could pass all of those guys into there. So if let's say I'm right here in my dog, 294 00:17:25,109 --> 00:17:28,810 I could say print, and I can pass dog into it. 295 00:17:30,470 --> 00:17:34,150 And if I run that, I should see woof woof twice. And there you can see it right up here. 296 00:17:34,810 --> 00:17:37,030 You could do the same thing with the account objects. 297 00:17:37,030 --> 00:17:39,530 This is where this is different 298 00:17:39,530 --> 00:17:42,130 from just regular inheritance from a base class. 299 00:17:42,130 --> 00:17:45,430 In this case, I can use this printable across hierarchies, 300 00:17:45,430 --> 00:17:50,030 across anything I want. I can just say that whatever I'm creating is printable, 301 00:17:50,030 --> 00:17:54,030 overload that print pure virtual function, and I'm good to go I'm a printable. 302 00:17:54,390 --> 00:17:57,590 So remember, in this case dog is a printable, 303 00:17:57,590 --> 00:18:00,390 an account was a printable, a savings account was a printable, 304 00:18:00,390 --> 00:18:04,890 a savings account was also an account, this is a really good use case for it.