识别标识符不起作用的派生类

时间:2016-05-16 17:06:18

标签: c++ c++11 shared-ptr

我正在尝试使用C ++中的唯一标识符编号为派生类创建通用接口。

这就是我的代码的样子(至少需要C ++ 11来编译它):

#include <iostream>
#include <memory>

class Base
{
    protected:
        int ident;
        Base(int newIdent) : ident(newIdent) { }

    public:
        Base() : ident(0x01) { }
        virtual ~Base() { }           //needed to make class polymorphic
        int getIdent() { return ident; }
};

class Derived : public Base
{
    protected:
        int answer;
        Derived(int newIdent, int newAnswer) : Base(newIdent), answer(newAnswer) { }

    public:
        Derived(int newAnswer) : Base(0x11), answer(newAnswer) { }
        int getAnswer() { return answer; }
};

int main()
{
    std::shared_ptr<Base> bPtr = std::make_shared<Derived>(Derived(42));

    std::cout << "ident = 0x" << std::hex << bPtr->getIdent() << std::dec << "\n";
    if(bPtr->getIdent() & 0xF0 == 1)
    {
        std::shared_ptr<Derived> dPtr = std::dynamic_pointer_cast<Derived>(bPtr);
        std::cout << "answer = " << dPtr->getAnswer() << "\n";
    }

    return 0;
}

当然,您应该期望该计划输出ident = 0x11answer = 42,但它不会,因为它通常存在于ident = 0x11行之后。我还对GDB进行了一些检查,并且在main函数中对重要if条件检查的反汇编确认了问题:

   0x0000000000400f46 <+196>:   call   0x401496 <std::__shared_ptr<Base, (__gnu_cxx::_Lock_policy)2>::operator->() const>
   0x0000000000400f4b <+201>:   mov    rdi,rax
   0x0000000000400f4e <+204>:   call   0x4012bc <Base::getIdent()>
   0x0000000000400f53 <+209>:   mov    eax,0x0
   0x0000000000400f58 <+214>:   test   al,al
   0x0000000000400f5a <+216>:   je     0x400fb7 <main()+309>

当您在*0x400f53处中断时,rax很好地保留了正确的值(0x11),但是下面的指令只是用零覆盖rax,test设置零标志和{{ 1}}指令跳转到主函数的末尾,因为设置了零标志。这里发生了什么?我错过了什么或编译器(jeg++ 4.9.2目标)产生了错误的指令吗?

1 个答案:

答案 0 :(得分:5)

始终在启用警告的情况下进行编译。您的问题是一个操作顺序问题,其中&的优先级低于==,因此您需要:

if ((bPtr->getIdent() & 0xF0) == 1)

虽然那时你正在比较错误的东西,所以你真的想要:

if ((bPtr->getIdent() & 0xF0) == 0x10)

在这种情况下,你会从gcc看到这个:

main.cpp:32:32: warning: suggest parentheses around comparison in operand of '&' [-Wparentheses]
     if(bPtr->getIdent() & 0xF0 == 1)
                           ~~~~~^~~~

或来自clang:

main.cpp:32:25: warning: & has lower precedence than ==; == will be evaluated first [-Wparentheses]
    if(bPtr->getIdent() & 0xF0 == 1)
                        ^~~~~~~~~~~
main.cpp:32:25: note: place parentheses around the '==' expression to silence this warning
    if(bPtr->getIdent() & 0xF0 == 1)
                        ^
                          (        )
main.cpp:32:25: note: place parentheses around the & expression to evaluate it first
    if(bPtr->getIdent() & 0xF0 == 1)
                        ^
       (                      )