1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
|
Often constructors are specializations of each other, allowing objects to be
constructed specifying only subsets of arguments for all of its data members,
using default argument values for the remaining data members.
Before the C++11 standard common practice was to define a member like tt(init)
performing all initializations common to constructors. Such an tt(init)
function, however, cannot be used to initialize tt(const) or reference data
members, nor can it be used to perform so-called em(base class)
initializations (cf. chapter ref(INHERITANCE)).
Here is an example where such an tt(init) function might have been used. A
class tt(Stat) is designed as a wrapper class around bf(C)'s bi(stat)(2)
function. The class might define three constructors: one expecting no
arguments and initializing all data members to appropriate values; a second
one doing the same, but it calls tt(stat) for the filename provided to the
constructor; and a third one expecting a filename and a search path for the
provided file name. Instead of repeating the initialization code in each
constructor, the common code can be factorized into a member tt(init) which
is called by the constructors.
Currently, bf(C++) offers an alternative by allowing
constructors to call each other. This is called
hi(constructor: delegation)
emi(delegating constructors)
The C++11 standard
allows us to delegate constructors as illustrated by the next example:
verb(
class Stat
{
public:
Stat()
:
State("", "") // no filename/searchpath
{}
Stat(std::string const &fileName)
:
Stat(fileName, "") // only a filename
{}
Stat(std::string const &fileName, std::string const &searchPath)
:
d_filename(fileName),
d_searchPath(searchPath)
{
// remaining actions to be performed by the constructor
}
};
)
bf(C++) allows static const integral data members to be initialized within
the hi(data member: initialization) class interfaces (cf. chapter
ref(StaticDataFun)). The i(C++11) standard adds to this the facility to define
default initializations for plain data members in class interfaces (these data
members may or may not be tt(const) or of integral types, but (of course) they
cannot be reference data members).
These default initializations may be overruled by constructors. E.g., if
the class tt(Stat) uses a data member tt(bool d_hasPath) which is tt(false) by
default but the third constructor (see above) should initialize it to tt(true)
then the following approach is possible:
verb(
class Stat
{
bool d_hasPath = false;
public:
Stat(std::string const &fileName, std::string const &searchPath)
:
d_hasPath(true) // overrule the interface-specified
// value
{}
};
)
Here tt(d_hasPath) receives its value only once: it's always initialized
to tt(false) except when the shown constructor is used in which case it is
initialized to tt(true).
|