开发者

C++ Getters-Setters in Implementation File

开发者 https://www.devze.com 2023-03-25 17:34 出处:网络
I\'m relatively new to C++ and I think that my question may be underst开发者_开发百科ood best by example. In my header file, suppose I have

I'm relatively new to C++ and I think that my question may be underst开发者_开发百科ood best by example. In my header file, suppose I have

class myClass{
    public:
        double getVar1();
        void setVar1(double newVar1);
        void copyVar1(myClass* dat);

    private:
        double var1;
};

In my implementation .cc file, when implementing the copyVar1 method, should I do

void myClass::copyVar1(myClass* dat){
   var1 = dat->var1;
}

or

void myClass::copyVar1(myClass* dat){
   var1 = dat->getVar1();
}

where in the second case, I use the getter method instead. Both work properly in Visual C++, but I would like to know which is better to use in practice.

Thank You for your comments!


Best practices? Overload the assignment operator instead of writing a method.

myClass & myClass::operator=(const myClass & dat)
{
   var1 = dat.var1; // or dat.getVar1()
   return *this;
}

As for using the field or calling a setter... it's all a matter of personal taste. If your getter has some side effect, then you probably should call it, otherwise, use the field.

So, a big "depends".


You should nearly always use getter/setter methods to access a variable when you're outside of the class, and often you have to because that's the only way to do so. However, when you're inside the class you can use either, and if the getter method does nothing but return the variable it won't make a difference.

Your decision is going to be based on if you have code in the getter method that does something more than just returning the variable, and if you want that code to be run when copyVar1 is called. If you don't know, my advice would be to still use the getter method should you ever decide to change the code in it in the future. While it works fine now just accessing it directly, and you might have microscopically better performance, it will be much easier to find an error of calling the getter when you shouldn't that not calling it when you should. And the compiler will probably end up optimizing enough that you won't even feel the difference. :D


I would prefer using setters and getter that way if way your change some implementation details (for example introduce validation on value assign) you jest have to change that in one place in setter...


It depends. Many people will tell you that using the getters/setters instead of the variables is more robust to programming errors and changes and reduces code duplication. But as long as these getters/setters are no inline functions you may get a small performance hit and as the implementation has to know the class's internals anyway, why not just use the variables directly.


Are you trying to write a copy constructor? Why do you need copyVar1 when you have a setVar1? If you are trying to write a copy constructor, it is better not to use getter.

myclass(const myclass& other)
{
var1 = other.var1;
}

When you have both getter and setter, why not make the var1 public?


There is no right or wrong way to do it here.

However, you are assuming that getVar1() returns the value or var1. If you decide to change the way the var1 value is stored then you need to go through all the code and update it. Using a setter / getter reduces this to just a couple of methods. In which case, you should use a third option:

void myClass::copyVar1(myClass* dat){
   setVar1 (dat->getVar1());
}

and then you completely remove the dependency on var1, you can change var1 to something else and the copyVar1 will still work.


As you say, both work correctly and are perfectly legal.

In a sense the difference between accessing directly the member variable or using an accessor is that you define a stronger "layer" inside of your class; this layer, as any layer, helps you reducing dependencies.

In other words, a getter method responds basically to the requirement of not disclosing to the outside world an implementation detail; say, you might decide one day that instead of storing var1 as a double, you calculate it. So, the accessor gives you this kind of freedom: to an extent you can change the implementation without affecting other classes (i.e., reducing dependencies).

The same is true in the case of using the getter method within the class itself, i.e., you are removing dependencies within the class scope and your design is more resilient to changes.


The point of the abstraction of setters and getters is that the method of retrieval may change. When you access the member variable directly, then if anything changes, you have to update your usage everywhere. But if you use the function, then changing the way the variable is retrieved only has to change in the function.

Now, because this is the same class, it is much less of a concern than when you make variables public, because you only have to update this one implementation file (instead of updatinng every user of your class, which may not be possible if you have a library class).

To see this, look at a class that suddenly needs to be made thread safe. Now, your copier would look like

void myClass::copyVar1(myClass * dat)
{
    scoped_lock lock(mutex);
    var1 = dat->getVar1();
}

and you would not have to fix anywhere else if you always called by function. If you accessed the variable directly, then it would look like

void myClass::copyVar1(myClass * dat)
{
    scoped_lock lock(mutex);
    scoped_lock lock2(dat->mutex)
    var1 = dat->var1;
}

which locks "dat"s mutex external to dat, usually not considered a very good design (if you make engineers have to remember to lock other people's objects then you open up the chance that they forget and don't do it).

Similarly, if the variable began to be stored on a database, you'd have to handle that as well. Or if the variable now was stored in two different variables and constructed when it was retrieved, you can see how the complexity would increase.

But remember, the design philosophy of using accessors and mutators is to lower potential complexity through encapsulation. There are times when working on smaller projects (particularly personal projects) where you have no intention of ever changing the class. It might be less complex to access them directly. Don't be afraid to do so, just know why you are making the decision.

0

精彩评论

暂无评论...
验证码 换一张
取 消