我是靠谱客的博主 踏实白昼,这篇文章主要介绍c++函数explicit修饰符,现在分享给大家,希望可以做个参考。

本文参考了以下两篇博客:[C++笔记(1)explicit构造函数], [explicit在构造函数的使用 及 详解],只是对自己的学习做一个简要的记录。

问题引入

explicit修饰符的作用是什么,什么时候用?

explicit的主要用法就是放在单参数的构造函数中,防止隐式转换,出现歧义.

因为,只有一个参数的构造函数也定义了一个隐式转换,将该构造函数对应参数的数据类型的数据转换为该类对象。如下面代码所示:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream> #include <cstring> class MyString{ public: MyString( const char* str ){ int s_len = strlen(str); ptr_ = new char[ s_len + 1 ]; strncpy( ptr_, str, s_len + 1); } friend std::ostream& operator<<( std::ostream& os, const MyString& s ); private: char* ptr_; int n_; }; std::ostream& operator<<( std::ostream& os, const MyString& s ){ if( os ){ os << s.ptr_; } return os; } int main(){ MyString s1( "hello, world!" ); // 单参数构造函数,显示定义 MyString s2 = "hello, world!"; // 但参数构造函数,隐式转换 std::cout << s1 << std::endl; std::cout << s2 << std::endl; }

上面这段代码看起来还没有什么问题,但是再看看下面的代码:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream> #include <cstring> class MyString{ public: MyString( int n ) : n_(n) { ptr_ = new char[n_]; } MyString( const char* str ){ int s_len = strlen(str); ptr_ = new char[ s_len + 1 ]; strncpy( ptr_, str, s_len + 1); } friend std::ostream& operator<<( std::ostream& os, const MyString& s ); private: char* ptr_; int n_; }; std::ostream& operator<<( std::ostream& os, const MyString& s ){ if( os ){ os << s.ptr_; } return os; } int main(){ MyString s1( "hello, world!" ); MyString s2 = "hello, world!"; std::cout << s1 << std::endl; std::cout << s2 << std::endl; MyString s3(8); // 单参数构造函数,显示定义 MyString s4 = 8; // 单参数构造函数,隐式定义 std::cout << s3 << std::endl; std::cout << s4 << std::endl; }

对于下面的这种写法,容易让人产生误解,这个接口本身的含义是构造含有8个字符的字符串,但是下面的这种写法感觉像是把数字8转换成了一个字符串。

复制代码
1
MyString s4 = 8; // 单参数构造函数,隐式定义

问题解决

通过对单参数的构造函数加explicit修饰符,防止隐式转换,出现语义歧义。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream> #include <cstring> class MyString{ public: explicit MyString( int n ) : n_(n) { // 此时,单参数构造函数无法进行隐式转换 ptr_ = new char[n_]; } MyString( const char* str ){ int s_len = strlen(str); ptr_ = new char[ s_len + 1 ]; strncpy( ptr_, str, s_len + 1); } friend std::ostream& operator<<( std::ostream& os, const MyString& s ); private: char* ptr_; int n_; }; std::ostream& operator<<( std::ostream& os, const MyString& s ){ if( os ){ os << s.ptr_; } return os; } int main(){ MyString s1( "hello, world!" ); MyString s2 = "hello, world!"; std::cout << s1 << std::endl; std::cout << s2 << std::endl; MyString s3(8); MyString s4 = 8; std::cout << s3 << std::endl; std::cout << s4 << std::endl; }

转换构造函数的细节问题

想看以下转换构造函数在不进行优化时的具体行为。是否还是要生成临时对象。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <iostream> #include <cstring> class MyString{ public: typedef size_t size_type; public: MyString(){} explicit MyString( int n, char ch = 0 ) : n_(n) { ptr_ = new char[n_ + 1]; for( int i = 0; i < n_; ++i ){ ptr_[i] = ch; } ptr_[n_] = 0; } MyString( const char* str ){ n_ = strlen(str); ptr_ = new char[ n_ + 1 ]; strncpy( ptr_, str, n_ + 1); std::cout << "conversion constructor called!" << std::endl; } MyString( const MyString& rhs ){ n_ = rhs.size(); ptr_ = new char[n_ + 1]; for( int i = 0; i < n_; ++i ){ ptr_[i] = rhs.ptr_[i]; } ptr_[n_] = 0; std::cout << "copy constructor called!" << std::endl; } MyString& operator=( const MyString& rhs ){ if( &rhs != this ){ delete [] ptr_; n_ = rhs.size(); ptr_ = new char[n_ + 1]; for( int i = 0; i < n_; ++i ){ ptr_[i] = rhs.ptr_[i]; } ptr_[n_] = 0; } std::cout << "assignment function called!" << std::endl; return *this; } ~MyString(){ delete [] ptr_; std::cout << "destructor called!" << std::endl; } size_type size() const { return n_; } friend std::ostream& operator<<( std::ostream& os, const MyString& s ); private: char* ptr_; int n_; }; std::ostream& operator<<( std::ostream& os, const MyString& s ){ if( os ){ os << s.ptr_; } return os; } int main(){ MyString s2 = "hello, world!"; std::cout << s2 << std::endl; } /* 程序输出: conversion constructor called!// 转换构造函数生成临时对象 copy constructor called!// 临时对象通过拷贝构造函数生成左值对象 destructor called!//临时对象析构 hello, world! destructor called!//左值对象析构 */

最后

以上就是踏实白昼最近收集整理的关于c++函数explicit修饰符的全部内容,更多相关c++函数explicit修饰符内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(64)

评论列表共有 0 条评论

立即
投稿
返回
顶部