Tip:
Highlight text to annotate it
X
In this lesson we're going to look at accessor and mutator functions,
also known as setter and getter functions or set and get functions. In fact, I think that's what I call them the most: set and get functions.
So the idea is, every once in a while, you'll be writing code for class and you need direct access to the member variables somewhere where
you really don't have it. And you think, "Okay, I need to create a function that allows me to access or mutate a private member variable."
I either need to set a value or need to get a value. Hence the name set and get functions.
Well, you can create these functions and sometimes it's necessary.
However, you must understand that these functions are dangerous. You have to define them very carefully because they do create a direct
avenue to the private member variables. You might be thinking why not make them public in the first place and avoid that problem? That
goes against the whole concept of a class where you want put the data in the private section of the clash to protect it
from being modified the way it should not be modified. So, let's take a look at some motivation here. Suppose that we want to write a
nonmember function "mult_fracs", and it is nonmember, it's not scoped as a fraction
class function, called "mult_fracs", that returns a fraction and we pass two fractions to it. Notice that I've passed
constant reference, both of those. Why? Well again,
referenced because we want to avoid the overhead of copy, const because
we don't want the object that we send to this function to be changed. And how am I going to use this?
Well, it will be use something like this. F3 is going to be assigned
the return value of "mult_fracs", which is a fraction and it's going to be a product of the two fractions that I passed in. So what this is doing is
emulating this process. "f3 = f1 * f2” And you might be thinking, well why don't you simply just do that?
Well, I can't because this operator is not defined for faction objects. It's defined for the basic built in
types, but not for fractions. Go ahead and try to compile that. It won't. The compiler
will say, "I don't know how to do this for these kinds of objects". And I'm going to define then a function called "mult_fracs" that will do it.
Let's see what we need to do. If I'm going to return a fraction, I'm going to create a local object of type fraction called temp and then I'm going to
build that object, the way I want to build it. I will assign to temp's numerator the numerator of the left-hand-side
times the numerator of the right-hand-side. Now, that's OK right because
this multiplication that I'm doing is between two integers right? Left-hand-side numerator that's a fraction's numerator, that's an integer.
Right-hand-side's numerator, that's an integer. An integer times an integer is an integer and I'm going to assign that to temp's numerator which is
an integer, which is an integer and everything's fine, right?
No, it's not alright. Remember that the numerator member variable of the fraction class is
private and this is not a member function so I can't do this. I can't directly access
the member variables in this line of code. So, what am I going to do? I'm going to create accessor and mutator functions for my fraction
class. But, I'm gonna do it carefully. We've added some functions to the class. We've added "getNum", "getDen", "setNumer" and
"setDenom". So, this is going to return the numerator, this going to do return the denominator so those are accessor functions.
So, these are accessors or get functions and these are set functions or mutators. Now, let's think about this.
If I'm going to return the numerator and denominator, I'm simply extracting that information to be public and that seems like an
OK thing. So I call them "getNum" and they're going to return the ints. There's no real problem there. What about the set functions? We have to
ask ourselves, can the numerator of the fraction be anything?
The answer is yes. Negative, positive and zero.
What about the denominator? No. The denominator can be negative, it can be positive, but it cannot be 0. And so this is the
one function, right here, that's going to be defined a little bit differently and notice that I've made it a bool. Why I've done that
here in a minute or two. Let's first take a look at the "getNum" function.
Okay, here I have it defined in the associated cpp, the implementation file. Notice again that I have scoped it. It's a member function. And it is simply
going to return "m_numerator". What numerator? The calling object's numerator.
If f calls "getNum", what's that return? It returns f's numerator, not anybody else's, f's numerator. This is a very small function.
It's extremely small and it's no mystery. So we're going to do something a little bit different with that here in a minute along with the "getDen” function.
We're going to do what's called an inline. Now, the "getDen" function is defined, very similarly, and again
don't forget to scope it. Let's take a look at the "setNumer", again scoped, don't forget the scoping.
I'm going to pass in an integer and that value is going to be assigned to the numerator. It's a very simple
definition. Now, what about the "setDenom" function? That's a bit different. I don't want to define this function to set the denominator to be
anything that's passed in. What I'm going to is I'm going to return a bool, true or false. True if it's set, false
if it's not set. Under what condition is it not going to be set? Well, let's take a look.
I'm going to default my set, that's a temporary, local variable of type bool. I'm going to default that to false and return set.
Okay, but if the denominator is not zero, I'm going to set 'set' to true,
I'm going to assign the passed value to the denominator and then again return set. If the parameter is non-zero then I'll set the
denominator to it and return true. If the parameter has been passed a zero value, then I'm simply not going to set the value and return false.
Again, let's look at what I mean by inlining. Okay, this is a small function; I'm going to put the definition of that "getNum" function
right there in the definition of the class. I'm going to bring that down
right into there and then get rid of this part. I can't have both. I can't have the definition here inline and the definition back in the cpp. If
you do that; the compiler will complain that it's got too many definitions. So, you have to have it one way or the other. And likewise,
I'm going to put the definition of the "getDen" right down there. Okay, now let's take a look at "mult_fracs" function again. What happens when
we do the following line of code? I'm going to have temp call its "setNumer" function
and the "getNumer" function and the "getNumer" function. That way I can access those variables
correctly. Alright, now what about setting the denominator? I could use it this way. I could do something like "if (!
temp set.Denom". So, what's happening here? This, the set denominator,
returns a bool, right? It is either true or false. So, if this returns false, meaning I've tried somehow to set the denominator
to zero, then I can output a message, an error message, and exit. I'm out on the program.
Now, you must understand this is one way to handle this situation. There are many different ways to do it. The best way
would be using what are called exception handling techniques,
but we don't teach that in this course. So, this is our best option I think at this point.
And that's the end of the session on set and get functions.
Remember one thing: just because you have a private member variable does not mean that you should have a set or get function for it.