[C++] C++11新特性之explicit关键字

参考

C++提供了关键字explicit,可以阻止不应该允许的经过转换构造函数进行的隐式转换的发生,声明为explicit的构造函数不能在隐式转换中使用。
C++中,只有一个参数的构造函数(或者除了第一个参数外其余参数都有默认值的多参构造函数), 承担了两个角色。

  • 一是构造
  • 二是默认且隐含的类型转换操作符
    所以,在我们写下如 a = b,这样的代码,且恰好b的类型正好是a单参数构造器的参数类型,这时候编译器就自动调用这个构造器,创建一个a的对象

C++中的explicit关键字只能用于修饰只有一个参数的类构造函数,作用是表明该构造函数是显式的,而非隐式的

与explicit对应的关键字是implicit,意思是隐藏的,类构造函数默认情况下即声明为implicit(隐式的)

只能在类内声明构造函数时使用explicit关键字

显式构造函数和隐式构造函数的区别

// 没有使用explicit关键字的类声明, 即默认为隐式声明
class CxString {  
public:
    CxString(int size) {  
        _size = size;//string的预设大小  
        _pstr = malloc(size + 1);//分配string的内存  
        memset(_pstr, 0, size + 1);//初始化函数,在一段内存块中填充某个给定的值  
    }  
    CxString(const char *p) {  
        int size = strlen(p);  
        _pstr = malloc(size + 1);//分配string的内存  
        strcpy(_pstr, p);//复制字符串  
        _size = strlen(_pstr);  
    }  
    // 析构函数这里不讨论, 省略...
private:
    char *_pstr;  
    int _size;  
};  
  
    // 下面是调用:  
    CxString string1(24);//这样是OK的, 为CxString预分配24字节的大小的内存  
    CxString string2 = 10;//这样是OK的, 为CxString预分配10字节的大小的内存  
    CxString string3;//这样是不行的, 因为没有默认构造函数, 错误为: “CxString”: 没有合适的默认构造函数可用  
    CxString string4("aaaa");//这样是OK的  
    CxString string5 = "bbb";//这样也是OK的, 调用的是CxString(const char *p)  
    CxString string6 = 'c';//这样也是OK的, 其实调用的是CxString(int size), 且size等于'c'的ascii码  
    string1 = 2;//这样也是OK的, 为CxString预分配2字节的大小的内存  
    string2 = 3;//这样也是OK的, 为CxString预分配3字节的大小的内存  
    string3 = string1;//这样也是OK的, 至少编译是没问题的, 但是如果析构函数里用free释放_pstr内存指针的时候可能会报错, 完整的代码必须重载运算符"=", 并在其中处理内存释放  
  • 注意CxString string2 = 10这句

    发生隐式转换的一种情况是执行拷贝形式的初始化时(使用=)

    在C++中,如果构造函数只有一个参数时,那么编译的时候会有一个缺省的转换操作,将该构造函数对应数据类型的数据转换为该类对象。

    也就是说CxString string2 = 10;这段代码,编译器自动将整型转换为CxString类对象,实际上等同于下面的操作:

    CxString string2(10);  
    或  
    CxString temp(10);  
    CxString string2 = temp; 
    

    但是上面代码中的_size代表的是字符串内存分配的大小,那么调用CxString string2 = 10;和CxString string6 = ‘c’;就显得不伦不类了,而且容易让人疑惑。

    使用explicit关键字,阻止这种方法。

    当我们使用explicit关键字声明构造函数时,只能以直接初始化的形式显式的使用

对上述代码修改

// 使用关键字explicit的类声明, 显示转换
class CxString {  
public:   
    explicit CxString(int size)  
    {  
        _size = size;//string的预设大小  
        _pstr = malloc(size + 1);//分配string的内存  
        memset(_pstr, 0, size + 1);//初始化函数,在一段内存块中填充某个给定的值 
    }  
    CxString(const char *p)  
    {  
        int size = strlen(p);  
        _pstr = malloc(size + 1);//分配string的内存  
        strcpy(_pstr, p);//复制字符串  
        _size = strlen(_pstr);  
    }
private:
    char *_pstr;  
    int _size; 
};  
  
    // 下面是调用:  
    CxString string1(24);//这样是OK的  
    CxString string2 = 10;//这样是不行的, 因为explicit关键字取消了隐式转换  
    CxString string3;//这样是不行的, 因为没有默认构造函数  
    CxString string4("aaaa");//这样是OK的  
    CxString string5 = "bbb";//这样也是OK的, 调用的是CxString(const char *p)  
    CxString string6 = 'c';//这样是不行的, 其实调用的是CxString(int size), 且size等于'c'的ascii码, 但explicit关键字取消了隐式转换  
    string1 = 2;//这样也是不行的, 因为取消了隐式转换  
    string2 = 3;//这样也是不行的, 因为取消了隐式转换  
    string3 = string1;//这样也是不行的, 因为取消了隐式转换, 除非类实现操作符"="的重载  
  • explicit关键字的作用就是防止类构造函数的隐式自动转换
  • explicit关键字只对有一个参数的类构造函数有效,如果类构造函数参数大于或等于两个,是不会产生隐式转换的,所以explicit关键字也就无效了,有一种特殊情况,当除了第一个参数以外的其他参数都是默认值的时候,explicit关键字依然有效

例外情况

除了第一个参数以外的其他参数都是默认值的时候,explicit关键字依然有效,此时当调用构造函数时只传入一个参数,等效于只有一个参数的类构造函数

//使用关键字explicit声明
class CxString {  
public:    
    explicit CxString(int size, int flag = 0) {  
        _flag = flag;  
        _size = size;//string的预设大小
        _pstr = malloc(size + 1);//分配string的内存  
        memset(_pstr, 0, size + 1);//初始化函数,在一段内存块中填充某个给定的值
    }  
    CxString(const char *p) {  
        int size = strlen(p);  
        _pstr = malloc(size + 1);//分配string的内存  
        strcpy(_pstr, p);//复制字符串  
        _size = strlen(_pstr);    
    }
private:
    char *_pstr;  
    int _size;
    int _flag;
};  
  
    // 下面是调用:  
    CxString string1(24);//这样是OK的  
    CxString string2 = 10;//这样是不行的, 因为explicit关键字取消了隐式转换  
    CxString string3;//这样是不行的, 因为没有默认构造函数  
    string1 = 2;//这样也是不行的, 因为取消了隐式转换  
    string2 = 3;//这样也是不行的, 因为取消了隐式转换  
    string3 = string1;//这样也是不行的, 因为取消了隐式转换, 除非类实现操作符"="的重载  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值