Effective C++——注意泛化构造函数(模板嵌套)涉及隐式转换

  1. 泛化构造函数本质并不是构造函数,而是类型转换函数,并不能替代构造函数,当U与T相等时,会走默认构造函数,如果没有,则编译器会生成一个。
  2. 注意隐式转换,如果不支持隐形转换,则加explicit
  3. 泛化构造主要有两个功能,一个是隐式转换,一个是显式调用
  4. =delete的作用是禁止拷贝构造和禁止拷贝赋值,如果delete掉后,那么显式和隐式都挂掉,具体见图2
  5. 条款45,shared_ptr就是使用了该特性
  6. 注意move构造和构造的区别
  7. class A{A(const B&);}这里就是可以用B构造出A,也是拷贝构造
  8. testSH< int> t3 =testSH< float>(new int);这里只调用一次构造,并不会走进拷贝构造,因为如果=右边进行构造,其结果是左右两边类型一致,那么我认为会走编译器的默认构造函数,这就是为什么=delete后,会报错!(泛化构造隐式转换也是同理)。但是如果如testSH< int> t3 =testSH< float>(new int);,就必须先构造,再拷贝构造,因为一次构造后类型不一致,需要再转一次!
    下图代码,分别为泛化的构造,拷贝构造,拷贝赋值!其中构造不支持隐式转换

具体代码分析

```cpp
template<class T>
class testSH{
    public:
    int i;
    //testSH(const T* _p)=delete;
   	template<class D>
    explict testSH(const D* _p) //不支持隐形转换
    {
        cout<<"????"<<endl;
    }
    //template<>
     //testSH(T* _p){cout<<"$$$$"<<endl;}
//     testSH& operator=(const testSH& tt){
//         cout<<"@@@@"<<endl;
//         return *this;
//     }
    template<class D>
    testSH& operator=(const testSH<D>& tt)
    {
        cout<<"####"<<endl;
        return *this;
    }
    //testSH(const testSH& t){cout<<"!!!!"<<endl;};
    //testSH(const testSH& t)=delete;
    
    template<class U>
    testSH(const testSH<U>& t){cout<<"****"<<endl;};
    //testSH& operator=(const testSH&)=delete;
};
//template<class T>
void fun(testSH<int>* a){};
int main()
{
    //testSH<int> t = new int;  //error1
    //fun(new int); //error2
    testSH<int> t1(new int);
    testSH<int> t3 =testSH<float>(new int);
    testSH<int> t4 =new float; //隐形转换,注意这里实际进行了构造,并不会再拷贝构造,但是
    //如果testSH(const testSH& t)=delete;则无法进行
    
    testSH<int> t2(new int);
    t1 = testSH<float>(new int);
    fun(new int);

在这里插入图片描述
上图所示,如果testSH的拷贝构造=delete,那么下面泛化拷贝构造也一并失效

template<class T>
class testSH{
    public:
    int i;
    //testSH(const T* _p)=delete;
    template<class D>
     testSH(const D* _p)
    {
        cout<<"????"<<endl;
    }
    //template<>
     //testSH(T* _p){cout<<"$$$$"<<endl;}
//     testSH& operator=(const testSH& tt){
//         cout<<"@@@@"<<endl;
//         return *this;
//     } 
    template<class D>
    testSH& operator=(const testSH<D>& tt)
    {
        cout<<"####"<<endl;
        return *this;
    }
    //testSH(const testSH& t){cout<<"!!!!"<<endl;};
    //testSH(const testSH& t)=delete;

    template<class U>
    testSH(const testSH<U>& t){cout<<"****"<<endl;};
    //testSH& operator=(const testSH&)=delete;
};
//template<class T>
void fun(testSH<int>* a){};
int main()
{
    shared<int> sp1 (new int);
    //shared<int> p = sp1;
    //testSH<int> t = new int;  //error1
    //fun(new int); //error2
    testSH<int> t1(new int);
    testSH<int> t3 =testSH<float>(new int);

这里的t3,需要先构造成float,再拷贝构造,因为必须搞成类型一致才行!

隐式调用

类型转换构造函数,它可以把一个Fuck< U>的类型转换成Fuck,也就是模版参数不同的模版类。这个应用就是比如说我有一个int类型的数组,要用来传递给一个double类型数组的参数,这个构造函数就可以完成这个转换,即可以显示调用,也可以隐式调用。包括:

Fuck (const test& t);
template<typename U> Fuck (const Fuck<U>& t);

Fuck<int> int_f;
Fuck<double> double_f(int_f);      // 显示调用
Fuck<double> double_f2 = int_f;    // 显示调用2
int my_func(const Fuck<double> & double_f);
my_func(Fuck<double>(int_f));      // 显示调用3
my_func(int_f);                    // 隐式调用

template<typename T>
T my_func2(T, const Fuck<T>&);

my_func2<double>(0.0, int_f);      // 隐式调用2

猜你喜欢

转载自blog.csdn.net/weixin_44537992/article/details/105160880