微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

没有间接跳转的多态性?

如何解决没有间接跳转的多态性?

| 几个月前,当我学习MIPS组装时,我突然想到了一个我忘记提的问题,所以我想现在就问: 没有间接跳转指令就可以实现多态吗?如果是这样,怎么办? (间接跳转是“跳转寄存器”指令,例如MIPS中的“ 0”或x86中的“ 1”。) 我想出的一种这样的解决方案是自我修改代码,但是我很好奇是否可以通过任何其他方式实现多态(以及OOP)。     

解决方法

        最简单的答案是编写程序(和可能的汇编程序),以便所有方法调用都可以在运行时解决,从而无需查找表。我假设您正在谈论将子类传递给为超类设计的函数,因此不可能实现此优化。 我认为消除查找超出了您的问题范围,因此我将建议替换
jmp <reg>
指令(对不起,我只知道x86)。 您可以在存储器上执行
call <mem>
地址(这不是您要怎么做) 它使用查找表?) 您可以在寄存器上执行
call <reg>
(与jmp完全不同 ,但确实回答了您的问题) 如果愿意的话,可以can5ѭ,但是 与ѭ2没什么不同 所有这些都有可能解决您的问题,但是都是一样的。我想这说明了我对为什么要执行自己的要求感到困惑。您必须具有某种方法来选择要调用的方法(vtable),以及某种将执行转移到该方法的方法(使用
jmp
call
)。 唯一可行的方法是摆弄用于指向执行链中下一个命令的寄存器(x86中的“ 9”)。能否还是应该是另一个问题。我想,如果您对体系结构非常了解,并且不担心更改它,可以这样做。     ,        是 您可能需要考虑更改您的问题 考虑下面的C ++代码,其中ѭ10显然是多态的(是的,我没有删除对象):
class Base
{
    public: int foo(){ return 1; }
};

class Derived: public Base
{
    public: int foo(){ return 2; };
};

int main()
{
    Base* b = new Derived();

    return b->foo();    //Returns 1
}
由gcc生成的程序集是
main:
.LFB2:
    pushq   %rbp
    .seh_pushreg    %rbp
    movq    %rsp,%rbp
    .seh_setframe   %rbp,0
    subq    $48,%rsp
    .seh_stackalloc 48
    .seh_endprologue
    call    __main
    movl    $1,%ecx
    call    _Znwm
    movq    %rax,-8(%rbp)
    movq    -8(%rbp),%rax
    movq    %rax,%rcx
    call    _ZN4Base3fooEv
    addq    $48,%rsp
    popq    %rbp
    ret
如您所见,没有间接跳转/调用。 那是因为多态性不是这里的重点(尽管有必要),虚方法才是重点。 然后答案就变成了 没有 如果通过间接跳转/调用,则表示使用运行时值来计算跳转/调用目标的每种技术(因此包括诸如
ret
call []
call reg
jr
jalr
之类的东西)。 考虑这个来源
#include <iostream>

class Base
{
    public: virtual int foo(){ return 1; }
};

class Derived: public Base
{
    public: int foo(){ return 2; };
};

class Derived2: public Base
{
    public: int foo(){ return 3; };
};



int main()
{
    int a;
    Base* b = 0; //don\'t remember the header for std::nullptr right now...

    std::cin >> a;

    if (a > 241)
        b = new Derived();
    else 
        b = new Derived2();

    return b->foo();    //Returns what?
}
结果取决于用户输入,原型运行时值,因此必须是被调用的例程,并且没有静态地址可以执行。 请注意,在这种情况下,编译器可以使用跳转到具有静态地址的调用(因为调用了
Derived2::foo
Derived::foo
),但这通常是不可能的(您可能有多个没有源文件的目标文件,可能有别名指针,指针
b
可以由外部库设置,依此类推)。     

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。