473,387 Members | 1,721 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

template accessors for class?

Say I have the following class:

using std::string;
class Player
{
public:
Player() : name(""), age(""), other_stuff("") {}
private:
string name;
string age;
string other_stuff;
};
It's "proper" to create setter and getter methods for each of those
private data members, right?

In Ruby, the same class plus all the accessor methods could be
represented as:

class Player
attr_accessor :name, :age, :other_stuff
def initialize
@name = ""; @age = ""; @other_stuff = ""
end
end

Where the attr_accessor method takes symbols (in short, immutable
strings) and dynamically generates a function that serves as a getter
and setter for each one of those data members...

class Player
def name=(n)
@name = n
end
def name()
return @name
end
# and so on
end
Can I do something like that with templates? I'm finding that I'm
repeating myself a bunch when doing these accessor methods in C++.

Thanks,
Joe
Apr 5 '06 #1
5 3042
Joe Van Dyk wrote:
Say I have the following class:

using std::string;
class Player
{
public:
Player() : name(""), age(""), other_stuff("") {}
private:
string name;
string age;
string other_stuff;
};
It's "proper" to create setter and getter methods for each of those
private data members, right?

Not in my book, it's a design smell.

If all you require is a bucket of values, use a struct.

If the object has some other use, then why provide accessors?

--
Ian Collins.
Apr 5 '06 #2
In article <Ix********@news.boeing.com>,
Joe Van Dyk <jo********@boeing.com> wrote:
Say I have the following class:

using std::string;
class Player
{
public:
Player() : name(""), age(""), other_stuff("") {}
private:
string name;
string age;
string other_stuff;
};
It's "proper" to create setter and getter methods for each of those
private data members, right?


Proper? Well it's not evil or anything like that but proper? Who's going
to call them and why? Once you know the answers to those two questions,
then you can say whether or not they are proper.

--
Magic depends on tradition and belief. It does not welcome observation,
nor does it profit by experiment. On the other hand, science is based
on experience; it is open to correction by observation and experiment.
Apr 5 '06 #3
Ian Collins wrote:
Joe Van Dyk wrote:
Say I have the following class:

using std::string;
class Player
{
public:
Player() : name(""), age(""), other_stuff("") {}
private:
string name;
string age;
string other_stuff;
};
It's "proper" to create setter and getter methods for each of those
private data members, right?


Not in my book, it's a design smell.

If all you require is a bucket of values, use a struct.

If the object has some other use, then why provide accessors?


I thought the point was that /now/ it's just a struct, but later on, it
could be a complex class that seeks world domination, and as such, would
need to hide its privates so it could change how they are stored later on.

Joe
Apr 5 '06 #4
Joe Van Dyk wrote:
Ian Collins wrote:
Joe Van Dyk wrote:
Say I have the following class:

using std::string;
class Player
{
public:
Player() : name(""), age(""), other_stuff("") {}
private:
string name;
string age;
string other_stuff;
};
It's "proper" to create setter and getter methods for each of those
private data members, right?


Not in my book, it's a design smell.

If all you require is a bucket of values, use a struct.

If the object has some other use, then why provide accessors?


I thought the point was that /now/ it's just a struct, but later on, it
could be a complex class that seeks world domination, and as such, would
need to hide its privates so it could change how they are stored later on.

That would happen as if by magic once you changed it from a struct to a
class!

--
Ian Collins.
Apr 6 '06 #5
Ian Collins wrote:
Joe Van Dyk wrote:
Ian Collins wrote:
Joe Van Dyk wrote:

Say I have the following class:

using std::string;
class Player
{
public:
Player() : name(""), age(""), other_stuff("") {}
private:
string name;
string age;
string other_stuff;
};
It's "proper" to create setter and getter methods for each of those
private data members, right?
Not in my book, it's a design smell.

If all you require is a bucket of values, use a struct.

If the object has some other use, then why provide accessors?


I thought the point was that /now/ it's just a struct, but later on,
it could be a complex class that seeks world domination, and as
such, would need to hide its privates so it could change how they
are stored later on.

That would happen as if by magic once you changed it from a struct to
a class!


If you allow me to butt in...

Having accessors is not yet the end of the world. However, the OP should
think first and foremost about the interface to the class, and not about
the data that are stored in.

Joe,

For some reason you decided to begin with the class implementation. That
is not right. I think I know why it's so. You might think: "OK, I have
a player. What properties does a player have? It has a name, its age,
and some other stuff. Let's give it those data members, and proceed from
there." It started OK, it only progressed in the wrong direction. Let's
begin again. You have a "player". In your model domain a "player" has
a "name". What for? So it can be identified by it, right? So, the class
'Player' needs a way so that somebody can query the "name" of an instance.
And we can safely establish that whoever asks for the "name" expects no
less (and no more) than a 'std::string' object.
So we write

class Player {
public:
std::string name() const; // I made it const because it's unlikely
// to change anything in the object
};

