Sign in to follow this  
glyvin

Accessor Methods

Recommended Posts

Hey Im having problem with Accessor methods and how to use them. I know that I need them to access variables that are set to private in the class but ok well hers my code.
#include <iostream.h>
#include <stdlib.h>
class cat
{
public:
//accessors
unsigned int GetAge();
void SetAge(unsigned int Age);

unsigned int GetWeight();
void SetWeight(unsigned int Weight);

//Member function

Meow();

//private members
private:
unsigned int itsAge;
unsigned int itsWeight;
};

ok so what does unsigned int getage() do and getweight() do. to change the age would we not declare a cat then do something like cat frisky; frisky.setage(5); ok I semi understand how this works but the line above that, whats the point of it ? Thanks for any help, Will

Share this post


Link to post
Share on other sites
Accessor methods are used to recover the values of some property of the object. In some cases it's just returning the value of a field, in other cases it would be more complex.

In your case, GetAge() probably looks like:

unsigned int cat::GetAge()
{
return itsAge;
}


If you look at the definition you provided for the cat class, itsAge and itsWeight are both private. So you can never access their values (for example, lets say you needed to compare the age of two different cats) unless you go through an accessor method.

They are, generally, a form of encapsulation, although they're somewhat redundant in such a trivial example.

Other points to note:
Accessor methods should usually be const, e.g., "unsigned int GetAge() const" so that they can be called on const objects (const cat).
Also, you should change your includes to #include <iostream> and #include <cstdlib> -- the forms you have are deprecated backwards-compatibility headers that should not be used in new C++ code.
Your declaration of Meow() is illegal, C++ does not support default-int, you need to specify a return type.

I'm gonna take a guess and say you're using Dev-C++, which is a terrible, broken, outdated tool. You should upgrade to Visual C++ Express, which is free and vastly superior to Dev-C++.

Share this post


Link to post
Share on other sites
That code's a mess. So first, a little tidy with comments.

#include <iostream>
#include <cstdlib>
/* No '.h' -- that went out with the ratification of the standard almost a
decade ago. Also, you want 'cstdlib' not 'stdlib.h'. */


class cat
{
/* Class visibility defaults to 'private' so if we move it here, no need to
manually declare them private. Although, this is stylistic. Also, I
dislike prepending the private members with 'its'. This is for two
reasons. Firstly, this interferes with a common abbreviation for
iterators and so might be considered confusing -- although this is
fairly unimportant. However, a 'cat' has an 'Age' and a 'Weight'. It
doesn't have an 'itsAge' or an 'itsWeight'. These distinctions are
unnecessary. If you need to disambiguate at some point, just use the
'this' pointer. Also, I removed the leading uppercase letter -- this
is absolutely stylistic, so feel free to stick to what you like. I
prefer lower case first letters for private members, upper case for
public. */

unsigned int age;
unsigned int weight;

public:
/* You'll see I've changed the return type of SetAge to a pointer-to-cat.
This is again stylistic, but it is idiomatic in that it allows for
method chaining, which allows you to do something like:
cat pussInBoots;
pussInBoots.SetAge(5).SetAge(6).SetAge(7);
// pussInBoots.GetAge() == 7;
*/

//accessors
unsigned int GetAge();
cat& SetAge(unsigned int Age);

unsigned int GetWeight();
cat& SetWeight(unsigned int Weight);

/* This might well be a member function -- but it won't compile. It has no
defined return type and C++ does not support default-int. You must
specify a return type. The only time you will see a function without
one is if it's a constructor or destructor for a class -- in which case
the function name will be the same as the class name. As a result, I've
changed the return type to 'void'. */

//Member function
void Meow();
};







Now to address your question.

Accessor methods are something of a design point in terms of whether or not you should include them. They provide a degree of extra encapsulation -- but it's worth considering whether this need for encapsulation might be avoided with a redesign -- in that if you need to change how the members are accessed, you have only a single point to do so rather than having to muck about with spaghetti code all over the place.

As for what they actually do, here's a naive implementation for the two functions (well, one pair of the four since the two pairs are virtually identical) you asked about:


unsigned int cat::GetAge()
{
return age;
}

cat& cat::SetAge(unsigned int Age)
{
/* This is part of why I like having lowercase for private, uppercase for
public. It's a simple thing, but the fact that C++ is case-sensitive
means that I don't have to do
this->Age = Age;
and yet I still avoid having the ugly 'its' on the member names. */

age = Age;

return *this; // For method chaining, remember?
}






