Sign in to follow this  

C++ theory question

This topic is 4750 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

OK, a theory question for you all. I know C++ fairly well, but as my CS teacher would tell you, my usage of C++ is horrendous. I use it as a subset of C, and it acts rather crazy. Here's the problem. I don't see the value of protecting data. Yes, I know you can prevent other parts of your program from altering data--but in most cases it's still changeable, and fairly easily. Is there any sort of real reason that "player.alter_health(10)" is better than "player.health += 10"? I don't work on projects with many people, and I'm usually the only coder, so it's unlikely that I'll change something in the wrong place...

Share this post


Link to post
Share on other sites
Quote:
Is there any sort of real reason that "player.alter_health(10)" is better than "player.health += 10"? I don't work on projects with many people, and I'm usually the only coder, so it's unlikely that I'll change something in the wrong place...

For the most part, its more of a design thing than a technical thing. Your 'player.alter_health(10)' may well be resolved down to a 'player.health += 10' (or similar) by your compiler based on optimizations/inlining...

From a design point of view, the vast majority of large systems are complex - we're talking 100,000's of lines, millions of files. Way bigger than you're likely to have even considered. Now, factor in that you might have several (if not more) developers working on this...

Can you guarantee that they'll all behave correctly? or that they'll all know whats supposed to happen?

say Programmer-A thinks health is measured on a 0..1000 scale... so he does 'player.health += 500'. But in fact, health is measured as a percentage 0..100 so obviously that 500 is a bit wrong.

Now, Programmer-B comes along, writing a completely different part of the program... something that casually references the health variable. But he knows (because he read the design document[wink]) that it's a percentage... and writes the code expecting this to be honoured... and his code falls to pieces because somewhere along the line a 500 has been involved.

You go try debugging that one when you've got several programmers working on 1000's of files who are all probably way too busy to give you their FULL attention.

Alternatively, as part of a class/struct:

void player::alter_health( int newHealth )
{
if( newHealth < 0 ) newHealth = 0;
if( newHealth > 100 ) newHealth = 100;
my_privately_contained_health = newHealth;
}




That is, two new lines in your original class make sure that (short of some real shocking programming), no one can abuse your system. This code can then pretty much be written off as "safe"..

hth
Jack

Share this post


Link to post
Share on other sites
Functional abstraction*. The example you give is not a great one to demonstrate this principle, but I believe I can still make a case. Imagine you're programming your game and you have health as a public member of type integer. Various other classes will access this code and alter it.

Now you decide you want to display your health in a pie-chart type form and you do so, but find that your FPS has mysteriously halved. You run it through a profiler and discover that converting from an integer to a float each frame and dividing to get a percentage health is killing you. The obvious solution would be to change the health to a float, but you also need to store it in percentage form to avoid that divide. What do you do?

You might decide to store health in both integer and float form, but now you must go back through all your code and change health op value; to health op value;percentageHealth op percentageValue;. Furthermore you must make sure that you don't miss any, or your players will be very annoyed when they die from being sneezed on while their health meter shows perfect health!

If you used a function in the first place you wouldn't have this problem. You add the code to update the percentageHealth in a single location and everything is forced to use that function, so you never miss a case.

Enigma

*This argument based on Scott Meyer's Effective C++ 2nd Edition, Item 20, which I thoroughly recommend (the whole book, not just item 20!).

Share this post


Link to post
Share on other sites
heres short answer to a very similar question that was part of my OO programming module - it's based around a smalltalk class called Frog with access methods for a variable named size, but you should get the general idea for c++ too:

//
The inherent benefit of forbidding direct access to data members is that all access has to be through an interface and implemetantion defined by the class (or possibly a derived implementation in a subclass). Essentially this means that the member cannot be accessed or modified without the Class noticing.

This is important firstly to allow validation of the input; to make sure we don't get a frog that fills the screen, for example or to disallow value that might cause undefined behaviour - a negative value for the Frog's size for example. This also means that users of a Class need less knowledge of the implementation, giving tighter encapsulation - they need not worry about breaking your implementation by giving it 'bad' input.