That's our first step in the design process. What's next? How does each
'Player' instance get its "name"? How did you get your name? Your parents
(most likely) named you when you were born. So, it makes sense to give
the class 'Player' a constructor with an argument, which will designate
the instance being constructed with a name:

class Player {
public:
Player(std::string name);
std::string name() const;
};

OK, good. As some would suggest, you need to make a test case immediately
for that functionality to provide the test platform and an example of how
to use the class:

int main() {
Player player("Joe");
assert(player.name() == "Joe");
}

If you combine the two pieces, the program won't compile yet, but it will
be very close. What do you need now? You need to _implement_ those two
functions (the constructor and the 'name' member). Only *now* do you get
to pick _how_ the "name" of a 'Player' instance gets stored. For all we
know, you could actually have a global table of names and each player
would store an index in that table...

But let's not overcomplicate things. Let 'Player' have a data member,
so it can store its own name and give it when asked:

class Player {
std::string n;
public:
Player(std::string name);
std::string name() const;
};

If that's our initial layout of the 'Player' class, let's now create the
bodies of the member functions:

Player::Player(std::string name) : n(name) {
// nothing here
}

std::string Player::name() const {
return n;
}

Why did we call the data member 'n'? No reason. Call it what you will.
It's only important to _you_, not to any user of that class.

Now, let's just evaluate a couple of things here. Is a 'Player' allowed
to change its name? Generally, yes. In real life, anybody can change
their name. The only limitation is (a) only after 18 years of age and
(b) by applying to a judge, and don't forget to give good enough a reason
for the name change.

So, why not limit [y]our class in that regard and prohibit it from ever
changing the name of an instance? I say, let's. How? We can make the
'n' member constant and not create any functionality to change the value
of that member during the lifetime of the object:

class Player {
const std::string n;
public:
Player(std::string name) : n(name) {}
std::string name() const { return n; }
};

What else can we improve here? Not much, but I'd do two things. First
of all, let's (for now, until we have a good reason not to) prohibit
implicit conversion from 'std::string' to 'Player' by declaring it one-
argument constructor 'explicit', and let's for the sake of keeping good
habits, pass the argument to the constructor by a reference to const:

class Player {
const std::string n;
public:
explicit Player(std::string const & name) : n(name) {}
std::string name() const { return n; }
};

That's it. We're done so far with the name. Now we can proceed to
the 'age'.

What's important about the age? If a 'Player' were a model of a real-
life person, at creation its age would be 0. And then, as 'time' would
pass in the simulation ("program"), each player would age accordingly.
Well, when we're born, we're rarely players, so we cannot model [y]our
'Player's as if they were real people. However, we could follow the
same logic as with the name. For the duration of the game, the 'age'
is unlikely to change. So, it is probably logically correct to prohibit
any changes to 'age' during the lifetime of a 'Player' object. And when
does it get its age? We should provide the mechanism to give every
'Player' some 'age', and the most logical time is during *construction*
(again)...

I'll leave this exercise to you. As soon as your 'Player' has two (and
not one) arguments in its constructor, you don't need "explicit" any
longer, but it shouldn't hurt. Don't forget to write a proper test for
'age' as well.

Good luck!

V
--
Please remove capital As from my address when replying by mail
Apr 6 '06 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: Simon G Best | last post by:
Hello! I have a query regarding explicit specialisation of class templates which are themselves members of class templates. Here's what I want to do: template< class T > struct pink { ...
4
by: Grey Plastic | last post by:
I have several classes that all keep track of static data. However, the manner that they keep track of static data is identical, and so I'm using the template<class Child> class Parent { ... };...
0
by: Arne Claus | last post by:
I've got a tricky problem here. I try to create an object-hierarchie, based on a template base class like template <class T> class Node { addChild(Node<T> *) =0; // the Node-Container wil be...
1
by: Jon Slaughter | last post by:
I've managed to put together a template class that basicaly creates a recursive tree that lets you easily specify the "base" class of that tree and and ending notes and lets you stop the recursive...
4
by: Werner Henze | last post by:
Hi folks, I found a bug in VS .NET 2003. When compiling the following code with FAIL defined I get an error C2352 'B<T>::g::B<T>::g': Unzulässiger Aufruf einer nicht statischen Memberfunktion...
8
by: maverick | last post by:
Hello I am getting an error when i am trying to instantiate an object of the template based class #include "foo.h" int main() {
2
by: vilarneto | last post by:
Hello everyone, I'm facing a particular situation about template class derivation. The subject is old -- deriving a non-template class from a template base class -- but my problem is that the...
2
by: Korosov | last post by:
Hi! GCC (4.1.2 20070502 (Red Hat 4.1.2-12)) gives an error: test.cpp: In constructor <Dclass<T>::Dclass()>: test.cpp:27: error: <a> was not declared in this scope when compiling the...
5
by: Harinezumi | last post by:
Hello, I need help with the design of a serialization template base class. The idea is that any class derived from this template base class would only need to implement the input and output...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.