As you can see, it's not complicated -- the idea is that you simply return the private member through the function, and set the private member through another function. Of course, another option is to avoid having explicit 'get' and 'set' methods and simply have a function named, e.g., Age which is overloaded -- one taking an argument, one not -- to return or set the member as necessary.

I mentioned above that the reason for (maybe) having accessors like this is encapsulation. It means that, for example, you might decide that no cat is older than 20 years (animal lovers feel free to jump in -- is this reasonable?):


cat& cat::SetAge(unsigned int Age)
{
#ifdef __DEBUG__
assert(age <= 20);
#endif

if (age > 20)
{
std::cerr << "Very old cat created!";
throw std::exception(); // Or something like that...
}

age = Age;

return *this;
}






EDIT: This took quite a time to type, and jpetrie managed to put it much more succinctly. ;-)
EDIT2: Silly mistake
EDIT3: Changed pointers to references -- wasn't thinking straight. Thanks to jpetrie.
EDIT3: Follow-up to EDIT3.

[Edited by - TheUnbeliever on May 9, 2007 9:36:50 AM]

Share this post


Link to post
Share on other sites
I would contest your suggestion that returning "this" out of manipulator (SetX) methods is "idiomatic." The chainability idiom generally involves only the bitshift operators when overloading for stream insertion/extraction, and a handful of other operators. The chaining of function calls in the sense allowed by your proposal isn't really idiomatic in C++, it's just a style decision.

And why not return a reference?

Share this post


Link to post
Share on other sites
thanks man I really appreciate your post C++ is a pretty complicated language and I am just having some in general problems with it. I am using the teach yourself C++ in 21 days book and its like cutting your way through a jungle, slow and painful lol. I am starting to understand classes but it will take me alot more reading and experimenting before I am to the point were I am truely comfortable with them.

Thanks for taking the time to write that tho, I will prob read it 4 - 5 times so I understand everything your saying :)

Will

Share this post


Link to post
Share on other sites
Quote:
Original post by jpetrie
I would contest your suggestion that returning "this" out of manipulator (SetX) methods is "idiomatic." The chainability idiom generally involves only the bitshift operators when overloading for stream insertion/extraction, and a handful of other operators. The chaining of function calls in the sense allowed by your proposal isn't really idiomatic in C++, it's just a style decision.


Fair dues. Perhaps it was a little over-the-top. I've come across it a few times (and certainly find it useful) but haven't read a large enough breadth of C++ source to claim what is idiomatic and not.

On the other hand, if he took the other 'option' that I mentioned, and rather had something like


class foo
{
int littleBar;
int bigBar;

public:
foo(int LittleBar, int BigBar) : littleBar(LittleBar), bigBar(BigBar) { }

int LittleBar()
{ return littleBar; }

foo& LittleBar(int LittleBar)
{
littleBar = LittleBar;

return *this;
}

int BigBar()
{ return bigBar; }

foo& BigBar(int BigBar)
{
bigBar = BigBar;

return *this;
}
}


Then that would allow for something slightly more idiomatic in that it would be similar to what I vaguely recall being referred to as the 'named parameter idiom' in the Parashift C++ FAQ (linked for OP -- it's a worthwhile read), kind of like:

foo someFoo(1, 2);
someFoo.LittleBar(3).BigBar(4);


Albeit, looking at the FAQ just now, it really isn't all that similar (and I'm not even entirely certain that the above code will compile; I think the parameters will shadow the functions if they've got the same name, but I'm not totally certain). Perhaps I should just concede defeat.

Quote:
And why not return a reference?


Oops. I meant to, and didn't. No excuse there.

Essentially: well intentioned but a little blundering.

EDIT: Addition.

[Edited by - TheUnbeliever on May 9, 2007 10:51:08 AM]

Share this post


Link to post
Share on other sites
so I am starting to understand but in my C++ book it says

"a member function def begins with the name of the class, followed by two colons ,the name of the function, and its parameters."

So why do yo have things like int cat and void cat, im just still having a little trouble, your explaination was almost a little over the top for me

Thanks

Will



EDIT!!!!!!!!!!!!!!!


Ok to make some of my questions clearer here is my finished code for this program I know some of my things are messed up with the .h but im trying to understand some basic coding principals before I go onto caring about that kinda stuff so here we go



