In order to implicitly convert all compatible types for a template class, we neet not a constructor function but a constructor template - member functoin templates that generate member functions of a class.
Implicit conversion is a big convenient advantage offered by pointers: derived class pointers convert into base class pointers implicitly, pointers to non-const
objects convert into pointers to const
implicitly, etc. For a three-level hierarchy, following code makes perfect sense:
|
|
In the world of template, we’d really like to emulate such conversions for our user-defined smart pointer classes:
|
|
However, there’s no inherent relationship among different instantiations of the same template, so compilers view SmartPtr<Middle>
and SmartPtr<Top>
as completely different classes. We need to write smart pointer constructors that is not only able to construct SmartPtr<Top>
from SmartPtr<Middle>
, but also capable to convert any compatible types in the hierarchy (we may extend the hierarchy in the future and add class BelowBottom: public Bottom
). In principle, such constructors are countless.
Considering the fact that a template can be instantiated to generate an unlimited number of functions, what we need here is not a constructor function, but a constructor template, the member function templates (also known as member templates) that generate member functions of a class:
|
|
Constructors like this - ones that create one object from anothe object whose type is a different instantiation of the same template (e.g., create a SmartPtr<T>
from a SmartPtr<U>
) - are known as generalized copy constructors.
However, this member template will generate more member functions than we need: as declared, it is possible to create a SmartPtr<Bottom>
from a SmartPtr<Top>
, which is contrary to the meaning of public inheritance (item 32). We need to restrict the conversions to those we want:
|
|
Since we initialize SmartPtr<T>
’s data member of type T*
with the pointer of type U*
held by SmartPtr<U>
, the code above will compile only if there is an implicit conversion from a U*
pointer to a T*
pointer, and this is exactly what we want.
Apart from constructors, we can also apply member function tmeplates to assignment. A good example is from TR1’s shared_ptr
(item 13):
|
|
Note that
- the generalized copy constructor is not declared
explicit
in order to support implicit conversion from one type ofshared_ptr
to another. - All other constructors are
explicit
, so implicit conversion from a built-in pointer or other smart pointer type is not permitted (explicit conversion via a cast is okey). auto_ptr
passed totr1::shared_ptr
constructors and assignment operators are not declaredconst
, becauseauto_ptr
will be modifies when they’re copyed (item 13).- both a generalized copy constructor (and assignment) as well as the “normal” copy constructor (and copy assignment) are declared, because declaring a generalized copy constructor (a member template) in a class doesn’t keep compilers from generating their own copy constructor (a non-template version), so if we want to control all aspect of copy construction, we declare both.