In this video, I'd like to implement a class template for an array class.
Now this is going to be a little bit more complicated than anything we've done before,
but I'm sure you'll be able to follow along if you've been following along with the course.
I'm in the section 20 workspace, and I'm in the ClassTemplate
Array project. Now I've started this a little bit already.
And the idea here is we'd like to create an array class.
Okay, not an array a raw array, and not a dynamic array,
just a class array.
And eventually, we want it to be of any size and of any type,
That'd be pretty cool. And we want this to be a fixed size array.
And basically, it would be a replacement for using a raw array.
C++ already has this for us. In c++11,
we have an array class in the standard template library,
and I'll talk about that in a couple of videos.
But let's see how we could implement the beginnings of that so we can really learn from it.
So we don't want to have an array of something, right.
Well, in this case, let's just stick to integers. And then later on what we'll do is we'll make this generic.
The array is a fixed size.
And that fixed size is n. And I've got this n right here. None of this will compile yet,
but i just want to get this point across here.
The question is how do we get this n.?
Well, the user knows how big the array needs to be. Let's say it's 10 integers or 20 integers
or 100 integers.
They could pass that in through a constructor argument, right.
The problem with that is that the compiler needs to know
what the value of n is
right here in order to create this array.
Now we're not doing something like using a pointer
and creating a new
array of integers, like we did before, we're not doing that.
That's not what I want to do. I want to create it on the stack.
So the compiler needs to know the value of that n.
And it can't know that if we pass it into a constructor argument because
it could be a variable, it could be any value.
So one of the first things we want to do is figure out how to do this.
So I want to be able to create an array class. And let me show you the way I want to do it.
I want to do something like this. I want to be able to say give me an array,
let's say it's arr.
Right now it's an array of integers by default you can see right here,
and I'll just do that. Now that's not good enough because there's no size information.
But if I can do something like that,
that's pretty cool. So I can pass in the size of the array
as a template parameter.
Well, how do we do that. Everything we've seen so far has been type parameters, right.
Well, it's possible to have non-type template parameters.
And let me show you how that works.
And basically what we're doing here is we just have a regular array class,
it's got a constructor, a default constructor,
it's got a constructor with an initial value.
So what we're doing here is just setting all the values of the array to that value.
I've got a method called fill, which will just change all those array elements
to whatever value is passed in here.
Then I've got a couple of more methods that I'll talk about in a little bit.
So first thing first. Let's make this array class
a template class.
So what we can do is we can come up here,
and we could say template.
And now we've got our template parameters here, right. Now what do we do here.
We're not passing in a type. We'll do that later when we make this a generic type.
But what we want here is the size of the array. So we can supply n right here.
Now when I use the syntax that I used earlier I've got my n. Now that's pretty cool.
So that's how we get the n. The user provides the n at compile time.
Now the compiler can actually create that array.
Now we've got a friend function here that's just used to display the array.
And in this case here, it needs to know what that n is.
So I'm just going to put an n right in here.
So it needs that template parameter. Now as I come down here,
none of this code really needs to be changed.
There might be a couple of new things that you haven't seen before.
This one here I don't know if we ever overloaded the subscript operator,
but we're doing it right here,
and it's the subscript operator, right, the 2 square brackets so that we can
use it as array indexing.
And all we're doing is returning a reference, so that we're able to change it as well.
So now let's go down to the main and see how we can actually use this.
And here's a couple of examples. Now
we'll write the rest of this in a little bit,
but take a look at how useful this array is.
Here I'm creating an array of 5
integers. These are all integers right now, right. I haven't made it generic yet.
But here I have an array of 5 integers,
and I can display what's the array size, it should display 5.
And then it'll display the the integers because because I've overloaded the insertion operator.
I can fill the array to 0s. I can fill it to 10s, and display it again.
And this is where the overloaded subscript operator comes in,
so I can specifically set. And remember, what's going to happen here
is it's going to call nums.
operator
subscript operator, and it's going to pass in 0 in this case.
So that's what's being called.
And I'm just setting those values in this case.
If this is on the left side, we're using the l-value. If it's on the right side, we'be using the r-value.
That's it.
And here in this case here, we're actually using an initializer,
we're initializing 100 integers, right.
So let's let me run this, so you can see the output.
And this
is all we did. And it's so powerful. All we really needed we did
was pass in that integer n as a non-type template parameter.
So you can see what's happening. Here I've got 5
integers and that array is called nums.
And notice when I display it, I get 5 pieces of garbage right here, right.
That's exactly what we'd expect.
Now here I'm filling it to 0, and then I'm displaying it again, and I'm getting this
output right here, all the bunch of 0s.
Then I'm filling it to 10s.
And you can see them display right here.
And then in this case, I'm setting nums of 0 to a 1000 and nums of 3 to 2000.
You can see right in this line when I display it. You can see that num of 0 is here,
and num sub 3 is right here.
Okay. So let me scroll just a little bit down. And
this last example, we're creating a 100
integers. Remember, they're all integers.
So we're creating 100 integers. This right here is that template parameter n.
This right up there when we created the top one was the template parameter n.
So in this case, we're creating an array of 100 integers.
It's a fixed size array. We're not doing any memory allocation.
It's happening on the stack, which is pretty cool.
The compilers handling the sizing,
and we're initializing all of those elements to one. We're displaying them all right here there's 100 of them.
Okay. So that's it. Now we've got a pretty powerful
little array class here that allow us to create
an array of any size but only of integers.
So let's take this to the next step and make it totally generic,
which is really where we want to go.
So let me close this window down up here.
And a couple of things, I'll scroll all the way to the top, so I can give you these little notes here.
Since c++11, the stl has been around before c++11.
But in c++11,
we have std array. And this is an array with a lowercase a here,
and I'll explain what that array is in a couple of videos
from now when we go over some of these container classes.
This is a template-based array class.
The idea here is in modern c++, we really shouldn't be using arrays,
raw arrays. We should be using std arrays and std vectors. Now
the the vector is great, right, but the vector can shrink, and it can grow,
and it varies in size depending on what you need,
that's one of the great things about the vector, you don't have to worry about that.
But sometimes you know exactly what you have.
You know that you have 10 integers, you have 20 integers or 5 strings.
And the vector might be overkill, and it could be a little less efficient.
In a case like that, you really want to use std array.
It's much more efficient. It's not going to shrink. It's not going to grow.
It's exactly that fixed size, and sometimes
that's exactly what we need.
If we've got 12 months in the year, that's not going to grow, right.
So it's a good example of using a std array.
Now let's make this template class generic.
So what do we have to do it's really all about this guy right here.
It's not about size. Size is always going to be an integer,
probably even better if we made that a size t-type since it's going to be an unsigned,
but we'll just leave it n for now.
Values is the one that's going to change. It's not just going to be integers.
It could be anything. So that's where we want to replace
our placeholder,right, our type name t.
So we'll do that right now.
So let's start right here in the template parameter right here, and we'll say type name.
And we can use t again. We can use anything we want.
Now that's going to be what's going to be replaced by whatever type the user wants,
right. So let's walk through this and make sure we get them all.
This is fine. This guy is going to be a t because now we've got
values is an array that's n size of t types.
Okay. Here we've got 2 template parameters so we need to
supply t,n.
And this is just my friend operator
that allows me to display these things on an output stream real easily.
So that should take care of that. Now let's take a look down here.
We've got the initial value that we want to set
the array elements to that can no longer be an int because it could be anything
so we want that to be a t.
Here the same idea, we want to fill the array with whatever
t's are provided to us. Remember, the t is just a plugable type,
could be an int, a double,a character or something more complicated.
Get size is okay. It's going to return an integer.
But this guy right here overloaded subscript operator
is not going to return an integer reference, it's going to return a reference to a t.
Okay. Now this won't compile any longer. Let me compile it just so you can see what's going on.
We're going to get errors right here,
why because look at our template definition right here. It's expecting
2 items. It's expecting a type,
and it's expecting an integer.
But right now, we're only providing the integer here.
So we need to provide the type. So we could say int comma and then the 5.
And now we've got exactly what we did before,
right. So let's try that again.
Same here.
We've got a 100 but let's try integers.
And we'll modify this to a different type in just a second. That's it. Now if I run this,
I've got a clean run.
It looks like I didn't do much, but there's a lot going on here.
Because in this case, the compiler is providing
2 template classes for me, right.
One is using integers with 5, and one is using integers with a 100.
So now what we can do is we can modify this.
Let's say we want to modify it so that we can hold
stood strings and not just integers. So we're going to create an array,
provide the type, which is going to be std string.
And how many do we want? Let's say we want 10 of them.
That's it. You can really see the power of templates here.
So now what do we do. Let's call this guy strings.
And
let's give it an initial value.
We'll call that constructor with the initial value. And what we'll do is we'll just say std string,
and we'll construct a string. Let's just call it Frank, makes it easy.
That's it. And then I'm going to just copy and paste this right here
and rename a few variables,
so that we know now that the size of strings now not nums.
That's my array right here that I just named
is strings.getsize,
and what we want to do is display it. That's it. Let's run this.
There it is. The size of strings is 10. And now I've got 10
std strings in there.
Pretty cool, right. I mean I didn't really do much. All I did was make this class generic.
That's awesome. Now suppose I want to change that first string,
right, the 0th index. So I could simply say strings
sub-0
equals,
and we'll create a std string. I can't use a character pointer literal right here
because the typing would be wrong. So I'm going to create a std string for, let's say, Larry.
And that is going to be put in for the 0th item,
and then I'll just display them again,
and we should be able to see that first
item in that strings array should not be Larry. So let me run that real quick.
And there it is. You can see it right there is Larry. That's pretty cool, right.
All right. Last thing is let's fill this array with some x's, let's say.
So we'll say strings.fill.
And again, I want to fill this with a std string
and let's just say x.
And we'll display it one more time.
Now we should see all x's when it displays. And there they are, right down here.
So that really finishes this video up in this little mini section about templates,
including function templates and class templates. You can see the power here, right.
It's so powerful. Now obviously --
let me scroll up real here. Obviously, you would never do this right here.
We're just doing this to learn.
If you need an array, use std array.
It's part of the stl. Everything's baked into it.
It supports algorithms and iterators and all kinds of good stuff that we'll talk about
soon. So again, if you need a fixed size
array in modern c++, use std array.
So the next video, we'll start talking about containers, iterators,
algorithms, and then we'll look at each one of the containers,
in other words, array, vector, lists, sets and maps and everything,
and we'll go through some examples for those.