In this video, we'll learn a little bit more about the const qualifier
in the context of class methods.
We've already learned that we can create const variables, which can't be changed.
And we've also seen how we can pass references and pointers
into functions as const, and they can't be modified while in the function.
Well, in this video, we'll learn how to create const objects
and see what happens when we pass constant objects to methods that don't expect the const.
Using const correctly in parameters as well as method declarations
is the basis for const correctness in a program.
In this example, we're creating a const object named villain.
Now once villain is created,
we can't change any of its attributes, that's the whole idea with it being const.
So what happens if we call member methods on a const object.
Let's look at calling a setter method that changes the object.
Obviously, this can't be allowed since the object is declared as const.
And in fact, this produces a compiler error.
The compiler complains that you're passing a const object as this
to a method that could change it.
But what about the output statement.
In this case, I'm not modifying the const object.
I'm simply getting a copy of its name for display.
Well, this won't compile either. In fact you get the same error that you get when you called set name.
So what's up.
Well, the compiler assumes that the get name function could potentially change the object,
so it gives an error.
But we need a solution to this problem
since we would like to call the getter methods and other methods that are public
that don't modify the object.
Here's another example. Again, we defined the villain object and it's a constant
so it can't change.
Now we have a display player name function that expects a reference to a const object.
Again, we get a compiler error.
Here the problem is that when we call p.get name
in the display player name function
this pointer isn't expecting a const object,
so get name could potentially change the object.
The compiler is being very careful not to allow a const object
to lose its constness.
So what's the solution?
The solution is actually very simple.
We need to tell the compiler that specific methods will not modify the object.
And all we have to do is put the const modifier before the semicolon and the method prototype.
That's it.
Now the compiler will not only allow this method to be called on const objects,
it will also produce a compiler error if you try to modify any of the object
attributes in the method.
The idea of class methods having const qualifiers
is part of what's referred to as const correctness.
Const correctness can get pretty complicated,
but this video serves to give you a basic idea of what it is and how important it is.
Now you can see that the call to get name works just fine,
but the call to set name is still not allowed
since set name is not a const function.
Remember, since you're telling the compiler that get name is a const member function.
Then if you write code in the body of get name that modifies the object, you'll get a compiler error.
That's const correctness in action.
Let's go to the IDE and see this example in code.
Okay. So I'm in the ide, I'm in the section 13 workspace
in the ConstInClasses project.
And this is basically the player class. Again,
you can see we've got our private attributes, some public methods and so forth.
And this is the real method that we're interested in in this example right here.
It's a simple getter that returns the name.
So you can see get name is the name of the method.
It returns name which is a string, simple as that.
That's the one we're going to have to fix
so that we achieve cons correctness with this program.
So let me go down to and you can see I've got constructor
copy constructor all the normal stuff.
I'm going to comment this function out because we're going to use that one in a minute,
but this is what I've got so far. I've created a villain object
that is a player type
and it's constant. I've also created a hero, which is a player type.
Hero is not constant. So what does this mean.
This means that I cannot change any of villains attributes.
So here's a real simple way to tell that this actually works.
If I take that xp attribute, that's private
and just make it public for a minute
and then I come down here, again and I'm just going to say something really simple like villain
.xp is a 1000.
It should let me do that right because xp is public,
but it won't because villain is constant. So if i try to compile this,
I'll get an error right here. It says assignment of member player xp
in a read-only object,
makes a lot of sense.
That's actually a really good compiler error.
It's telling you that that object villain is read-only. You can't change any of it, right.
That's what that const right there does.
So let me undo what I just did here,
and I'll make xp private again.
Okay. So let's do a couple of things now.
Let's come down again to our main here,
and I'll remove that line right here. So we're right back to where we started. We've got the villain,
and we've got the hero.
Now obviously, I should never be allowed to change villain, right.
So doing something like villain.set name
to super villain
that should never be allowed.
Because if you look at the set name method up here,
it is actually changing that name attribute.
So if you try to compile this,
you would expect an error, and you do get an error.
And the the error message is saying passing const player.
That's what this is right here villain.
As this argument discards qualifier.
So what it's telling you is that you're passing this in as a constant,
but the class is not expecting a constant.
And it's going to be able to change it.
Now you'd get the same error if you call the get name function.
So let's try that on villain.
You may not -- this one may not seem so obvious as to why.
But let's say we did something like that.
I'll just put that in an output statement.
So we'll say something we can cout.
There we go, something like that.I'll comment this one out because we know that one's --
that one should never work right, ever. No even once we're const correct that should never be allowed.
But now we're here. So I'm saying villain get me your name.
That should work and you really think about it, right. Because it's not changing the object,
it's simply returning that string and display it. But it won't work.
It's going to give you an error. And the error is again same error,
passing const player as this argument discards qualifier.
So what's going on?
Well, that get name method
could change the object,
right. There's no reason. I couldn't write some code in the get method right here,
that changed one of those attributes.
And the compiler can't guarantee that at this point. So it's going to throw the error.
The fix will come up in a little bit.
But now what if I did
something like this.
What if I did the same output statement,
but I did it with hero instead of villain.
Let's compile that.
There you go. You get a clean run, right. That makes sense because hero is not const.
So the compiler doesn't really care if you change hero in that method or not.
Okay. So we'll make all this const correct in a little bit.
So there you can see some of the issues here.
Now suppose that I'm going to comment all this out, and then I'll uncomment it in a little bit.
But now suppose we have this function right here, this is not a member function,
it's just a regular function. It's called display player name,
and it expects p, which is a reference to a const player object,
right. And all we're doing is getting that that player object's name and displaying it.
So let's call that method.
So we'll call display player name,
and we'll pass in villain.
And what we'd expect it is to print out villain, right. So let's compile that.
We get an error. Error passing const player is this argument discards qualifier.
It's like the problem's right here, right there.
And okay. You know we can sort of understand that error.
But now let's try this with hero.
And we'll just replace villain with hero here,
and I'll comment this line out so
we're definitely sure what's causing any errors if we get any.
So look what's happening here. Hero is not a const, right.
So I'm going to pass hero into display player
as a const that means this function can't change it, right.
That's the problem.
When I call p.get name,
as far as p dot get name is concerned, that's a const.
It can't change it, right. But there's no way to guarantee that.
So this is going to give me the same error as before.
There's the error again.
Okay. So what's the fix? Well, the fix is pretty simple.
The fix is we come up here to our class,
and we come to that method get name.
And we want to tell the compiler hey compiler
I guarantee and you double check for me
that this method get name is not modifying the object at all.
You do that with the const qualifier right there.
You put a const right after the parameter list.
If you've just got a prototype, you just put it like right
before the prototype, right in there before the semicolon.
That's it. Now you've just told the compiler I guarantee
that I'm not changing that object in this method.
So now the compiler is happy, and all of this stuff will work now, right.
Let's uncomment all of these out.
And I'll uncomment this guy out as well because that should work as well.
And that's it. So now if we run this.We should get a clean run.
Villain hero, villain hero, just what we expect.
Obviously, this will never work, right.
That should never work because it's -- we don't want to set anything
in villain, which -- that should never be allowed. So I'll just leave that commented out.
And then the other thing that's important to understand is once you define
a method here is const,
you can't mess around with those attributes in here.
I can't say xp equals a 100
right because now it's -- you're just violating what
you just said you were going to do it's no longer const.
So if I compile, I'm going to get an error right there on that line,
right. You're changing something at a read-only object.
So this is const correctness. It can get pretty complicated
when you're passing things all over the place as
const here, non-const here and so forth.
But the rule of thumb is all your getters should be const.
Basically, any method that you have in your class
that doesn't modify the object should be const.
Okay. So that's it for the const correctness.