​原文​

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/构造器​