识别标识符不工作的派生 class

Recognize derived class with identifier not working

我正在尝试使用 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 做了一些检查,并且在主函数中对关键 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 设置零标志和je 指令跳转到主函数的末尾,因为设置了零标志。这里发生了什么?我是不是遗漏了什么或者编译器(g++ 4.9.2x86_64-linux-gnu 目标)生成了错误的指令?

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

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)
                        ^
       (                      )