#include <iostream.h>
#include <stdlib.h>

class Cat
{
public:
int GetAge(); //Accessor Function
void SetAge (int age); //Accessor Function
void Meow();

private:
int itsAge;
};
//GetAge, Public accessor function
//returns value of itsAge Memeber
int Cat::GetAge()
{
return itsAge;
}
//Definition of setage, public
//accessor function
//sets itsage member
void Cat::SetAge(int age)
{
//Set member Variable itsAge to
//Value passed in by parameter age
itsAge=age;
}

//Definition of meow method
//returns:void
//Parameters: NONE
//action : Prints "meow" to the screen

void Cat::Meow()
{
cout << "Meow.\n";
}

//create a cat, set its age , have it
// meow, tell us its age, then meow again





int main()
{
Cat Jet;
Jet.SetAge(5);
Jet.Meow();
cout << "Jet is a cat who is " ;
cout << Jet.GetAge() << " years old.\n";
Jet.Meow();
system("PAUSE");
return 0;
}



Ok so I still need the question aboved answered + how do you know when to use int and void, do you use int when you have a value being returned, and void for setage becuase its just setting the age and not returning a actual value?

Thanks

Will


[Edited by - glyvin on May 10, 2007 10:57:23 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by glyvin
Ok so I still need the question aboved answered + how do you know when to use int and void, do you use int when you have a value being returned, and void for setage because its just setting the age and not returning a actual value?


First bold: Yes, if the value being returned is of type int.
Second bold: Also correct.

The "type" of a function tells the compiler what type the function should be returning. A bool function should either be returning true or false, int functions should be returning an integer value, etc. If it simply modifies data and doesn't spit out anything of it's own, it's a void. This is why you see two basic types of main() functions:


int main()
{
//code
return 0;
}





and


void main()
{
//code
//no "return" endpiece
}



Share this post


Link to post
Share on other sites
Quote:
Original post by TheUnbeliever
... // For method chaining, remember? ...

Like in
int cat_age = cat().setAge(10).setAge(20).getAge()

I'd sum up that in three little words: "Thou", "are" and "fired".

Of course, this is a simple example. But allowing this kind of code in a complex project is likely to result in a Royal Mess, something I would not maintain - even if I'm paid to do it.

First, you have no way to tell (from the client side) if you are manipulating the same object or another one (a copy?). Second, it triggers my "Law of Demeter" spider sense (I care a lot about the Law of Demeter; I don't apply it to its extremity, but it really helps to build clean code. Method chaining simply breaks this rule of style).

Quote:
Original post by BCullis
This is why you see two basic types of main() functions:
int main() ...
void main() ...

void main() doesn't exist. The C++ standard explicitly says that main() should return an int. Some compiler supports this as an extension, but that doesn't mean that it's valid code (and it isn't, as far as the standard is concerned). It also says that if there is no return statement at the end of the function, a return 0 is assumed.

Quote:
Original post by glyvin
how do you know when to use int and void, do you use int when you have a value being returned, and void for setage becuase its just setting the age and not returning a actual value?

The (simplified) prototype for a C++ function is
RETURN_TYPE function_name(ARG_TYPE_1 arg1, ..., ARG_TYPE_N argN)
{
...
}

It means that the function "function_name" is expected to return a value of type RETURN_TYPE (be it int, char, float, a class or whatever you want, as long as it's a type). The function must contain a "return" statement in order to return the value (main() being the only exception, see the previous paragraph). "void" is a special RETURN_TYPE which says "I don't need to return anything". As a consequence, while you can still have a return statement in the function, you are not allowed to return a value (so the "return" statement is only used to exit the function before it reaches the end. This is not really a good practice, so I'd suggest you to avoid it).

A simple example of a function that returns a value: the addition() function:
int addition(int a, int b)
{
int result;

result = a + b;

return result;
}
// usage:
int result = addition(4,5); // puts 4 + 5 into result

For a class function (a method), this is largely similar, except that your have to tell the compiler to which class the function belongs to:
RETURN_TYPE CLASS_NAME::function_name(ARG_TYPE_1 arg1, ..., ARG_TYPE_N argN)
{
...
}

This is what your book says: "a member function def begins with the name of the class, followed by two colons ,the name of the function, and its parameters.". Except that it forgot the return type (I'm pretty sure he didn't forgot it, and that your quote is a bit approximative. If your quote is correct, change the book).

Best regards,

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this