Using setters in the constructor

I am a Java developer trying to pick up C ++. Is it possible to use the setter inside the constructor to reuse the sanity checks that the setter provides?

For instance:

#include <stdexcept> using namespace std; class Test { private: int foo; void setFoo(int foo) { if (foo < 42) { throw invalid_argument{"Foo < 42."}; } this->foo = foo; } public: Test(int foo) { setFoo(foo); }; }; 
+5
source share
6 answers

Yes, it is recommended to do this, mainly for the reason that you have already mentioned.

On the other hand, you should ask yourself if you need a setter at all, and not directly perform checks inside the constructor. The reason I write this is because setters generally lead to a mutable state that has many flaws, rather than immutable classes. However, sometimes they are required.

Another recommendation: if your class variable is an object, and you can change the constructor of this object, you can put a check in the constructor of this object:

 class MyFoo { public: MyFoo(int value) { if (value < 42) { throw invalid_argument{"Foo < 42."}; } v = value; } private: int v; } 

This will allow you to use the initialization list in the constructor of your Test class:

 Test(int foo) : foo(foo) {} 

However, now the check is a property of the variable class and is no longer one of the owning classes.

+5
source

Yes, you can. This is fine as long as your setters are not virtual , because the inheritance hierarchy when calling the correct functions, because "this" ptr is not ready yet.

Here is Herb Sutter GOTW on this subject: http://www.gotw.ca/gotw/066.htm

+3
source

Yes, that’s fine if it makes sense to have a setter for a particular member variable (there is some logic that cannot be verified by purpose alone). In this example, setFoo might just accept an unsigned int , and the caller knew that he would not pass negative values. This, in turn, can eliminate the check and, therefore, the need for a setter. For more complex checks, the setter and using this setter in the constructor is fine.

+1
source

Short answer: Yes. In fact, your example works.

Long answer: But this is not a good practice. At least you have to take care.

In general, the set function works with the constructed object. It is assumed that the class invariant holds. Functions in the class are implemented taking into account the invariant.

If you want other functions to be used in the constructor, you will have to write code. For example, to create an empty object.

For example, if in your class you change setFoo in the future (let's say setFoo changes the foo member, only it is bigger), for example, you stop working.

+1
source

This is normal.

The only situation you cannot call a member function with is when the base classes are not yet constructed.

Can member functions be used to initialize member variables in an initialization list?

0
source

I know this is not appropriate for your situation. Its just for the sake of completeness:

When you simply set element parameter values ​​(without checks like yours in setFoo ), it is recommended that you use initialization lists in the constructor. This prevents members from “initializing” 2 times: 1. with their default value, 2. with the value you passed to the constructor.

 class Test { private: int foo_; public: Test(int foo) : foo_(foo) { }; }; 
0
source

All Articles