概述
本文参考了以下两篇博客:[C++笔记(1)explicit构造函数], [explicit在构造函数的使用 及 详解],只是对自己的学习做一个简要的记录。
问题引入
explicit修饰符的作用是什么,什么时候用?
explicit的主要用法就是放在单参数的构造函数中,防止隐式转换,出现歧义.
因为,只有一个参数的构造函数也定义了一个隐式转换,将该构造函数对应参数的数据类型的数据转换为该类对象。如下面代码所示:
#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;
}
上面这段代码看起来还没有什么问题,但是再看看下面的代码:
#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转换成了一个字符串。
MyString s4 = 8; // 单参数构造函数,隐式定义
问题解决
通过对单参数的构造函数加explicit修饰符,防止隐式转换,出现语义歧义。
#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;
}
转换构造函数的细节问题
想看以下转换构造函数在不进行优化时的具体行为。是否还是要生成临时对象。
#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修饰符所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复