C++的类型转换重载(type casting overriding)
最近项目里面用了mysqlpp,注意到query对象在获取查询结果时候的store()方法返回了StoreQueryResult,虽然它不是指针但是可以这样用:
if (StoreQueryResult queryResult = query.store()) {...
一开始以为写错了——而且就算是运算符重载,不也只能用“!”么。查了一下相关的文档,原来这玩意是类型转换重载。
operator关键字后面的类型任意,甚至可以是void*,显而易见在这种情况下需要这么做:
private:
bool _isValid;
public:
operator void*() const { return _isValid ? this : nullptr; }
这样一来也可以达到上面type casting的效果。
但这几种方式或多或少都存在问题,所以The Safe Bool Idiom介绍了另外一种方式:嵌套类/安全类型转换。可以看到mysqlpp用的也是这种方式。文章最后还利用模板创建了支持多类型的版本。
这个故事告诉我们,C++的细节太多了。
p.s:想到了C#的nullable type。
在C# 2.0之前,类似int这种值类型是不能和null比较的,所以总需要提供一个getter或者其他什么method进行bool判断。有了nullable type后,就可以用int? x = 0; 这样的语法创建可和null比较的值类型对象。
那个问号其实只是语法糖,真正实现功能的是System.Nullable
namespace System
{
[TypeDependency("System.Collections.Generic.NullableComparer`1"), TypeDependency("System.Collections.Generic.NullableEqualityComparer`1")]
[Serializable]
public struct Nullable where T : struct
{
private bool hasValue;
internal T value;
public T Value
{
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
get
{
if (!this.HasValue)
{
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_NoValue);
}
return this.value;
}
}
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public Nullable(T value)
{
this.value = value;
this.hasValue = true;
}
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public static implicit operator T?(T value)
{
return new T?(value);
}
public static explicit operator T(T? value)
{
return value.Value;
}
}
}
说白了还是privaate flag + getter + conversion method。最后两个方法,就是C#版本的type casting overriding。