D opEquals()和opCast()给了我一个分段错误

D opEquals()和opCast()给了我一个分段错误,d,D,我试图用D编程语言编写一个表示全球贸易标识号(GTIN)的类型库。GTIN有四种,每种都是根据数字本身的长度命名的:GTIN8,GTIN12,GTIN13,以及GTIN14。其中每一个都被建模为一个从抽象GTIN类继承的类 在抽象的GTIN类中,我重写了opEquals操作符来比较两个GTINs。由于所有较小的GTINs都可以映射到较宽的GTIN14,因此比较中的每个GTIN首先被转换为GTIN14,然后进行比较 在比较一个或多个GTIN13s(或者可能是更小的GTIN类型)之前,这一切都可以正

我试图用D编程语言编写一个表示全球贸易标识号(GTIN)的类型库。GTIN有四种,每种都是根据数字本身的长度命名的:
GTIN8
GTIN12
GTIN13
,以及
GTIN14
。其中每一个都被建模为一个从抽象
GTIN
类继承的类

在抽象的
GTIN
类中,我重写了opEquals操作符来比较两个
GTIN
s。由于所有较小的
GTIN
s都可以映射到较宽的
GTIN14
,因此比较中的每个
GTIN
首先被转换为
GTIN14
,然后进行比较

在比较一个或多个
GTIN13
s(或者可能是更小的
GTIN
类型)之前,这一切都可以正常工作,在这种情况下,我会得到一个分段错误

这一切都从这个单元测试开始:

GTIN13 gtin1 = new GTIN13("123456789012");
GTIN13 gtin2 = new GTIN13("123456789012");
assert(gtin1 == gtin2);
运算符
opEquals()
具有
对象的签名。opEquals(对象o)
,将签名更改为任何其他内容都不会覆盖
=
。在我的例子中,这变成了对
gtin1.opEquals(cast(Object)gtin2)
的调用。我的
opEquals
覆盖如下所示(减去累计注释掉的代码和调试语句):

此外,我的朋友
writeln()时,
b
null
。(该行之前不为空。)

因此,总而言之,问题似乎是将
GTIN14
以外的任何类型的
GTIN
投射到
对象
,然后返回到
GTIN14
会以某种方式完全删除该对象。这是虫子吗?这是我的代码的问题吗?是否有一种不影响代码质量的变通方法


如果能得到任何帮助,我将不胜感激。

好的,我从你的邮箱里得到了一些评论

public abstract
class GlobalTradeItemNumber
{
    // this could prolly just return _digits.length too.
    public abstract @property
    size_t length();
我在这里的一般评论是,通过从数组中借用长度,可以稍微简化代码。。。。或者,您也可以使用长度作为参数来执行类似于模板化类的操作

不过,我稍后会再讨论这个问题,首先,让我们修复您的代码。在课堂上继续:

public
/*
    Note #1:

    OK, this line is wrong:
    //GTIN14 opCast(GTIN14)()

    It should probably be:
*/
GTIN14 opCast(T : GTIN14)()
{
    string currentGTINString = this.toString()[0 .. $-1];
    while (currentGTINString.length < 13)
        currentGTINString = ('0' ~ currentGTINString);
    return new GTIN14(currentGTINString);
}

// we also need one for converting to the other sizes
// this could also be done with metaprogramming
GTIN13 opCast(T : GTIN13)()
{
    string currentGTINString = this.toString()[0 .. $-1];
    while (currentGTINString.length < 12)
        currentGTINString = ('0' ~ currentGTINString);
    return new GTIN13(currentGTINString);
}
好吧,这里没什么好说的,你的代码是有效的,我只是写得有点不同。累加器变量模式将稍微优化它。当然,这里不是很重要,只是需要记住一些事情

/*
    Note #2: this is where things get broken
*/
public override @trusted
bool opEquals(Object other)
{
    /*
    these are actually two different kinds of casts
    GTIN14 b = cast(GTIN14) other; // does a generic dynamic cast!
    GTIN14 a = cast(GTIN14) this; // actually calls the opCast
    */

    GTIN obj = cast(GTIN) other;
    if(obj is null) // which might return null because Object is not necessarily an instance of your class
        return false; // definitely not a match

    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; // a generic dynamic cast!
    GTIN obj = cast(GTIN) other;
    if(obj is null) // which might return null because Object is not necessarily an instance of your class
        return -1; // so return something indicating not a match
    GTIN14 that = cast(GTIN14) obj; // now you can use your custom cast
    const ulong thisNumber = this.toNumber();
    const ulong thatNumber = that.toNumber();
    if (thisNumber == thatNumber) return 0;
    return ((thisNumber / 10u) > (thatNumber / 10u) ? 1 : -1);
}
如果你看过火卫一的一些内部结构,你会在
std.base64
std.digest
中看到类似的模式

这样,所有的功能实际上都在基类中了。您可以像在基类中那样重写
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);
}
T optcast(T:GlobalTradeItemNumberImpl!N,int N)()
{
string currentGTINString=this.toString()[0..$-1];
而(当前安装长度<(N-1))
currentGTINString=(“0”~currentGTINString);
返回新的T(当前GTINSTRING);
}
这里的专门化使用了本章表格#7中描述的“模式匹配”:捕获任意随机N,并提取它在函数中使用的内容


