Placeholder Image

Subtitles section Play video

  • Hello.

  • In this video, I'm going to have a brief look.

  • Att OPERATOR Overloading and show you how you can use it to simplify your programs.

  • Now, in many of my videos about graphics and physics, the first thing I usually do is create some sort of structure that represents a to D point.

  • So in this case factor floating point to D on, I would give it to member variables Float X, and I'll initialize it and float.

  • Why?

  • And I'll initialize that, too.

  • And somewhere in my main program, I'll create some of these vectors.

  • So let's take Victor a here, and I'll initialize that to 1.0 on dhe 2.5, for example, on Dhe, really, I work with just one vector.

  • We may have a bunch of them, so I'll create A B and C.

  • And when I want to operate on these directors, I would do it on a component by component basis.

  • So a dot X equals b dot x plus seed attacks on whatever you do for X, you typically want to do for white.

  • So in this case, I'm adding the two factors together.

  • I could also do it using initialize the lists.

  • I could say a equals b dot x plus c dot x comma be dot war II plus C Don't why, and that would be equally valid.

  • And so far, my programs have been simply enough that this is a completely fine way to do things.

  • However, with working on the top down city based car crime game, I'm doing a lot of things using physics and to de vectors, and after a while it gets a little cumbersome to keep splitting of the code into two lines.

  • I also mentioned in my coat yourself feed the engine Siri's that one day I'll do a video about operator overloading to simplify the nature of the back to type.

  • And so here it is.

  • And what do I mean by simplifying?

  • Well, surely it would be much more convenience to just write a equals.

  • B Plus C on the system knows how to go on Adam.

  • You can see it gives you a little red wiggly here because it doesn't know how to out these two types of the moment.

  • So let's make a basic two D vector type that, to all intents and purposes, can be treated like any other basic primitive in the program.

  • Firstly, the only two members I want my type to contain are the X and Y variables, and I want everything within this type to remain public.

  • So I'm just going to keep it as a structure lets out a simple constructor to start with, and I'm going to use member initialization syntax.

  • I don't really need a body for my constructor, but I've got to include the brackets anyway.

  • I've got to constructed for initializing the struck.

  • Let's also add a default constructor.

  • I'll do exactly the same.

  • Except this time I'm going to pass in the values zero zero again, an empty body.

  • And simply because I want to show various interesting things in this video, I'm also going to add a copy constructor, which takes a reference to an object of the same type and constructs with it again, an empty body.

  • Since we're creating a vector type, it may also be useful to include some utility functions normally associated with vectors, for example, getting the magnitude or the length of the vector, which is simply the high Potter news.

  • I never know why video studio doesn't put spaces there another common thing to do if actors is to normalize them.

  • So create a function called norm, which returns anew.

  • Vector, which is the normalized form of this vector.

  • It becomes the unit vector.

  • So first we want to create a temporal variable cold Oh, which is the inverse of the magnitude.

  • And I'm going to construct a new vector where I multiply the components by our and that will give me the normal the third year sole function, maybe to get the perpendicular you something at 90 degrees to this factor.

  • Well, that's easy enough.

  • I'm just going to create a new vector and swizzle the components around.

  • So far, we got nothing out of the ordinary.

  • We've just added utility functions to a stroke, But how do we make it behave like a primitive?

  • It's time to start overloading some operators.

  • I think the first operator I'm going to add is going to be simply addition Aunt.

  • To specify the overriding an operator we need to use the operator keyword and then the symbol that we wish to override.

  • Now I find to the syntax of operator overloading little bit clumsy, but it say it does make sense once you get used to it.

  • And the intention of this addition, if we will take what's on the right hand side and add it to the left hand side and will assume that this particular stroked is on the left hand side and so will pass into this operator overload the right hand side or at least a reference to it.

  • All right, Jess.

  • Right inside.

  • Now we don't want to in any way modify this structure.

  • Simply adding two vectors together shouldn't change either of those vectors.

  • It produces a new vector.

  • So I'm going to return a new object.

  • I'm going to construct it with a mechanism that facilitates this addition.

  • I'm going to use this key word, which is a pointer to this particular struck.

  • We stick its experiments, and I'm going to add it to the right hand sides experimenter.

  • And, of course, do exactly the same for the why it goes without saying that the other basic operators are exactly the same, so subtraction.

  • We just need to change the mathematical operator used in the constructor.

  • Multiplication and division don't really make much sense to do a similar pattern.

  • Instead, what we want to do is is passing a floating point scaler.

  • So change this to float right and so I can stay the same.

  • But this time we're just multiplying this structure's X and Y coordinates by the scale of values.

  • We'll do exactly the same for Divide.

  • So there we have the basic operators.

  • Let's try the mouth we can see on this third line.

  • The compiler no longer has an issue with it.

  • The red wig Lee has gone, but let's see if it actually works.

  • We'll change these values to something different just so we could follow along.

  • Let's run the D bugger to this line.

  • I'll zoom in here and we can clearly see the De Burger is quite happy representing our vectors.

  • So I just perform the addition when we can see that the values have changed appropriately.

  • III, in this one little operation, we've performed additional code.

  • I know that I'm using the constant e word and this is used to reinforce the point that the right hand side should not be in any way modified.

  • So if you do try to modify it, the compiler will catch it for you.

  • But what if we wanted to self modify the vector.

  • So something like a plus equals B.

  • We've got that little red wiggly back.

  • We've not defined what happens for this operation.

  • Let's consider what happened when we did just the regular edition.

  • The addition operator was identified, and so we performed the calculation.

  • We had dot exe and dot exe dot Why plus dot why?

  • And we created a new object using that result, let's just call that D.

  • We then returned D, which was copied into the location of A.

  • However, this time we want to directly change the values of a based on whatever is going on on the right hand side.

  • Effectively want X plus equals be dot Exe and why plus equals bead up.

  • Roy, I know that this time we're not copying anything over to a, However, we do want to return something just in case.

  • The result of all of this, it's used in some other equation, for example, C minus all of that.

  • So when the operator insists that we're going to modify the structure itself, we don't really want to move things around.

  • If we can help it so goingto work with references, operate a keyword plus equals is the operator.

  • Overriding the right hand side is the same as the previous edition and will perform the operation manually.

  • But we're going to use this key word again just to make sure we know what we're operating on.

  • So this objects X value Plus equals the right hand side dot x value on the same for why, but I want to return a reference to this object, just in case it's used by other things.

  • I don't want to return a pointer to this object, so I'm going to grab the value off it.

  • Now we can see the compiler is quite happy with that.

  • Syntax, multiplication and division are similar, but again, we can't multiply two vectors sensibly, so I'm going to change it to a scale of value.

  • Instead, we'll just do the same for devoid.

  • Very nice.

  • So now we've got the facility to do quite complicated operations, and we can see here.

  • The compilers flagged a little error.

  • We put our curse over it.

  • No operator divide matches thes two operas, and it's basically saying I can't divide one vector by another because it doesn't make any sense because A is a vector on the result of this results.

  • In a vector, its flagging.

  • That is an error.

  • So let's just turn this bottom one into something can work with, which would be a scaler value.

  • Let's take the magnitude of it.

  • The compiler is quite happy, so we've now got quite a sophisticated operation on a type we've defined ourselves, but we can handle it as humans like normal mathematics.

  • I'm going to add in two more utility functions, which are quite useful for factors.

  • The first is to get the duck product between two factors.

  • This isn't an operator overload put, it's just really useful.

  • I'm also going to throw in the cross product between the two factors.

  • Now, these air to de vectors So cross product doesn't really make a great deal of sense in this regard.

  • Other than giving you an indication off something in a hypothetical zed access we can see that are simple to element.

  • Vector class is now becoming quite a sophisticated thing.

  • Now this is a simple, quick video about operator overloading on.

  • There's one more type of operator overloading the satellite to show, and it's the embrace subscript operator.

  • Now, before you all right in with letters of complaint.

  • I'm fully aware of what I'm about to show is really about practice and probably has all sorts of technical problems and issues.

  • The array subscript operator is exactly what you think it is.

  • It's the square brackets.

  • After a variable, we're usually passive sub sort of index.

  • And in the case of my simple stroked if I pass in a zero, I wanted to return the X, and if I pass in a one, I wanted to return the Y components of the vector.

  • Either way, the race subscript operator overload is going to return.

  • The float is going to return a reference to a float, and I'll explain why in a minute.

  • So use the operator keyword.

  • Tell it which symbol we want to overload, and in this instance, I'm just going to use a simple numeric index size T.

  • Of course, it needn't be a simple numeric index.

  • It could be anything you want now.

  • I could check explicitly here.

  • If I equals zero, then return X.

  • If I equals one, then return why?

  • But where's the fun in that?

  • Instead, what I'm going to do is knowing that my struck is a simple, plain old data type with just two members X and y so in memory.

  • It'll just be those two floating point values.

  • If I take this pointer because I know that that's where the start of my structure resides in memory.

  • And I cast that pointer to a pointer to a floating point number.

  • Assuming, of course, that the ex is the first element in the memory of this structure, Then I can use some simple point arithmetic to access the right value.

  • Of course, right now this is all a pointer.

  • So I want to actually return the value.

  • And if you're not well upon your pointers, do check out might what are points his video now?

  • It was important that we returned the reference simply because if we didn't have the reference, we wouldn't be able to write anything to the array because the reference is the data at that location.

  • And we want to change that by writing to it.

  • In this case, we're writing and eight to it.

  • We didn't make that a reference.

  • You see, we can't compile it.

  • It won't allow us to write to that location, but we can happily read from it.

  • There's a lot to our simple type now, so let me just take a minute to tidy up the code.

  • Very nice.

  • A completely custom data type now Philly Show wanted to have You will have the following consent.

  • But, Jerry, the 32 bit floating point number is completely insufficient for my calculations.

  • I need a full 64 bits of numerical precision have described in the specifications laid out in IEEE 754 ratified in 2000 and eight.

  • Well, don't worry.

  • Whilst that's incredibly nerdy, it is a completely valid point here we are entirely restricted to single precision floating point numbers.

  • What do we do if we do want fundamentally a different type?

  • Well, one obvious answer is to copy and paste the whole thing and change anywhere where we have a float to the type that you need.

  • But this isn't very elegant way to do things and c++ in fact, providers with a tool to do just this templates.

  • And I'm only going to very briefly scared of air on the topic of 10 plates.

  • 10 plates could get very complicated very quickly, and I'm just going to show a very simple use case.

  • For now, the way I'm about to use template is effectively just fancy.

  • Couldn't paste for the compiler using the template keyword.

  • I can specify a particular variable t and it is through this variable t that the user will specify the underlying type used in the class.

  • So, anywhere we've got float, we no want to change that to t The current name of the struck VF two d implies that we're using a 32 bit float.

  • So I'm going to change this to something more generic and naturally, wherever we were referring to VF two D, Now we want to refer to this generic name.

  • So there we go.

  • And yes, I'm fully aware I can change lots of things simultaneously using clever search and replace options.

  • But it's more interesting visually to do it like that.

  • And this is a video after all.

  • So how do I use this template?

  • We can see the compiler is no longer very happy.

  • Well, one option is to use the numeric name on pass along the underlying type that we wish to use.

  • So in this case, this is the same as it was before these are floating point types we can see.

  • It's all very happy.

  • I can change these floats two doubles and again, Justus happy, but fundamentally the underlying data type of our X and a Y on all of the calculations that are performed upon them happening using a different primitive type.

  • We could even use interviews and short.

  • But we have to be careful in that case about what things start to mean.

  • For example, normalizing and interject vector probably doesn't make very much sense.

  • Also, this is now a bit of a mouthful every time we want to create an instance of our vector type.

  • So I'm going to create some convenient shorthand types using type death one for float, which will go back to our original name, VF two D and one for double.

  • We'll call up V Dy two d.

  • It's all of these now.

  • I could go back to how they were, and so they have it, a custom vector type that behaves like a primitive because we've used operator overloading to make it more convenient to use on.

  • We can also use it with different fundamental types.

  • It is both useful and pretty, very much unlike me.

  • In fact, I like this so much I'm going to include it directly into the pixel game Engine Head of file.

  • I'll put the source code for this video in the getup and linked to it below in the description.

  • If you've enjoyed it, give me a big thumbs up.

  • Have a think about subscribing and come and have a chat on the discord on until next time.

  • Take care.

Hello.

Subtitles and vocabulary

Click the word to look it up Click the word to find further inforamtion about it