-1

In C++, which of these ways is better?

// this is class, not a struct (just means members are public by default)
struct foo {
    int w, h;
private:
public:
};

Or

class foo {
private:
    int w, h;
public:
    int getW() { return w; }
    int getH() { return h; }
};

In this case:

foo *A;

If I'm trying to get the values of w and h,
should I use A->w and A->h for the first example or A->getW() and A->getH() for the second example?

Right now I'm using the first example, but is it in any way better practice to make methods to return the private variables? Is there some advantage to one way over the other?

jackcogdill
  • 4,900
  • 3
  • 30
  • 48
  • 1
    The second example is better in object-oriented programming. One of the main rules of OOP (generally OOD) is encapsulation. In some cases, like value objects or avoiding overhead of function call, the first example may be more appropriate. – rzymek Dec 28 '13 at 07:53
  • @rzymek And then the API is nothing but `getX` and `getY`. –  Dec 28 '13 at 07:54
  • @remyabel, it is not that simple. This approach is better which more accurately reflects Domain Model (in terms of RUP). You can imagine a system which simulates car accidents. The system contain some Factory which is responsible for creating car parts (class foo) with strictly defined physical attributes. In this case uncontrolled change of these attributes may result in faulty simulation. In other words, you can violate OOP/D principles only if it does not violate Domain Model and you will have some benefits, e.g. more readable or faster code. – rzymek Dec 28 '13 at 08:12
  • The semantics of both are different, so the answer depends on what you want to achieve. There are good cases for both approaches. – juanchopanza Dec 28 '13 at 08:19
  • 1
    @rzymek: Blindly hiding everything behind getters and setters is _not_ better object-oriented programming. – Lightness Races in Orbit Dec 28 '13 at 13:48
  • @LightnessRacesinOrbit: actually, blindly hiding behind getters and setters *is* better OOP, since it leaves the data access as a point of customization for the implementation of that type, which a data member of a specified type does not. It's still not very good, but it is better. – Steve Jessop Dec 28 '13 at 18:30
  • 1
    @Steve: [Relevant](http://stackoverflow.com/a/12108025/560648) – Lightness Races in Orbit Dec 28 '13 at 18:31
  • 1
    @LightnessRacesinOrbit: I disagree with that in various ways. Just to begin with, the statement "adding validation to a setter is a change to its preconditions" is simply false. It's the documented interface that defines the contract, not the code. There's nothing (in general) wrong with code that doesn't check preconditions at runtime, and there's nothing (in general) wrong with later changing that code to check. I don't want to get too hung up on that, though, since as it happens, this question is not necessarily about setters -- it compares a public data member with a getter *only*. – Steve Jessop Dec 28 '13 at 18:34
  • OOP and encapsulation are orthogonal. OOP is applying message passing and polymorphism to objects. Encapsulation is more general and applicable almost everywhere. –  Dec 28 '13 at 18:37
  • rightfold, encapsulation is one of the four fundamentals of OOP @LightnessRacesinOrbit, of course even blindly hiding attributes behind getters and setters is better that defining everything as public because of laziness. Implementation lasts about 10% overall time of project, maintenance 90%. Only performance reasons force me to violate OOP/D principles and I agree that "Premature optimization is the root of all evil" [D. Knuth] – rzymek Dec 28 '13 at 21:01

2 Answers2

1

If this is your only concern, then there is no practical difference. If you intend to only have members that are visible to the outside via accessor methods, then they might as well be made public (or a POD.) For example:

struct SomeSortOfInformation
{
 int w, h, x, y, pixelFormat, whatever;
};

If you intend to protect implementation details, or to change the behavior of accessing a variable (i.e., this is a common idiom in C#), then feel free to use accessor methods.

void setWidth(const int& w) { 
  if (w <= 0) this->w = 0;
  else this->w = w;
}
0

The immediate difference is that users of the class can assign to the values of w and h in the first example, but not the second.

The difference for future code changes is that the author of the class can change the way that foo's data is stored in the second example, but not the first. For example if the class represents a rectangle, then you could switch to storing the co-ordinates of the corners, and calculate the width and height when requested.

There is no certain way that is "better". If you have a class that is defined to be a dumb data container, that users can read from and write to, and it is guaranteed that it will not in future perform any clever calculations, then you can use public data members. An example of this in the standard libraries is std::pair, which has public data members first and second. Many OOP programmers will (on principle) never define or document any such guarantee, but the designers of the C++ standard libraries do not agree with this absolute principle. In any case C++ is not designed on strict OOP principles.

If you have a class that just so happens to store values that are useful to the user, but is not guaranteed to store them as members, then you would use accessors if necessary. An example in the standard libraries is std:vector, which has functions begin() and end(). In some implementations of vector they just return the values of two private data members, in other implementations they do something else.

If possible, though, give the class the functionality that the user needs, so that they don't need public data or accessors. An example in the standard libraries is std::stack, which has a protected data member for use by derived classes, but does not give "normal" users any direct access to it. If you find yourself routinely writing accessors for most data members of most classes you write, then you should seriously consider whether your design can be improved. Accessors mean that users of your class must provide the logic to use the data member. But the main advantage of classes is the ability to keep the logic for using data in the same place that the data is defined. If users always provide the logic then you're not using that opportunity.

By the way, there are a couple of errors in your question:

this is class, not a struct

It is a struct. It is also a class type.

int getW() { return w; }

Getters should be const functions: int getW() const { return w; }

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • Some people may dislike the idea of exposed-field types, but I like the "self-documenting" nature of such types. While types which are used to exchange information among objects of other types should document any non-obvious conventions, if the real "meaning" of a `Foo`'s members is determined not be anything in the code for `Foo` itself, but rather in the code for other objects which create and manipulate `Foo` instances, exposing the type's state as public fields makes it clear. – supercat Dec 28 '13 at 19:29