Let's assume I have a class A looking like that:
class A {
public:
public A(bool someFlag, Params someParams);
private:
vector<string> texts;
}
I would like to extract the logic of initializing the texts member field.
I came up with 2 ideas:
First idea - static, private member functions that would return the desired vectors of texts.
A::A(bool someFlag, Params someParams) {
if (someFlag)
texts = createSomeTexts(someParams);
else
texts = createOtherTexts(someParams);
}
Second idea - private member functions that would assign the desired vectors of texts to the class members by themselves.
A::A(bool someFlag, Params someParams) {
if (someFlag)
createAndAssignSomeTexts(someParams);
else
createAndAssignOtherTexts(someParams);
}
Of course both versions do the job correctly, but I wonder what is the advised approach to theese situations. Also, if the approach should change if member initalization requires more parameters (especially ones that are stored in the class as members as well).
You should strive to initialize your data member, not assign to them in the constructor body. Both versions you showed cause default construction of the std::vector<std::string> instance, and assign to it later. Hence, I'd suggest this:
A::A(bool someFlag, const Params& someParams) :
texts(someFlag ? createSomeTexts(someParams) : createOtherTexts(someParams))
{}
or, more readable, let createSomeTexts handle the flag, too:
A::A(bool someFlag, const Params& someParams) :
texts(createSomeTexts(someFlag, someParams))
{}
Make createSomeTexts a member function if it needs to access other data members (make sure they're declared before the texts member and properly initialized - as #Scheff pointed out, this is unlikely to be a good idea, though). Otherwise, make it a free function (see here why this is preferrable). Once createSomeTexts is a free function, you could equally well construct the object like this:
std::vector<std::string> stringsToInject = createSomeText(/* Some flags.... */);
A instance(stringsToInject); // A's ctor updated to make this work
which could further separate concerns as the constructor of A takes care of initializing the data members, while the logic to create the initialization data is located somewhere else.
I would use case 1 because the functions createSomeTexts and createOtherTexts do not alter any class variables. That means these functions can be unit tested.
It is better not to use global variables and if you must, not to alter them from the global scope (this->) but to pass them by reference or as a pointer to your function.
This way you can pass stubs in your code and write test cases.
Also, Params should be a const reference:
class A {
public:
public A(const bool someFlag, const Params &someParams);
private:
vector<string> texts;
}
Related
As far as I can understand as new comer to C++, both intends to expose a private member to public. We can say like this:
// Make everything outside can see value of name
object.get_name(); // get method
object.name(); // return member by ref to get
// Make everything outside can set value of name
object.set_name("Name"); // set method
object.name() = "Name"; // return member by ref to set
What's difference between those two way of accessing private member?
Why bother not to just create a public member if all I need is just to
get or set without doing anything else inside those functions?
With set_name, you can perform validation on the input, and throw exceptions as necessary. You can also update any other class members at the same time.
If you return a reference, you lose control of what can be set since the member can be modified through the reference. In fact, you may as well have the member variable public, as you point out.
you can have more control when you use a set function, rather than returning a reference to an internal class member (validation of input, exception throwing etc.).
class Foo{
std::string name;
public:
const std::string& get_name() const;
void set_name(const std::string&); // perform input validation inside set_name
};
If you expose the class member via a public function returning a reference to it you have removed the purpose of it being private in the first place.
Moreover, if the object is shared between multiple threads it may be necessary to synchronize access to the object's state. For that you would typically lock a mutex inside the object's functions.
class Foo{
mutable std::mutex mtx; // mutable so that it can be modified in const-qualified functions
std::string name;
public:
std::string get_name() const
{
std::lock_guard<std::mutex> lg{mtx};
return name;
}
void set_name(const std::string& str)
{
std::lock_guard<std::mutex> lg{mtx};
name = str;
}
};
By having the synchronization taking place inside get/set-functions the class itself handles the synchronization, without you having to worry about data races.
My suggestion is the following:
If your class is just a collection of independent variables (e.g. 3
dimensions of a vector or name, birth date and adress of a person)
then just use public members.
If your class has to maintain some
invariants (e.g. the allowed days in a date depends on the year and
month) use private members and public setter/getter methods that
enforce those invariants.
Sometimes, you also want to allow only read or only write access or you have "simulated" properties, which don't map directly to a specific member variable, but are calculated from them. In those cases you obviously also need separate setter and getter methods (or only one of them).
Finally, the only common case - I know of - in which you want to return
a non-const reference to a private variable is in containers, where
you acces an element by its index or key.
I would like to know if the following scenario is possible.
I have a class A which has some data members, one of them being a container (let's assume a simple array).
Now to the constructors of A, I'd like to pass a lambda function to initialize the data members of the class.
I want the user to be given the ability to write his own initialization routine and have it applied on the class.
For example, consider this constructor of A which takes 2 arguments.
The first as the size of the array and the second, a lambda function.
A(std::function<void (self_type)> f) {
f(*this);
}
Now I'd create an object as follows:
A a([](A a) {
//do something here to initialize array and data members
});
This way, the user is given the ability to perform his own initialization rather than using the constructors or other fill functions offered by the class.
Is this possible using some trickery? It'd be even better if I somehow could use this inside the lambda function.
For example -
A a([]() {
//do something here to initialize array and data members
this->_n = 100; // where _n is some data member.
});
Any possible solution is welcome!
Generally, if a class keeps members private, it enforces an invariant over the state of those members. If you let J. Random User poke at your privates you don't know that he will maintain that invariant. So I'm not sure if this is design-wise a good idea.
That said, you can achieve something like this by putting all relevant data members in a private base class as public members:
struct A_base {
int something;
std::string some_other_thing;
};
class A : private A_base {
public:
A(std::function<void(A_base&)> f) { f(*this); }
template <typename Function>
A(Function&& f) { std::forward<Function>(f)(*this); }
};
This provides the required access to the user function, but obviously without the syntactic ability to use this.
Can someone please quote an example code when we should not use initialisation list in the constructor and how that can be overcome with assignment?
I am looking for an example for the below statement
This might happen when your class has two constructors that need to initialize the this object's data members in different orders. Or it might happen when two data members are self-referential. Or when a data-member needs a reference to the this object, and you want to avoid a compiler warning about using the this keyword prior to the { that begins the constructor's body (when your particular compiler happens to issue that particular warning). Or when you need to do an if/throw test on a variable (parameter, global, etc.) prior to using that variable to initialize one of your this members.
I believe the main concept that the author of your statement was referring to is the fact that calls made to variables in the initialisation list occur not in the order you see them in the initialisation list, but in the order the variables are listed in the class definition.
That means
if you have two different constructors which use initialisation lists, they must initialise them in the same sequence
your control over sequencing (which may be important if you have mutually-dependent members) is limited
I'd recommend taking a look at Scott Meyer's Effective C++ which covers this (amongst many, many other useful and informative topics).
Here are some examples:
This might happen when your class has two constructors that need to
initialize the this object's data members in different orders.
class Example1 {
public:
Example1(std::string decoded, std::string encoded)
: decoded_(decoded),
encoded_(encoded) {}
explicit Example1(std::string encoded)
: decoded_(), // Can't use "decoded_(Decode())" since "encoded_" isn't initialised
encoded_(encoded) {
decoded_ = Decode(); // Assign here instead of initialising
}
private:
std::string Decode(); // decodes class member "encoded_"
std::string decoded_, encoded_;
};
In this example, decoded_ will always be initialised before encoded_ since that's the order in which they are declared in the class, even if we swap their order in the initialisation list.
Or when a data-member needs a reference to the this object, and you
want to avoid a compiler warning about using the this keyword prior to
the { that begins the constructor's body (when your particular
compiler happens to issue that particular warning).
class Example2 {
public:
Example2() : functor_() {
functor_ = std::bind(&Example2::Do, this);
}
private:
void Do();
std::function<void()> functor_;
};
Here, functor_ needs to use this when it is initialised/assigned. If we were to intialise functor_ in the initialisation list, the this pointer would be referring to an object which at that point wasn't fully initialised. That could be safe depending on the particular circumstances, but the foolproof option is to defer setting functor_ until inside the constructor body, by which point this does refer to a fully-initialised object.
Or when you need to do an if/throw test on a variable (parameter,
global, etc.) prior to using that variable to initialize one of your
this members.
class Example3 {
public:
Example3(int force, int acceleration)
: force_(force),
acceleration_(acceleration),
mass_(0) {
if (acceleration_ == 0)
throw std::exception("Can't divide by 0");
mass_ = force_ / acceleration_;
}
private:
int force_, acceleration_, mass_;
};
Hopefully this is self-explanatory.
I'm not sure what is meant by
when two data members are self-referential
so I can't give an example for that I'm afraid.
My gut feeling is it is not. I am in the following situation:
class PluginLoader
{
public:
Builder* const p_Builder;
Logger* const p_Logger;
//Others
};
PluginLoader::PluginLoader(Builder* const pBuilder)
:p_Builder(pBuilder), p_Logger(pBuilder->GetLogger())
{
//Stuff
}
Or should I change the constructor and pass a Logger* const from where PluginLoader is constructed?
That's perfectly fine and normal. p_Builder was initialized before it.
What you have is fine. However, I just want to warn you to be careful not to do this: (GMan alluded to this, I just wanted to make it perfectly clear)
class PluginLoader
{
public:
Logger* const p_Logger; // p_Logger is listed first before p_Builder
Builder* const p_Builder;
//Others
};
PluginLoader::PluginLoader(Builder* const pBuilder)
:p_Builder(pBuilder),
p_Logger(p_Builder->GetLogger()) // Though listed 2nd, it is called first.
// This wouldn't be a problem if pBuilder
// was used instead of p_Builder
{
//Stuff
}
Note that I made 2 changes to your code. First, in the class definition, I declared p_Logger before p_Builder. Second, I used the member p_Builder to initialize p_Logger, instead of the parameter.
Either one of these changes would be fine, but together they introduce a bug, because p_Logger is initialized first, and you use the uninitialized p_Builder to initialize it.
Just always remember that the members are initialized in the order they appear in the class definition. And the order you put them in your initialization list is irrelevant.
Perfectly good practice.
I would suggest this (but its on a purely personal level):
instead of having functions called in your constructor, to group them in a init function, only for flexibility purposes: if you later have to create other constructors.
First, my latest coding is Java, and I do not want to "write Java in C++".
Here's the deal, I have to create an immutable class. It's fairly simple. The only issue is that getting the initial values is some work. So I cannot simply call initializes to initialize my members.
So what's the best way of creating such a class? And how can I expose my immutable / final properties to the outside world in C++ standards?
here's a sample class:
class Msg {
private:
int _rec_num;
int _seq;
string text;
public:
Msg(const char* buffer) {
// parse the buffer and get our member here...
// ... lots of code
}
// does this look like proper C++?
int get_rec_num() { return _rec_num; }
};
C++ offers some nice mechanisms to make your class immutable. What you must do is:
declare all your public (and maybe protected) methods const
declare (but not define) operator= as private
This will ensure that your objects cannot be modified after they have been created. Now, you can provide access to your now immutable data members anyway you want, using const methods. Your example looks right, provided that you make it const:
int get_rec_num() const { return _rec_num; }
EDIT: Since C++11 you can explicitly delete operator=, rather than just leave it undefined. This explicitly instructs the compiler to not define a default copy assignment operator:
Msg& operator=(const Msg&) = delete;
I'd mark your immutable member as 'const', and assign it a value in your constructor initializer list.
I'd also parse your buffer outside of the class, and pass in the string to the constructor.
Something like this:
class Msg {
private:
int _rec_num;
int _seq;
const std::string text;
public:
Msg(const std::string& str) :
text(str)
{
}
// does this look like proper C++?
int get_rec_num() const { return _rec_num; }
};
// parse the buffer and get our parameter somewhere else
NB:
You should make any member functions that do not change the state of your class internals as 'const'; as this will allow you to call them with const objects.
You should avoid inluding a using std::string in header files; as anyone who includes your header has this 'using' forced upon them.
You're on the right track -- use getters for everything, and without any setters, your class is effectively immutable.
Don't forget some of the corner cases though -- you might want to declare the operator=() method as private and not implement it so someone can't override the object with the default compiler generated assignment operator, etc.
// does this look like proper C++?
int get_rec_num() { return _rec_num; }
You should use
int get_rec_num() const { return _rec_num; }
(see the const which allows to call the member on const objects).
To make a variable immutable you have to use the const key word eg const int _rec_num. Const variables can only be initialised through an initialisation list, which gets called before any code in the constructor. This means that you cannot do any processing in the constructor which sets the const member variables.
You have two ways round this, first you can create another internal class which takes in a buffer and parses it into your variables. Put a const version of this into your MSG class and put this in the initialisation list:
class MsgInner
{
public:
int _rec_num;
Msg(const char* buffer) {
// Your parsing code
}
};
class Msg
{
public:
const MsgInner msg;
Msg(const char* buffer) : msg(buffer)
{ // any other code }
};
This is perhaps not so 'standard', but it's another perspective. Otherwise you can also do it as the other answers have suggested with get methods.
On Finalizers
There is none, you have to emulate it. Either by using a cleanup function or by having all your resources encapsulted in RAII classes. The compiler will place static machinery in your application to call destructors on your RAII classes --i.e., when they go out of scope the resources get released through the destructor.
On Immutability and Initialization
Generally if something is immutable and const-correct the class will have all of its members as const and the only time you get to "write" to them is when the class is initialized. However in your case that might not be possible.
I suggest you gather all your resources and initialize the class (via a non-default constructor with const members) once you have them. The other alternative (which I do not abide) is to have a mutator function that "claims" to be const correct but writes to the const values for a one-time post construction initialization.
First of all, it is possible to initialize the members efficiently and at construction time even if they were declared as const (which is neither necessary nor recommended).
I would still suggest that you split this class into two separate classes (pseudo-code):
// Msg: pure data object; copy constructible but not modifiable.
class Msg
{
public:
Msg(int rec_num, ...)
: rec_num_(rec_num)
...
{}
int rec_num() const
{ return rec_num_; }
...
private:
// prevent copying
Msg& operator=(Msg const&);
private:
int rec_num_;
};
// MsgParser: responsible for parsing the buffer and
// manufacturing Msg's.
class MsgParser
{
public:
static Msg Parse(char const* buffer)
{
... parse ...
return Msg(...);
}
};
// Usage
Msg const msg = MsgParser::Parse(buffer);
This also nicely separates the concerns of holding and parsing the data into separate classes.