原文
public abstract
class GlobalTradeItemNumber
{
// 可仅return _digits.length
public abstract @property
size_t length();
代码:
public
/*
//该行是错的.
//GTIN14 opCast(GTIN14)()//.1
应为
*/
GTIN14 opCast(T : GTIN14)()
{
string currentGTINString = this.toString()[0 .. $-1];
while (currentGTINString.length < 13)
currentGTINString = ('0' ~ currentGTINString);
return new GTIN14(currentGTINString);
}
// 用元编程需要转为其他大小
GTIN13 opCast(T : GTIN13)()
{
string currentGTINString = this.toString()[0 .. $-1];
while (currentGTINString.length < 12)
currentGTINString = ('0' ~ currentGTINString);
return new GTIN13(currentGTINString);
}
参考.1
定义了名为GTIN14
的本地模板参数
.并隐藏了外部名
.
如果用的是模板类
,则特化
还可提取长度
,并且应有可完成这些的函数
.或,如果长度
为每个子类
中的编译时常量
(枚举),也可从那里
提取它.
用T : class_name
加上函数
就可修复.
public ulong toNumber()
{
ulong result;
// int exponent = 1;
// exponent *= 10;然后不断乘
for (size_t i = this.length-1; i > 0; i--)
{
result += (this._digits[i] * (10^^(this._digits.length-i)));
}
return result;
}
再看:
public override @trusted
bool opEquals(Object other)
{
/*//两种转换!
GTIN14 b = cast(GTIN14) other;
// 通用动态转换
GTIN14 a = cast(GTIN14) this;
// 调用opCast
*/
GTIN obj = cast(GTIN) other;
if(obj is null) //
//Object可能不是你类实例,可能返回`无效`.
return false; // 不是匹配
GTIN14 b = cast(GTIN14) obj;
GTIN14 a = cast(GTIN14) this;
for (int i; i < a.digits.length; i++)
{
if (a.digits[i] != b.digits[i]) return false;
}
return true;
}
public override @trusted
int opCmp(Object other)
{
// GTIN14 that = cast(GTIN14) other;
// 通用动态转换
GTIN obj = cast(GTIN) other;
if(obj is null) // 同上
return -1; // 不匹配
GTIN14 that = cast(GTIN14) obj;
// 这是自定义转换.
const ulong thisNumber = this.toNumber();
const ulong thatNumber = that.toNumber();
if (thisNumber == thatNumber) return 0;
return ((thisNumber / 10u) > (thatNumber / 10u) ? 1 : -1);
}
麻烦在:相同的cast
语法做了两件不同
事情
other
静态类型是Object
通用基类,所以它还不知道你的自定义转换函数
.(opCast
,作为模板,不能是虚的,因此这不是其他修改
模板函数的覆盖
行为)
用的是类似C++
的动转
,c++的转换 试从基类/接口
转换回子类
,成功得到引用
,失败,则返回无效
,并段错误
.
cast(xxx) this
知道是GTIN
或其子类.因而,可用自定义opCast
来转换.因而a
成功,但b
失败.
GTIN14 a = new GTIN14("xxx");
Object b = new Object();
assert(a == b);
修复为:Object other
转为GTIN
基类,再检查null
.
用a is null
来比较无效
.因为a == b
在a
为无效
时会崩溃,==为opEquals
.
转换回GTIN
之后,可再次转换
,并调用转换
函数.
在实现它们的类中,opEquals
和opCmp
都需要遵循相同
模式.
在opEquals
中,为无效
时,我返回假
.而opCmp
中返回-1
.
实现通用模板类:
alias GTIN14 = GlobalTradeItemNumberImpl!14;
alias GTIN13 = GlobalTradeItemNumberImpl!13;
public
class GlobalTradeItemNumberImpl(int size) : GlobalTradeItemNumber
{
public override @property
size_t length()
{
return size;
}
this(string digits)
{
super(digits);
}
}
都在基类
中实现功能
,可用opCast
覆盖.
T opCast(T : GlobalTradeItemNumberImpl!N, int N)()
{
string currentGTINString = this.toString()[0 .. $-1];
while (currentGTINString.length < (N-1))
currentGTINString = ('0' ~ currentGTINString);
return new T(currentGTINString);
}
用alias this
改类
为构
来组合功能.
C++ | D |
const_cast | cast()/cast(const) |
dynamic_cast | cast(some_object) |
reinterpret_cast | *cast(T*)cast(void*)&x |
static_cast | opCast/构造器 |