Secondly it allows behaviour to be based on changing input - we might want a Frog to change colour every time it changes size for example, or to make all frogs over a certain size red. It also allows a class to call 'self changed' and inform dependants of the change, again leading to better encapsulation and much more convenient reuse.
//

You could argue that validation etc can be done in the user code (assuming you want to write it multiple times....) but this breaks encapsulation pretty badly. Encapsulation is the main thing here - it's the corner stone of clean, reuable object programming.

If you think it unlikly that you ever change something in the wrong place or forget the exact implementation details, you probably never worked on a large project, and have never gone back to a project after a long absence. Encapsulation frees you from having to remember the ins and outs of that spaghetti code you wrote years ago, because it's all neatly abstracted away.

Share this post


Link to post
Share on other sites
Quote:

Here's the problem. I don't see the value of protecting data. Yes, I know you can prevent other parts of your program from altering data--but in most cases it's still changeable, and fairly easily.

Then don't do it. Just make sure you know the tools offered. I promise, when you get involved in a bigger project, you'll see the point. :)
Until then, don't bother.

It's only a design tool. It's there to remind you or any other coder that "this variable shouldn't just be changed at will". In simple examples like your player.health += 10, it doesn't really matter, because the health value probably doesn't affect a lot of other factors. But what if it does? What if the health level determines run speed? You run slower when you're wounded? Then suddenly you need to remember to change the run speed every time the health changes. So if health is a public variable, you or someone else is bound to just alter it directly at some point, accidentally bypassing all the stuff that was meant to be changed with it. If you'd called the alter_health() method, you'd have ensured that it updated the run speed or whatever else needed updating. Then you won't have to remember "When I change health, I should also compute a new run speed", because that happens automatically in the alter_health() method.

The problem with this, or a zillion other OO features is that it simply doesn't make sense in the small examples you're shown when learning about it. It can be handy in bigger projects though, not just if there are multiple coders, but also just if it's big enough that you're unable to keep every aspect of it in mind at the same time.

Share this post


Link to post
Share on other sites
Look up Bruce Eckel's "Thinking in C++" - its a free online pdf C++ book that intelligently explains _why_ you should use C++ features and discusses how to actually code in C++.

Fundamentally, C++ is two things:
a) a superset of C
b) a compiled OOP language that is backwards-compatible with C.

Learn to think of it as b).

Share this post


Link to post
Share on other sites
Yep.

Basically, some day the task of adjusting health is bound to become more complicated than just adding to the variable. And at that point, you'll be glad you "pre-factored" by putting the code in a specific place.

Also, in the general case, manipulating an object can involve more than one of its data members. This is bad:

tmp = foo.z;
foo.z = foo.y;
foo.y = foo.x;
foo.x = tmp;


This is actually worse, generally speaking:

tmp = foo.getZ();
foo.setZ(foo.getY());
foo.setY(foo.getX());
foo.setX(tmp);


The problem is that rotating the values around is conceptually part of the behaviour of the foo object. (OK, you're going to have to trust me on this one because of the abstractness of the example. [wink]) The behaviour really belongs in the foo object itself:

void Foo::rotate() {
int tmp = z; z = y; y = x; x = tmp;
}
// ...
Foo foo;
foo.rotate();


Now foo has a method that *does something*.

Share this post


Link to post
Share on other sites
Quote:
Original post by Pxtl
Look up Bruce Eckel's "Thinking in C++" - its a free online pdf C++ book that intelligently explains _why_ you should use C++ features and discusses how to actually code in C++.

Fundamentally, C++ is two things:
a) a superset of C
b) a compiled OOP language that is backwards-compatible with C.

Learn to think of it as b).


I have that book. I should probably actually read it sometime. :D

Thanks for your replies, all.

Share this post


Link to post
Share on other sites

This topic is 4750 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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