A way of using classes

Started by
5 comments, last by Xartrix 15 years, 6 months ago
Hello, I'm having a problem deciding how I should use classes. I have two of them, all having public functions and private variables. The problem is I need to use some private/protected members from one class in another, so I wondered how should I do it... One way would be to write a 'query' function, which would return the value I want: class ONE { private: int One; public: int getInt() {return One;} }one; , but this wasn't exactly appealing, because I could make (int One) public and I wouldn't need a function for it. However, this isn't a best idea either, because there won't be a reason to use private or protected anymore (I want to use private/protected to throw some order into all that chaos). Inheritence (to my knowledge) only derives public/protected when the class is created, so if I were to inherit from class ONE and change (int One) later, the inherited member would remain unchanged. There is still friendship, but as far as I know, you need to pass the class as an argument to the function which uses its protected members, and I don't want to pass arguments if I don't have to Still, maybe a namespace would do, so I could have them (protected/private members) tied with the class a little more, but it would essentially be the same as making them global variables. Basicly, all I'm looking for is a way to share variables without using unnecessery functions, friendship, while retaining private/protected access restrictions.
Advertisement
Using Get/Set functions as you have in your example, is a valid way to share data across classes, in that you can control how the member variable is being changed.

For example, if you member - int One should only have a value between 1 and 3, your public method could be as so:

class One{private:int One;public:void setInt(int i){if(i > 0 && i < 4)One = i;}};


This will prevent a class outside the One class chaging this member to an invalid value.

If these classes are very heavily dependant on data from each other, maybe you should refactor them and see exactly which classes should be responsible for which data.
Quote:Original post by Xartrix
Basicly, all I'm looking for is a way to share variables without using unnecessery functions, friendship, while retaining private/protected access restrictions.


The entire point of having private/protected access restrictions is to prevent you from sharing variables. From your post, it seems that you know you you're doing is "nasty OO", so you're looking for a way to do it anyway, but without feeling guilty.

Access to an implementation detail, whether it happens directly because that detail is public, or indirectly through an accessor or visitor, is still access to an implementation detail, and as such it should be avoided.

The obvious question to ask yourself, when you want to design a new class, is what the state of that class should be. In other words, you need to decide what the interface is. See the linked article for some tips to create good, clean interfaces.

If the only purpose of your object (class ONE) is to store an integer, then typedef int ONE; is enough.

If you want it to store an integer without being one, or if you want to perhaps later on restrict the range of values that are allowed, then consider:
class ONE {  int value;public:  ONE(int value) : value(value) {}  int operator *() const { return value; }};

The compiler will handle assignment and copy construction automatically for you, and you got what you want.

Of course, I suspect that your class isn't just destined to be a single integer value. People usually expect to manipulate several values as part of a class. But then, there are two possible situations.

In the first case, a value is independent of all the others. Such a value doesn't have to be private: you can let it be public, because everyone can change it on its own without altering the state of the object. Of course, this value might have forbidden states, such as a probability being larger than one. But since this restriction is part of the value (instead of the containing object), you can create a new type for that value to enforce the restrictions. For instance, don't store a probability as a floating-point number, but as an instance of a probability class.

In the second case, the value depends on the state of another. For instance, the health must be smaller than the max-health. If you have a group of properties that is independent of all other properties, you can group them together as an object. So, you would have a health class which keeps both the current health and the max health, and enforces the health-less-than-max constraint.

What happens, in the second case when all values depend on other values, is that you can't change a value on its own. This is because your change might violate a constraint, which results either in silent failure (you change to a "close" value that respects the constraint) or explicit failure (you throw an exception), and both are pretty nasty semantics for a SetValue mutator.

The solution is to drop mutator semantics and instead describe what the operation will actually do. For instance, you don't Set the health of a player character: if you exceed the maximum value, what happens? Do you increase the max-health accordingly, or do you cap the health?

By using Heal(amount), you get the implicit notion that healing can't exceed the maximum health. So, you guess (correctly) that the health will be capped.

Conclusion:

  • If a value can be changed independently of the state of the object, make it a public variable (possibly with a custom class).
  • Group values which behave in a coupled manner into classes.
  • Use semantics that are more easily understandable than simple mutators
.

However, read-only accessors, such as your getInt() example, are acceptable because they don't change the state, they merely represent it. Assuming of course that Int is truly part of the state, and not an implementation detail.
Thanks for your advices...

Class ONE was just an example of a class with a query function. The idea was to somehow use protected window width and height from one class in another (without inheriting).

However, I think you missed my point :)
I wanted to know if there was a way to make classes interact between one another, without using accessors and mutators, friendships, inheritence (ordinary if they have something in common, I usually submerge one into another or make something public).

Normally, those classes don't have anything to do with each other and this was the only occasion (getting window sizes), so I thought writing an accessor would be a waste of space. Also, since I don't have much in protected yet, I wasn't willing to move it (window sizes) to public (although I realize it would probably be the easiest solution).

Nevertheless, I'll probably just concatenate them or submerge one class into another to solve this.
Quote:
Nevertheless, I'll probably just concatenate them or submerge one class into another to solve this.

I am not entirely sure what you mean here, but anything that I could guess is likely worse than simply providing accessors for the window width and height -- which is not entirely an uncommon property for a window class to expose.

I think you should provide us with some more information about what you're trying to do and what your current code looks like.
Quote:Original post by Xartrix
Hello,

I'm having a problem deciding how I should use classes.
I have two of them, all having public functions and private variables. The problem is I need to use some private/protected members from one class in another, so I wondered how should I do it...

One way would be to write a 'query' function, which would return the value I want:


"I'm having a problem deciding how I should take my friend out to dinner. The problem is I need to put the food in her stomach so she can digest it, so I wondered how I should do it... one way would be to perform surgery,..."

Quote:Original post by Xartrix
However, I think you missed my point :)
I wanted to know if there was a way to make classes interact between one another, without using accessors and mutators, friendships, inheritence (ordinary if they have something in common, I usually submerge one into another or make something public).


Of course there is: you use ordinary member functions.

Private data is private for a reason. You're not supposed to think of the other object in terms of what data it has. We communicate with classes via their interface, which is to say, the public functions. The purpose of the interface is not to expose the data, because the point is not to expose the data at all. We use the interface to specify what the object can do.

// Noclass Friend {  Stomach s;  public:  Stomach& getStomach() { return s; }};class Me {  public:  void feed(Cake& c, Friend& f) { f.getStomach().insertFood(c); }};// Yesclass Friend {  Stomach s;  public:  void eat(const Cake& c) { s.insertFood(c); }};class Me {  public:  void feed(Cake& c, Friend& f) { f.eat(c); }};


In the general case, this will be difficult to do right. It requires you to think. It also makes it easier to ensure that things are working right, easier to find problems, and easier to read the code, which are all more important than saving time on "getting it right".
Zahlman: thanks, I understand now!

Quote:Original post by jpetrie
I am not entirely sure what you mean here, but anything that I could guess is likely worse than simply providing accessors for the window width and height -- which is not entirely an uncommon property for a window class to expose.


err what I meant was to nest them (like the Stomach s in above example) or to merge them together somehow

This topic is closed to new replies.

Advertisement