explicit 和operatorjs隐式类型转换转换冲突吗

C#入门教程:使用explicit,implicit做用户定义的类型转换转换 - 为程序员服务
为程序员服务
C#入门教程:使用explicit,implicit做用户定义的类型转换转换
C# 允许程序员在类或结构上声明转换,以便可以使类或结构与其他类或结构或者基本类型相互进行转换。转换的定义方法类似于运算符,并根据它们所转换到的类型命名。
在 C# 中,可以将转换声明为 implicit(需要时自动转换)或 explicit(需要调用转换)。所有转换都必须为 static,并且必须采用在其上定义转换的类型,或返回该类型。
本教程介绍两个示例。第一个示例展示如何声明和使用转换,第二个示例演示结构之间的转换。
本示例中声明了一个 RomanNumeral 类型,并定义了与该类型之间的若干转换。
// conversion.cs
struct RomanNumeral
public RomanNumeral(int value)
this.value =
// Declare a conversion from an int to a RomanNumeral. Note the
// the use of the operator keyword. This is a conversion
// operator named RomanNumeral:
static public implicit operator RomanNumeral(int value)
// Note that because RomanNumeral is declared as a struct,
// calling new on the struct merely calls the constructor
// rather than allocating an object on the heap:
return new RomanNumeral(value);
// Declare an explicit conversion from a RomanNumeral to an int:
static public explicit operator int(RomanNumeral roman)
return roman.
// Declare an implicit conversion from a RomanNumeral to
// a string:
static public implicit operator string(RomanNumeral roman)
return(&Conversion not yet implemented&);
class Test
static public void Main()
numeral = 10;
// Call the explicit conversion from numeral to int. Because it is
// an explicit conversion, a cast must be used:
Console.WriteLine((int)numeral);
// Call the implicit conversion to string. Because there is no
// cast, the implicit conversion to string is the only
// conversion that is considered:
Console.WriteLine(numeral);
// Call the explicit conversion from numeral to int and
// then the explicit conversion from int to short:
short s = (short)
Console.WriteLine(s);
Conversion not yet implemented
本示例定义 RomanNumeral 和 BinaryNumeral 两个结构,并演示二者之间的转换。
// structconversion.cs
struct RomanNumeral
public RomanNumeral(int value)
this.value =
static public implicit operator RomanNumeral(int value)
return new RomanNumeral(value);
static public implicit operator RomanNumeral(BinaryNumeral binary)
return new RomanNumeral((int)binary);
static public explicit operator int(RomanNumeral roman)
return roman.
static public implicit operator string(RomanNumeral roman)
return(&Conversion not yet implemented&);
struct BinaryNumeral
public BinaryNumeral(int value)
this.value =
static public implicit operator BinaryNumeral(int value)
return new BinaryNumeral(value);
static public implicit operator string(BinaryNumeral binary)
return(&Conversion not yet implemented&);
static public explicit operator int(BinaryNumeral binary)
return(binary.value);
class Test
static public void Main()
roman = 10;
// Perform a conversion from a RomanNumeral to a
// BinaryNumeral:
binary = (BinaryNumeral)(int)
// Performs a conversion from a BinaryNumeral to a RomanNumeral.
// No cast is required:
Console.WriteLine((int)binary);
Console.WriteLine(binary);
Conversion not yet implemented
在上个示例中,语句
binary = (BinaryNumeral)(int)
执行从 RomanNumeral 到 BinaryNumeral 的转换。由于没有从 RomanNumeral 到 BinaryNumeral 的直接转换,所以使用一个转换将 RomanNumeral 转换为 int,并使用另一个转换将 int 转换为 BinaryNumeral。
另外,语句
执行从 BinaryNumeral 到 RomanNumeral 的转换。由于 RomanNumeral 定义了从 BinaryNumeral 的隐式转换,所以不需要转换。
您可能的代码
相关聚客文章
荣誉:1225
相关专栏文章explicit,implicit,operator 重载运算符_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
explicit,implicit,operator 重载运算符
&&C# 运算符重载 修饰符
你可能喜欢拒绝访问 |
| 百度云加速
请打开cookies.
此网站 () 的管理员禁止了您的访问。原因是您的访问包含了非浏览器特征(3af8-ua98).
重新安装浏览器,或使用别的浏览器温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
class MyClass{public:
MyClass( int num );}....MyClass obj = 10; //ok,convert int to MyClass在上面的代码中编译器自动将整型转换为MyClass类对象,实际上等同于下面的操作: MyClass temp(10);MyClass obj =上面的所有的操作即是所谓的"隐式转换"。如果要避免这种自动转换的功能,我们该怎么做呢?嘿嘿这就是关键字explicit的作用了,将类的构造函数声明为"显示",也就是在声明构造函数的时候前 面添加上explicit即可,这样就可以防止这种自动的转换操作,如果我们修改上面的MyClass类的构造函数为显示的,那么下面的代码就不能够编译通过了,如下所示:class MyClass { public:
explicit MyClass( int num ); } .... MyClass obj = 10; explicit作用: 在C++中,explicit关键字用来修饰类的构造函数,被修饰的构造函数的类,不能发生相应的隐式类型转换,只能以显示的方式进行类型转换。 explicit使用注意事项:
&&& *explicit 关键字只能用于类内部的构造函数声明上。
&&& *explicit 关键字作用于单个参数的构造函数。 &&& *在C++中,explicit关键字用来修饰类的构造函数,被修饰的构造函数的类,不能发生相应的隐式类型转换 例子: 未加explicit时的隐式类型转换 && 1. class Circle& && 2. {& && 3. public:& && 4.&&&& Circle(double r) : R(r) {}& && 5.&&&& Circle(int x, int y = 0) : X(x), Y(y) {}& && 6.&&&& Circle(const Circle& c) : R(c.R), X(c.X), Y(c.Y) {}& && 7. private:& && 8.&&&& double R;& && 9.&&&& int&&& X;& & 10.&&&& int&&& Y;& & 11. };& & 12.&& & 13. int _tmain(int argc, _TCHAR* argv[])& & 14. {& & 15. //发生隐式类型转换& & 16. //编译器会将它变成如下代码& & 17. //tmp = Circle(1.23)& & 18. //Circle A(tmp);& & 19. //tmp.~Circle();& & 20.&&&& Circle A = 1.23;&& & 21. //注意是int型的,调用的是Circle(int x, int y = 0)& & 22. //它虽然有2个参数,但后一个有默认值,任然能发生隐式转换& & 23.&&&& Circle B = 123;& & 24. //这个算隐式调用了拷贝构造函数& & 25.&&&& Circle C = A;& & 26.&&&&&& & 27.&&&& return 0;& & 28. }& 加了explicit关键字后,可防止以上隐式类型转换发生 && 1. class Circle& && 2. {& && 3. public:& && 4.&&&& explicit Circle(double r) : R(r) {}& && 5.&&&& explicit Circle(int x, int y = 0) : X(x), Y(y) {}& && 6.&&&& explicit Circle(const Circle& c) : R(c.R), X(c.X), Y(c.Y) {}& && 7. private:& && 8.&&&& double R;& && 9.&&&& int&&& X;& & 10.&&&& int&&& Y;& & 11. };& & 12.&& & 13. int _tmain(int argc, _TCHAR* argv[])& & 14. {& & 15. //一下3句,都会报错& & 16.&&&& //Circle A = 1.23;&& & 17.&&&& //Circle B = 123;& & 18.&&&& //Circle C = A;& & 19.&&&&&& & 20. //只能用显示的方式调用了& & 21. //未给拷贝构造函数加explicit之前可以这样& & 22.&&&&&&&&& Circle A = Circle(1.23);& & 23.&&&&&&&& Circle B = Circle(123);& & 24.&&&&&&&& Circle C = A;& & 25.&& & 26. //给拷贝构造函数加了explicit后只能这样了& & 27.&&&&&&&&& Circle A(1.23);& & 28.&&&&&&&& Circle B(123);& & 29.&&&&&&&& Circle C(A);& & 30.&&&& return 0;& & 31. }&那为何要防止隐式类型转换呢? 让编译器进行隐式类型转换所造成的弊端要大于它所带来的好处,所以除非你确实需要,不要定义类型转换函数。隐式类型转换的缺点:它们的存在将导致错误的发生。例如:class Rational {public:& ...& operator double()&&&&&&&&&&&&&&&&&& // 转换Rational类成double类型};在下面这种情况下,这个函数会被自动调用:Rational r(1, 2);&&&&&&&&&&&&&&&&&&&&&&&&&&& // r 的值是1/2&double d = 0.5 *&&&&&&&&&&&&&&&&&&&&&&&&& // 转换 r 到double,然后做乘法假设你有一个如上所述的Rational类,你想让该类拥有打印有理数对象的功能,就好像它是一个内置类型。因此,你可能会这么写:Rational r(1, 2);&cout &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // 应该打印出"1/2"当 编译器调用operator&&时,会发现没有这样的函数存在,但是它会试图找到一个合适的隐式类型转换顺序以使得函数调用正常运行。类型转 换顺序的规则定义是复杂的,但是在现在这种情况下,编译器会发现它们能调用Rational::operator double函数来把r转换为double类型。所以上述代码打印的结果是一个浮点数,而不是一个有理数。这简直是一个灾难,但是它表明了隐式类型转换的 缺点:它们的存在将导致错误的发生。解决方法是用不使用语法关键字的等同的函数来替代转换运算符。例如为了把Rational对象转换为double,用asDouble函数代替operator double函数:class Rational {public:& ...& double asDouble()&&&&&&&&&&&&&&&&&& //转变 Rational};&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // 成double这个成员函数能被显式调用:Rational r(1, 2);&cout &&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // 错误! Rationa对象没有operator&&&cout && r.asDouble();&&&&&&&&&&&&&&&&&& // 正确, 用double类型打印r通 过不声明运算符(operator)的方法,可以克服隐式类型转换运算符的缺点,但是单参数构造函数没有那么简单。毕竟,你确实想给调用者提供一个单参数 构造函数。同时你也希望防止编译器不加鉴别地调用这个构造函数。幸运的是,有一个方法可以让你鱼肉与熊掌兼得。事实上是两个方法:一是容易的方法,二是当 你的编译器不支持容易的方法时所必须使用的方法。&&& 容易的方法是利用一个最新编译器的特性,explicit关键字。为了解决隐式类型转换而特别引入的这个特性,它的使用方法很好理解。构造函数用explicit声明,如果这样做,编译器会拒绝为了隐式类型转换而调用构造函数。显式类型转换依然合法:template&class T&class Array {public:& ...& explicit Array(int size);&&&&&&&&&& // 注意使用"explicit"& ...};&Array&int& a(10);&&&&&&&&&&&&&&&& // 正确, explicit 构造函数在建立对象时能正常使用Array&int& b(10);&&&&&&&&&&&&&&& // 也正确&if (a == b[i]) ...&&&&&&&&&&&& // 错误! 没有办法隐式转换int 到 Array&int&&if (a == Array&int&(b[i])) ...&&&&&&& // 正确,显式从int到Array&int&转换(但是代码的逻辑不合理)if (a == static_cast& Array&int& &(b[i])) ...& //同样正确,同样不合理&if (a == (Array&int&)b[i]) ...&&&&&&& //C风格的转换也正确,但是逻辑 依旧不合理&&& 在例子里使用了static_cast(参见条款M2),两个“&”字符间的空格不能漏掉,如果这样写语句:if (a == static_cast&Array&int&&(b[i])) ...&&& 这是一个不同的含义的语句。因为C++编译器把“&&”做为一个符号来解释。在两个“&”间没有空格,语句会产生语法错误。&&& 如果你的编译器不支持explicit,你不得不回到不使用成为隐式类型转换函数的单参数构造函数。&&&&&&& 我前面说过复杂的规则决定哪一个隐式类型转换是合法的,哪一个是不合法的。这些规则中没有一个转换能够包含用户自定义类型(调用单参数构造函数或隐式类型转换运算符)。你能利用这个规则来正确构造你的类,使得对象能够正常构造,同时去掉你不想要的隐式类型转换。&&& 再来想一下数组模板,你需要用整形变量做为构造函数参数来确定数组大小,但是同时又必须防止从整数类型到临时数组对象的隐式类型转换。你要达到这个目的, 先要建立一个新类ArraySize。这个对象只有一个目的就是表示将要建立数组的大小。你必须修改Array的单参数构造函数,用一个 ArraySize对象来代替int。代码如下:template&class T&class Array {public:&& class ArraySize {&&&&&&&&&&&&&&&&&&& // 这个类是新的& public:&&& ArraySize(int numElements): theSize(numElements) {}&&& int size() const { return theS }&& private:&&& int theS& };&Array(int lowBound, int highBound);& Array(ArraySize size);&&&&&&&&&&&&&&&&& // 注意新的声明&...&};&&& 这里把ArraySize嵌套入Array中,为了强调它总是与Array一起使用。你也必须声明ArraySize为公有,为了让任何人都能使用它。&&& 想一下,当通过单参数构造函数定义Array对象,会发生什么样的事情:&&& Array&int& a(10);&&& 你的编译器要求用int参数调用Array&int&里的构造函数,但是没有这样的构造函数。编译器意识到它能从int参数转换成一个临时 ArraySize对象,ArraySize对象只是Array&int&构造函数所需要的,这样编译器进行了转换。函数调用(及其后的对象 建立)也就成功了。&&& 事实上你仍旧能够安心地构造Array对象,不过这样做能够使你避免类型转换。考虑一下以下代码:bool operator==( const Array&int&& lhs,&&&&&&&&&&&&&&&& const Array&int&& rhs);Array&int& a(10);Array&int& b(10);...for (int i = 0; i & 10; ++i)& if (a == b[i]) ...&&&&&&&&&&&&&&&& // 哎呦! "a" 应该是 "a[i]";&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // 现在是一个错误。&&& 为了调用operator==函数,编译器要求Array&int&对象在”==”右侧,但是不存在一个参数为int的单参数构造函数。而且 编译器无法把int转换成一个临时ArraySize对象然后通过这个临时对象建立必须的Array&int&对象,因为这将调用两个用户定 义(user-defined)的类型转换,一个从int到ArraySize,一个从ArraySize到Array&int&。这种转换 顺序被禁止的,所以当试图进行比较时编译器肯定会产生错误。
阅读(127)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
loftPermalink:'',
id:'fks_',
blogTitle:'c++中的explicit关键字及隐式类型转换',
blogAbstract:'
c++中的explicit关键字用来修饰类的构造函数,表明该构造函数是显式的,既然有\"显式\"那么必然就有\"隐式\",那么什么是显示而什么又是隐式的呢?如果c++类的构造函数有一个参数,那么在编译的时候就会有一个缺省的转换操作:将该构造函数对应数据类型的数据转换为该类对象,如下面所示: class MyClass{public:
MyClass( int num );}....MyClass obj = 10; //ok,convert int to MyClass',
blogTag:'',
blogUrl:'blog/static/',
isPublished:1,
istop:false,
modifyTime:0,
publishTime:1,
permalink:'blog/static/',
commentCount:0,
mainCommentCount:0,
recommendCount:0,
bsrk:-100,
publisherId:0,
recomBlogHome:false,
currentRecomBlog:false,
attachmentsFileIds:[],
groupInfo:{},
friendstatus:'none',
followstatus:'unFollow',
pubSucc:'',
visitorProvince:'',
visitorCity:'',
visitorNewUser:false,
postAddInfo:{},
mset:'000',
remindgoodnightblog:false,
isBlackVisitor:false,
isShowYodaoAd:false,
hostIntro:'',
hmcon:'1',
selfRecomBlogCount:'0',
lofter_single:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}安全检查中...
请打开浏览器的javascript,然后刷新浏览器
< 浏览器安全检查中...
还剩 5 秒&

我要回帖

更多关于 explicit operator 的文章

 

随机推荐