如果您感兴趣,我们还可以进行其他优化,比如使用
~
运算符,或者甚至可以使用
别名this
将其从类更改为
结构
,以组合常用功能。。但是如果你想玩的话,我可以让你玩:)

你不必使用
override
来重载操作符,包括
opEquals
。只需将您的
opEquals
bool opEquals(GTIN other)
。我建议您不要使用
对象
。取而代之的是使用超类(基类或接口)GTIN,所有GTIN子类型都从那里继承。如果您确实使用对象,那么我建议您使用
is
来检查它是什么类型的对象。使用您的方法,您甚至可以传递RacingCar类型的对象,而这似乎不是您想要做的事情……我不想这么说,但您的代码在几个级别上都是错误的。。。。你能把整件事都贴出来吗?如果你能把它贴出来,我会写一些细节,并从整件事中提出建议。@Michail,我会在听了Adam的话后试一试。我可以发誓我试过了,但没有成功,但我会记住的。谢谢。@DejanLekic,我正在使用GTIN超类,与GTIN相关的大部分内容都是在其中实现的。噢,哇!我不知道我是如何编程这么长时间的,从来没有学习过不同类型的演员!至于其他方面,我同意你所说的一切。我试图制作一个模板版本,但是我有一些问题,但是看起来你已经解决了!引人注目的观点和解释。非常感谢你的帮助,亚当!是的,演员阵容有点混乱。我建议在C++版本上读一点:在D中,沃尔特想简化C++到一种类型的简化…但真正发生的是,现在我们有了所有相同类型的强制转换,只是共享了相同的关键字
const\u cast
cast()
cast(const)
等。
dynamic\u cast
cast(某个对象)
来自另一个对象<代码>重新解释\u cast
*cast(T*)cast(void*)和x
(是的,混乱的lol)。其余部分为静态广播,除非涉及到opCast或CTOR。我不在房间里
public
ulong toNumber()
{
    ulong result;
    // a note here: I would probably just have
    // int exponent = 1;
    // then exponent *= 10; in each loop instead of pow each time.
    for (size_t i = this.length-1; i > 0; i--)
    {
        result += (this._digits[i] * (10^^(this._digits.length-i)));
    }
    return result;
}
/*
    Note #2: this is where things get broken
*/
public override @trusted
bool opEquals(Object other)
{
    /*
    these are actually two different kinds of casts
    GTIN14 b = cast(GTIN14) other; // does a generic dynamic cast!
    GTIN14 a = cast(GTIN14) this; // actually calls the opCast
    */

    GTIN obj = cast(GTIN) other;
    if(obj is null) // which might return null because Object is not necessarily an instance of your class
        return false; // definitely not a match

    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; // a generic dynamic cast!
    GTIN obj = cast(GTIN) other;
    if(obj is null) // which might return null because Object is not necessarily an instance of your class
        return -1; // so return something indicating not a match
    GTIN14 that = cast(GTIN14) obj; // now you can use your custom cast
    const ulong thisNumber = this.toNumber();
    const ulong thatNumber = that.toNumber();
    if (thisNumber == thatNumber) return 0;
    return ((thisNumber / 10u) > (thatNumber / 10u) ? 1 : -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);
    }
}
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);
}