C++类的隐式类型转换和explicit关键字

C++类的隐式类型转换和explicit关键字

C++类的隐式类型转换

当我们为一个C++ class定义单参数的构造函数时,该构造函数实际上也同时定义了隐式的类型转换,即将参数类型转换为所定义的class类型,这个隐式的转换函数称为转换构造函数。如下,定义一个Person.h中定义一个Person类

#ifndef PERSON_H
#define PERSON_H

#include <string>

class Person
{
public:
    Person(std::string name) : name_(name) {}
    std::string getName()
    {
        return name_;
    }

private:
    std::string name_;
};

#endif

在main.cpp中定义这个类的对象,并且打印对象的name_。

#include <iostream>
#include "Person.h"

using namespace std;
int main()
{
    
    string nm = "Jack";
    Person Jack(nm);//显式由string对象初始化Person对象
    std::cout<<Jack.getName()<<std::endl;

    string rs = "Rose";
    Person B = rs;//隐式类型转换,将string对象转换为一个Person临时对象,并拷贝构造给对象B
    std::cout<<B.getName()<<std::endl;

    return 0;
}

编译运行都没有问题

编译结果:
ubuntu:~/exception_test/build$ make -j10
Scanning dependencies of target ex_test
[ 50%] Building CXX object CMakeFiles/ex_test.dir/main.cpp.o
[100%] Linking CXX executable ex_test
[100%] Built target ex_test
运行结果:
ubuntu:~/exception_test/build$ ./ex_test 
Jack
Rose

添加一个Person C,编译运行都OK。

#include <iostream>
#include "Person.h"

using namespace std;
int main()
{
    string nm = "Jack";
    Person Jack(nm);
    std::cout<<Jack.getName()<<std::endl;

    string rs = "Rose";
    Person B = rs;
    std::cout<<B.getName()<<std::endl;

    Person C("LiLei");//LiLei是char型字符串,隐式的转换为string类型,string类型又显式的初始化					   //了C
    return 0;
}

再添加一个Person D

#include <iostream>
#include "Person.h"

using namespace std;
int main()
{
    string nm = "Jack";
    Person Jack(nm);
    std::cout<<Jack.getName()<<std::endl;

    string rs = "Rose";
    Person B = rs;
    std::cout<<B.getName()<<std::endl;

    Person C("LiLei");
    Person D = "Trump";
    return 0;
}

此时编译编译就出问题。看来这个Trump是来捣乱的啊!Why? 编译log如下:log的5~7行确实显示Trump的问题。

ubuntu:~/exception_test/build$ make -j10
Scanning dependencies of target ex_test
[ 50%] Building CXX object CMakeFiles/ex_test.dir/main.cpp.o
~/exception_test/main.cpp: In function ‘int main()’:
~/exception_test/main.cpp:16:16: error: conversion from ‘const char [6]’ to non-scalar type ‘Person’ requested
     Person D = "Trump";
                ^
CMakeFiles/ex_test.dir/build.make:62: recipe for target 'CMakeFiles/ex_test.dir/main.cpp.o' failed
make[2]: *** [CMakeFiles/ex_test.dir/main.cpp.o] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/ex_test.dir/all' failed
make[1]: *** [CMakeFiles/ex_test.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2

这是因为C++只能进行一次隐式类型转换。string 类型有一个接收一个const char *型的参数构造函数,该函数不是explicit的。因此有“LiLei”隐式的转换为string对象,再由string对象初始化了Person C对象是没有问题的。但是Person D需要执行两次隐式类型转换,所以报错了。

explicit关键字

explicit关键字可以避免编译器为我们定义隐式类型转换函数。如下在构造函数前添加了explicit关键字。

#ifndef PERSON_H
#define PERSON_H

#include <string>

class Person
{
public:
    //添加了explicit关键字
    explicit Person(std::string name) : name_(name) {}
    std::string getName()
    {
        return name_;
    }

private:
    std::string name_;
};

#endif

编译如下的代码就会报错了

#include <iostream>
#include "Person.h"

using namespace std;
int main()
{
    string nm = "Jack";
    Person Jack(nm);
    std::cout<<Jack.getName()<<std::endl;

    string rs = "Rose";
    Person B = rs;
    std::cout<<B.getName()<<std::endl;

    return 0;
}

编译log如下:显示Person B出错。添加了explicit关键字后类的初始化就只能显式的初始化了。

ubuntu:~/exception_test/build$ make -j10
Scanning dependencies of target ex_test
[ 50%] Building CXX object CMakeFiles/ex_test.dir/main.cpp.o
~/exception_test/main.cpp: In function ‘int main()’:
~/exception_test/main.cpp:12:16: error: conversion from ‘std::__cxx11::string {aka std::__cxx11::basic_string<char>}’ to non-scalar type ‘Person’ requested
     Person B = rs;
                ^
CMakeFiles/ex_test.dir/build.make:62: recipe for target 'CMakeFiles/ex_test.dir/main.cpp.o' failed
make[2]: *** [CMakeFiles/ex_test.dir/main.cpp.o] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/ex_test.dir/all' failed
make[1]: *** [CMakeFiles/ex_test.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2

explicit关键字只需要在函数声明的地方添加上就可以了,不要在函数定义的地方再次添加

google的c++规范中提到explicit的优点是可以避免不合时宜的类型变换。所以google约定所有单参数的构造函数都必须是显示的,只有极少数情况下拷贝构造函数可以不声明称explicit。例如作为其他类的透明包装器的类。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值