Is it good to have all the setter functions return a reference to the object in c++?
It's a usable enough pattern if there's a lot of things that need to be set on an object.
class Foo
{
int x, y, z;
public:
Foo &SetX(int x_) { x = x_; return *this; }
Foo &SetY(int y_) { y = y_; return *this; }
Foo &SetZ(int z_) { z = z_; return *this; }
};
int main()
{
Foo foo;
foo.SetX(1).SetY(2).SetZ(3);
}
This pattern replaces a constructor that takes three ints:
int main()
{
Foo foo(1, 2, 3); // Less self-explanatory than the above version.
}
It's useful if you have a number of values that don't always need to be set.
For reference, a more complete example of this sort of technique is refered to as the "Named Parameter Idiom" in the C++ FAQ Lite.
Of course, if you're using this for named parameters, you might want to take a look at boost::parameter. Or you might not...
You can return a reference to this
if you want to chain setter function calls together like this:
obj.SetCount(10).SetName("Bob").SetColor(0x223344).SetWidth(35);
Personally I think that code is harder to read than the alternative:
obj.SetCount(10);
obj.SetName("Bob");
obj.SetColor(0x223344);
obj.SetWidth(35);
The typical purpose for this style is in use for object construction.
Person* pPerson = &(new Person())->setAge(34).setId(55).setName("Jack");
instead of
Person* pPerson = new Person( 34, 55, "Jack" );
Using the second more traditional style one might forget if the first value passed to the constructor was the age or the id? This may also lead to multiple constructors based on the validity of some properties.
Using the first style one might forget to set some of the object properties and and may lead bugs where objects are not 'fully' constructed. (A class property is added at a later point but not all the construction locations got updated to call the required setter.)
As code evolves I really like the fact that I can use the compiler to help me find all the places where an object is created when changing the signature of a constructor. So for that reason I prefer using regular C++ constructors over this style.
This pattern might work well in applications that maintain their datamodel over time according to rules similar to those used in many database applications:
- You can add a field/attribute to a table/class that is NULL by default. (So upgrading existing data requires just a new NULL column in the database.)
- Code that is not changes should still work the same with this NULL field added.