1 00:00:05,370 --> 00:00:06,030 Hello everyone. 2 00:00:06,030 --> 00:00:12,450 In the last video we learned about UN scoped enumerations, that is enumerations whose enumerators are 3 00:00:12,450 --> 00:00:17,130 unqualified and they are visible throughout the scope in which the enumerator was declared. 4 00:00:17,640 --> 00:00:23,640 In this video, we'll learn about the other side of the coin scoped enumerations, that is, enumerations 5 00:00:23,640 --> 00:00:30,120 whose enumerators are qualified, and therefore they're only visible by using the scope resolution operator. 6 00:00:30,890 --> 00:00:36,680 This means that if we want to access an enumerations enumerators, we must specify which enumeration 7 00:00:36,680 --> 00:00:38,270 the enumerator belongs to. 8 00:00:39,110 --> 00:00:44,030 In place of the singular enum, a keyword used to declare a scoped enumerations. 9 00:00:44,180 --> 00:00:48,680 We declare scoped enumerations using the enum class key. 10 00:00:49,310 --> 00:00:53,780 We can also use enum struct and they are both semantically equivalent. 11 00:00:54,320 --> 00:00:57,800 So you're probably wondering why do we even need scoped enumerations? 12 00:00:58,100 --> 00:01:03,590 Well, you may remember me saying that scoped enumerations can sometimes cause issues that can only 13 00:01:03,590 --> 00:01:05,750 be resolved by using scoped enumerations. 14 00:01:05,750 --> 00:01:10,190 So let's take a look at two motivating examples so you can understand why. 15 00:01:12,430 --> 00:01:15,370 Here we can see two UN scoped enumerations. 16 00:01:15,820 --> 00:01:21,100 The first one contains species of whales and the other species of sharks. 17 00:01:21,430 --> 00:01:26,770 Now, suppose we want to determine whether a beluga whale is equivalent to a hammerhead shark. 18 00:01:27,930 --> 00:01:30,660 Because both enumerations are un scoped. 19 00:01:30,690 --> 00:01:37,260 This is a valid comparison and even worse it evaluate to true since both the numerators have the same 20 00:01:37,260 --> 00:01:38,910 underlying value of one. 21 00:01:39,300 --> 00:01:44,280 Obviously this is not what we want since a beluga whale is certainly not equivalent to a hammerhead 22 00:01:44,280 --> 00:01:44,910 shark. 23 00:01:45,650 --> 00:01:51,050 Another issue that can arise from the use of UN scoped enumerations are name clashes. 24 00:01:52,600 --> 00:01:57,100 Suppose that we want to include the blue shark species in our shark enumeration. 25 00:01:57,460 --> 00:02:03,250 You'll notice that it has the same enumerator name as the blue whale species because both enumerations 26 00:02:03,250 --> 00:02:04,180 are un scoped. 27 00:02:04,210 --> 00:02:09,190 The compiler will think we're trying to re declare the enumerator blue and it will generate an error. 28 00:02:10,000 --> 00:02:14,950 Of course, we could just rename the enumerator to something more specific, but in general, we don't 29 00:02:14,950 --> 00:02:17,530 want to have to worry about naming our enumerators. 30 00:02:17,740 --> 00:02:20,050 So what can we do to address this issue? 31 00:02:20,710 --> 00:02:25,270 As you've probably already guessed, we can declare the enumerations as scoped enumerations. 32 00:02:27,250 --> 00:02:33,550 The use of if and switch statements with scoped enumerations is identical to that of scoped, but with 33 00:02:33,550 --> 00:02:37,000 the additional requirement of specifying enumerator scopes. 34 00:02:37,480 --> 00:02:43,060 In fact, everything you can do with an scoped enumeration, you can do with a scoped enumeration so 35 00:02:43,060 --> 00:02:45,710 long as you specify the scope of its enumerators. 36 00:02:45,730 --> 00:02:49,330 With that said, there is one difference that's worth discussing. 37 00:02:51,700 --> 00:02:57,910 In this example, we have a scoped enumeration type named item that might be items in a grocery or shopping 38 00:02:57,910 --> 00:02:58,480 list. 39 00:02:58,840 --> 00:03:04,150 The underlying value of each item might be an item code or some other value that makes sense in our 40 00:03:04,150 --> 00:03:05,050 application. 41 00:03:05,880 --> 00:03:11,460 You'll remember that with un scoped enumerations if we wanted to use their enumerator values, we simply 42 00:03:11,460 --> 00:03:16,140 stated the name of the enumerator and the compiler would implicitly convert its value to its underlying 43 00:03:16,170 --> 00:03:16,710 type. 44 00:03:17,360 --> 00:03:18,800 With scoped enumerations. 45 00:03:18,800 --> 00:03:20,030 That's not possible. 46 00:03:20,570 --> 00:03:26,060 In fact, if we try to do so, even with specifying the numerator scope, the compiler will generate 47 00:03:26,060 --> 00:03:26,660 an error. 48 00:03:28,120 --> 00:03:33,430 This is because scoped enumeration type variables are not implicitly convertible. 49 00:03:33,760 --> 00:03:38,200 Instead, we must explicitly cast a variable to its underlying type. 50 00:03:39,080 --> 00:03:44,060 Here you can see that we can cast the numerator to the integer underlying type using a few different 51 00:03:44,060 --> 00:03:45,380 styles of casting. 52 00:03:46,040 --> 00:03:49,880 Only then can we use the value of a scoped enumeration type variable. 53 00:03:51,050 --> 00:03:55,880 Now that we've seen what stoked enumerations are and how to use them, let's head on over to the ID 54 00:03:55,880 --> 00:03:57,200 and see a few examples. 55 00:04:00,060 --> 00:04:00,420 Okay. 56 00:04:00,420 --> 00:04:02,030 So I'm in the i.t. 57 00:04:02,040 --> 00:04:07,650 I'm in the enumerations workspace and in the scoped in nums project. 58 00:04:08,100 --> 00:04:12,870 I'm going to close this workspace for you just to give myself a little bit more room here. 59 00:04:13,050 --> 00:04:18,750 All right, so what we've got here is this to test examples that show you different ways to use scoped 60 00:04:18,750 --> 00:04:19,709 enumerations. 61 00:04:19,709 --> 00:04:24,270 So I've got them both set up and I've already built and run the program. 62 00:04:24,270 --> 00:04:25,650 You can see it over here on the right. 63 00:04:25,650 --> 00:04:30,480 And what I want to do is go over those examples so you can see exactly what's happening. 64 00:04:30,750 --> 00:04:37,440 This first test is very, very similar to the same first test that we did in the scoped enumerations 65 00:04:37,440 --> 00:04:38,160 project. 66 00:04:38,280 --> 00:04:42,130 Here we've got our grocery item enumeration. 67 00:04:42,150 --> 00:04:47,830 I notice that this is now a scoped enumeration because we're using enum class here. 68 00:04:47,880 --> 00:04:50,760 I've got milk, bread, apple and orange, just like before. 69 00:04:51,510 --> 00:04:57,540 The difference is I've assigned some initialized values to these enumerators and this could represent 70 00:04:57,540 --> 00:05:03,180 the item code or really just about anything you can think of that could identify these the values for 71 00:05:03,180 --> 00:05:04,170 these enumerators. 72 00:05:04,440 --> 00:05:10,200 So in this case we are explicitly defining those values and the compiler will not generate zero, one, 73 00:05:10,200 --> 00:05:11,040 two and three. 74 00:05:11,460 --> 00:05:14,970 We're going to do exactly what we did before with maybe a little bit of a change. 75 00:05:15,120 --> 00:05:15,390 Okay. 76 00:05:15,420 --> 00:05:17,580 So look at some of the examples we've written here. 77 00:05:17,580 --> 00:05:22,170 Here we're overloading the insertion operator again, the stream insertion operator, just like we did 78 00:05:22,170 --> 00:05:22,800 before. 79 00:05:23,220 --> 00:05:29,310 The only real difference is that is that now in order to use those enumerators, we must scope them. 80 00:05:29,310 --> 00:05:35,550 We have to use the enumeration class name grocery item right before the enumerator value. 81 00:05:35,580 --> 00:05:37,860 Otherwise it's not going to compile. 82 00:05:37,860 --> 00:05:41,370 So that's one of the benefits of using scoped enumerators. 83 00:05:41,640 --> 00:05:46,680 The other thing we're going to do is in this case, I'm grabbing the underlying type of that grocery 84 00:05:46,680 --> 00:05:48,060 item value right here. 85 00:05:48,210 --> 00:05:50,070 So all I'm doing is displaying that. 86 00:05:50,070 --> 00:05:56,130 So when we display these values, we're going to display you can see up here, Apple 132, milk 350 87 00:05:56,130 --> 00:05:57,090 and so forth. 88 00:05:57,090 --> 00:06:00,540 What I do is I'm going to switch off the grocery item passed into me. 89 00:06:00,960 --> 00:06:06,780 I'm going to put whatever string is appropriate on the output stream, and then I'm just going to display 90 00:06:06,780 --> 00:06:09,450 the value right after that colon. 91 00:06:09,630 --> 00:06:12,540 And the value again is one of these guys. 92 00:06:12,600 --> 00:06:15,120 Those are the ones I'm grabbing from the underlying type. 93 00:06:15,330 --> 00:06:20,880 I've got the Boolean function again exactly like it was in the previous example with scoped. 94 00:06:20,910 --> 00:06:26,310 Except since it's a scoped enumeration, we need to qualify those enumerators. 95 00:06:26,310 --> 00:06:32,400 So in this case, whatever grocery item is passed into this function, if it's one of these four, then 96 00:06:32,400 --> 00:06:33,240 we know it's valid. 97 00:06:33,240 --> 00:06:36,000 Otherwise we'll return false because it's invalid. 98 00:06:36,180 --> 00:06:40,230 And then the display grocery list function that I wrote is exactly the same. 99 00:06:40,230 --> 00:06:45,630 Again, the whole point of this was to create an scoped version and a scoped version so you can see 100 00:06:45,630 --> 00:06:46,290 the difference. 101 00:06:46,290 --> 00:06:51,720 So in this case, we've got that stupid vector of grocery items just like we did before, and we're 102 00:06:51,720 --> 00:06:57,600 going to loop through that using the range based for loop right here on line 64 and just display them. 103 00:06:57,600 --> 00:06:58,740 So that's pretty simple. 104 00:06:58,740 --> 00:07:00,930 We'll keep track of what's valid and invalid. 105 00:07:00,930 --> 00:07:04,800 I went over this in more detail in the scoped video so you can check it out there. 106 00:07:04,830 --> 00:07:10,020 And then what we'll do is we will create some items and add them to the shopping list, right? 107 00:07:10,020 --> 00:07:11,850 So that's what test one is doing. 108 00:07:11,850 --> 00:07:14,040 And you could see what I'm doing right here. 109 00:07:14,040 --> 00:07:16,440 And let me grab my pen right here. 110 00:07:16,440 --> 00:07:19,320 We're simply displaying test one and that's done right up here. 111 00:07:19,320 --> 00:07:20,280 There's the output. 112 00:07:20,580 --> 00:07:26,370 I'm creating my shopping list and I'm adding not Apple, I'm adding grocery item Apple. 113 00:07:26,370 --> 00:07:27,510 We've got to scope it. 114 00:07:27,510 --> 00:07:33,570 So I'm adding apple milk and orange and I'm creating a helicopter integer with 1000 and I'm going to 115 00:07:33,570 --> 00:07:35,160 push that guy back in. 116 00:07:35,310 --> 00:07:37,980 Now, I can do that here because I'm casting. 117 00:07:37,980 --> 00:07:40,320 So remember, be very careful with casting. 118 00:07:40,320 --> 00:07:42,120 Make sure your cast makes sense. 119 00:07:42,120 --> 00:07:46,710 In this case, it doesn't make sense really, because I don't have a white item with a 1000 code. 120 00:07:46,860 --> 00:07:52,260 Notice that if I try to add helicopter here, I'll get a compiler error because this is an INT and it's 121 00:07:52,260 --> 00:07:53,970 doing a little bit of checking for me. 122 00:07:53,970 --> 00:07:59,520 The shopping list is expecting a grocery item, not an int here. 123 00:07:59,520 --> 00:08:04,620 I'm telling you, hey, I know what I'm doing, so do what I tell you to do. 124 00:08:04,620 --> 00:08:06,390 And that's not always a good thing. 125 00:08:07,080 --> 00:08:11,640 I'm doing the 350 item, which is the milk, so it's going to add that again. 126 00:08:11,940 --> 00:08:15,240 And when I'm done, I display the list and here's the list that displays. 127 00:08:15,240 --> 00:08:20,190 I get apple, I get milk, I get orange, I get that invalid item, which is this one right here. 128 00:08:21,070 --> 00:08:29,440 On my 93, I get milk again because I'm adding the item code 350 and we've got five total items, four 129 00:08:29,440 --> 00:08:31,000 valid, one invalid. 130 00:08:31,240 --> 00:08:32,020 So there you go. 131 00:08:32,020 --> 00:08:36,130 That's very, very similar to the example that I did in the scoped video. 132 00:08:36,340 --> 00:08:39,110 So now let's check this example. 133 00:08:39,130 --> 00:08:45,490 Test two for test two, I created a class just to show you how we can use these scoped enumerators or 134 00:08:45,490 --> 00:08:47,890 really scoped enumerators inside a class. 135 00:08:48,070 --> 00:08:49,810 So here's an example. 136 00:08:49,810 --> 00:08:55,600 I've got a class called Player and this would model a player in a video game or something like that 137 00:08:55,600 --> 00:09:01,390 where they've got a mode which is an attack, a defense or an idle right, their current mode in the 138 00:09:01,390 --> 00:09:06,670 game direction that they're facing north, south, east or west, and they've got a name. 139 00:09:06,670 --> 00:09:11,640 So you could see those attributes of the class right here down at the bottom right here between 129 140 00:09:11,640 --> 00:09:12,850 to 131. 141 00:09:12,850 --> 00:09:17,860 So again, you can see that the player has a name, it has a mode of attack or defense, whatever their 142 00:09:17,860 --> 00:09:21,580 their current mode is and the direction that they're facing in the game. 143 00:09:21,580 --> 00:09:27,220 So those are the attributes that if I scroll back up, we've got a constructor here just like we've 144 00:09:27,220 --> 00:09:28,570 done before, nothing new. 145 00:09:28,750 --> 00:09:33,370 We've got our getters and our setters for the name, the mode and the direction. 146 00:09:33,370 --> 00:09:36,430 So let's write a couple of utility functions. 147 00:09:36,430 --> 00:09:38,830 The first one gets me the player mode. 148 00:09:38,830 --> 00:09:43,660 So if I pass in not a player, but if I pass in a player mode. 149 00:09:44,470 --> 00:09:49,410 It's going to return attack defense or idol as a string. 150 00:09:49,420 --> 00:09:54,640 That'll be a really handy function that I can call whenever I need to display that, for example. 151 00:09:55,030 --> 00:09:58,970 I also have a function that's going to give me the player direction. 152 00:09:59,020 --> 00:10:00,640 It works exactly the same way. 153 00:10:00,670 --> 00:10:04,420 It expects a player's direction, not a player, just the player's direction. 154 00:10:04,420 --> 00:10:10,420 And it returns the stud string here, and it's going to return north, south, east or west, depending 155 00:10:10,420 --> 00:10:11,850 on that enumeration. 156 00:10:11,860 --> 00:10:14,710 Since it's a scoped enumeration, I need to qualify it. 157 00:10:14,710 --> 00:10:19,720 And then finally I've overloaded the stream insertion operator and this is where those functions that 158 00:10:19,720 --> 00:10:22,150 I just wrote will be called so drain insertion. 159 00:10:22,150 --> 00:10:28,180 Operator If we're passing in a player object by reference, in this case by const references as we're 160 00:10:28,180 --> 00:10:34,330 supposed to, this is simply going to display player name and then it's going to get the player's name, 161 00:10:34,660 --> 00:10:39,010 then player mode and it's going to get the player mode, that function we wrote and it's going to pass 162 00:10:39,010 --> 00:10:41,940 in the player's mode rather than the entire player. 163 00:10:41,950 --> 00:10:47,650 We don't need to pass in the entire player to display the mode and we're going to display player direction 164 00:10:47,650 --> 00:10:51,130 followed by get player direction and port direction. 165 00:10:51,820 --> 00:10:55,900 We'll put an inline at the end and we'll return OS and now we'll be able to use that. 166 00:10:55,900 --> 00:10:58,120 So in test two, you can see the test. 167 00:10:58,120 --> 00:10:59,770 It's really, really simple here. 168 00:10:59,770 --> 00:11:05,200 I'm creating three player objects right here on lines 190 to 192. 169 00:11:05,770 --> 00:11:07,150 The first one is P one. 170 00:11:07,180 --> 00:11:08,590 It's cloud strife. 171 00:11:09,270 --> 00:11:15,450 Its current player mode is attack and its current direction is facing north. 172 00:11:15,960 --> 00:11:19,680 And you can see how we're using those enumerators right here. 173 00:11:20,100 --> 00:11:23,370 Also, you can see that the way the scope works, right? 174 00:11:23,430 --> 00:11:29,100 It's not just mode attack, it's player mode attack, because that enumeration is defined in the player 175 00:11:29,100 --> 00:11:29,730 class. 176 00:11:29,730 --> 00:11:33,200 So it's defined publicly within the scope of the player class. 177 00:11:33,210 --> 00:11:38,850 So we need to create so we need to provide all the information that the compiler needs to do this. 178 00:11:38,850 --> 00:11:42,780 But look at the readability again, that's very readable, right? 179 00:11:42,810 --> 00:11:43,320 Player one. 180 00:11:43,320 --> 00:11:47,460 Player two is Tifa Lockhart in defense mode facing West. 181 00:11:47,460 --> 00:11:53,190 This is so much easier than having magic numbers again in there and the compiler is helping us out. 182 00:11:53,190 --> 00:11:54,540 It's checking for errors. 183 00:11:54,660 --> 00:12:00,630 So once I did find those three player objects, I can display them really simply by just putting those 184 00:12:00,630 --> 00:12:04,410 player objects right on the output stream here with the insertion operator. 185 00:12:04,410 --> 00:12:07,140 And this is what we're going to get as the output right there. 186 00:12:07,440 --> 00:12:14,100 Play your name, cloud strife, attack mode north, just like we did here, Tifa Lockhart, Defense 187 00:12:14,100 --> 00:12:18,510 West and Sephiroth Idle South. 188 00:12:18,510 --> 00:12:20,370 And you can see that display right there. 189 00:12:20,910 --> 00:12:24,210 Now, I didn't implement test three, which is the rocket launch example. 190 00:12:24,210 --> 00:12:26,040 I'll leave that to you as an exercise. 191 00:12:26,040 --> 00:12:30,870 That way you can translate it from an scoped to a scoped enumeration and play around with that and have 192 00:12:30,870 --> 00:12:31,500 some fun. 193 00:12:31,620 --> 00:12:37,650 So that covers enumerations, as you can see at their core, they're very, very simple. 194 00:12:37,650 --> 00:12:43,230 Using them involves a lot because we can use a lot of advanced features in C++. 195 00:12:43,230 --> 00:12:48,570 We can use them with all kinds of control structures, we can use them inside classes, we can overload 196 00:12:48,570 --> 00:12:51,390 operators, we can get underlying types. 197 00:12:51,660 --> 00:12:53,880 We can do all kinds of really cool stuff. 198 00:12:53,880 --> 00:12:56,460 The big benefits readability. 199 00:12:56,820 --> 00:13:00,240 Also, let the compiler help you find mistakes.