面向对象规则中,在对象生成的时候,存在隐式和显式两个方式。隐式调用构造函数,使得调用很灵活。但是,有些情况必须显式,此时可以选择“必须显式”的模式。explicit就是限定构造函数,使其只能显式调用,不能隐式转换的关键词。
看一下这种隐式类型转换是怎么发生的吧.
- #include
- using namespace std;
-
- class Point {
- public:
- int x, y;
- Point(int x = 0, int y = 0)
- : x(x), y(y) {}
- };
-
- void displayPoint(const Point& p)
- {
- std::cout << "(" << p.x << "," << p.y << ")" << std::endl;
- }
-
- int main()
- {
- displayPoint(1);
- Point p=30 ;
- displayPoint(p );
- }
以上的隐式转化有两个:
1) displayPoint(1); 此处的“1”是这样得到的:
从" const Point& "知道,此处的“1”是调用Point(1)获得。
2) Point p=30 ;此处的p先调用Point(3)完成。
- class CxString // 没有使用explicit关键字的类声明, 即默认为隐式声明
- {
- public:
- char *_pstr;
- int _size;
- 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);
- }
- // 析构函数这里不讨论, 省略...
- };
因此:
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内存指针的时候可能会报错, 完整的代码必须重载运算符"=", 并在其中处理内存释放
- class Test1
- {
- public:
- Test1(int n)
- {
- num=n;
- }//普通构造函数
- private:
- int num;
- };
- class Test2
- {
- public:
- explicit Test2(int n)
- {
- num=n;
- }//explicit(显式)构造函数
- private:
- int num;
- };
- int main()
- {
- Test1 t1=12;//隐式调用其构造函数,成功
- Test2 t2=12;//编译错误,不能隐式调用其构造函数
- Test2 t2(12);//显式调用成功
- return 0;
- }
Test1的构造函数带一个int型的参数,代码23行会隐式转换成调用Test1的这个构造函数。而Test2的构造函数被声明为explicit(显式),这表示不能通过隐式转换来调用这个构造函数,因此代码24行会出现编译错误。
普通构造函数能够被隐式调用。而explicit构造函数只能被显式调用。