The so-called smart pointer is an object that acts like a pointer and provides functions that the pointer does not have.
One good thing about real pointers is that implicit conversion is supported. The derived class pointer can be implicitly converted to a base class pointer. The pointer to the non-const object can be converted to the const object. Below are some transformations that occur in the three-tier inheritance system:
Class top {...};
Class middle: Public top {...};
Class bottom: public middle {...};
Top * pt1 = new middle; // convert middle * to top *
Top * pt2 = new bottom; // convert bottom * to top *
Const top * pct2 = pt1; // convert top * to const top *
However, it is a bit difficult to simulate the above conversions in a user-defined smart pointer. We hope the following code can be compiled:
Smartptr <top> pt1 = smartptr <middle> (New Middle); // convert smartptr <middle> to smartptr <top>
Smartptr <top> pt2 = smartptr <bottom> (new bottom); // convert smartptr <bottom> to smartptr <top>
Smartptr <const top> pct2 = pt1; // convert smartptr <top> to smartptr <const top>
However, there is no inherent relationship between different entities of the same template (if B has a base-derived relationship, D has a template, respectively, the two generated geometries do not have a base-derived relationship. Therefore, the compiler regards smartptr <middle> and smartptr <top> as completely different classes. To obtain the conversion capability between the expected smartptr classes, we must write them explicitly.
Template and generic programming (generic programming)
Instead of writing a constructor, we need to construct a smartptr <top> Based on a smartptr <middle> or a smartptr <bottom>. Instead, write a construction template for it. This template is member function templates (often referred to as member templates). Its function is to generate a function for the class:
Template <typename T>
Class smartptr {
Public:
Template <typename u> // member Template
Smartptr (const smartptr <u> & other); // to generate the copy constructor
};
The code above means that any type T and any type U, you can generate a smartptr according to smarptr <u> -- Because smartptr <t> has a constructor that accepts a smartptr <u> parameter. This type of constructor creates object T through object U (for example, creates a smartptr according to object smartptr <u>), which is called generalized copy constructor.
It is not declared as explicit, and it is deliberate. In the templated constructor, explicit is omitted to follow implicit conversion.
After the declaration is completed, we must select or delete the member function group created by this member template from some aspects. We want to create a smartptr <top> Based on a smartptr, but do not want to create a smartptr <bottom> Based on a smartptr <top>, because it is contradictory to public inheritance, and you do not want to create a smartptr <int> Based on a smartptr <double>, in reality, there is no implicit conversion behavior for "converting double * into int.
The Code restricts the conversion behavior so that it meets our expectations:
Template <typename T>
Class smartptr {
Template <typename u>
Smartptr (const smartptr <u> & other)
: Heldptr (other. Get () {...} // initialize the heldptr of this with the heldptr of other
T * Get () const {return heldptr ;}
PRIVATE:
T * heldptr; // the built-in (original) pointer held
};
In the member Initial Value column, the pointer initialization type of type U * Is T * member variable, this action can be compiled only when "an implicit conversion can convert a u * pointer to a T * Pointer", which is exactly what we want. Smartptr <t> has a generalized copy constructor. This constructor is compiled only when the obtained real parameters belong to an appropriate (compatible) type.
Member function templates is not limited to constructor functions. They often assume another role that supports value assignment. For example, shared_ptr of tr1:
Template <class T>
Class shared_ptr {
Public:
Template <class Y> // constructed from any compatible
Explicit shared_ptr (y * P); // built-in pointer
Template <class Y>
Shared_ptr (shared_ptr <Y> const & R); // or shared_ptr
Template <class Y>
Explicit shared_ptr (weak_ptr <Y> const & R); // or weak_ptr
Template <class Y>
Explicit shared_ptr (auto_ptr <Y> & R); // or auto_ptr
Template <class Y> // value assignment comes from any compatible
Shared_ptr & operator = (shared_ptr <Y> const & R); // shared_ptr
Template <class Y>
Shared_ptr & operator = (pai_ptr <Y> & R); // or auto_ptr
};
Except for the generalized copy constructor, the above constructor is explicit, which means that implicit conversion from a shared_ptr type to another shared_ptr type is allowed, however, implicit conversions from a built-in type pointer or from other smart pointer types are not recognized as auto_ptr and are not declared as const, because as stated in Clause 13, when you copy an auto_ptr, they have actually been modified.
Member function templates does not change the basic language rules. Article 5 said that the compiler may generate four member functions for us, two of which are the copy constructor and the copy assignment operator. Now, shared_ptr declares a generalized copy constructor. Obviously, once the type T and Y are the same, the generalized copy constructor will become a "normal" copy constructor. Then, will the compiler generate a copy constructor for shared_ptr? Or when a shared_ptr object expands the constructor behavior based on another shared_ptr object of the same type, will the compiler generate the generalized copy constructor template?
Member templates does not change the language rules, but the language rules say that if the program requires a copy constructor, but you do not declare it, the compiler will generate a secret for you. Declaring a generalized copy constructor (a member template) does not prevent the compiler from generating their own copy constructor (a non-template). Therefore, if you want to control all aspects of the copy constructor, you must declare both the generalized copy constructor and the "normal" copy constructor. The same rule applies to the value assignment operator.
Template <class T>
Class shared_ptr {
Public:
Shared_ptr (shared_ptr const & R); // copy constructor
Template <class Y>
Shared_ptr (shared_ptr <Y> const & R); // generalized copy constructor
Shared_ptr & operator = (shared_ptr const & R); // copy assignment
Template <class Y>
Shared_ptr & operator = (shared_ptr <Y> const & R); // generalized copy assignment
};