Conditional operator + upcast + const reference

前端 未结 1 626
一向
一向 2021-02-08 03:36

Inspired by this question, I tried the following code:

struct A {
  virtual void doit() const = 0;
};

struct B : public A {
  virtual void doit() const;
};

str         


        
相关标签:
1条回答
  • 2021-02-08 04:22

    Oh, it's very invalid.

    Consider:

    #include <iostream>
    using namespace std;
    
    struct A {
        virtual ~A() { cout << "~A" << endl; }
        virtual void doit() const = 0;
    };
    
    struct B : public A
    {
        ~B() override { cout << "~B" << endl; }
        void doit() const override { cout << "A::doit" << endl; }
    };
    
    struct C : public A
    {
        ~C() override { cout << "~C" << endl; }
        virtual void doit() const { cout << "C::doit" << endl; }
    };
    
    void foo(bool p)
    {
        cout << "foo( " << p << ")" << endl;
        const A &a = (p ? static_cast<const A &>(B()) : static_cast<const A &>(C()));
        a.doit();
    }
    
    auto main( int argc, char* argv[] ) -> int
    {
        cout << boolalpha;
    
        foo( true );
        cout << endl;
        foo( false );
    }
    

    Output in Coliru Viewer, using g++ 4.8:

    foo( true)
    
    ~B
    
    ~A
    
    pure virtual method called
    
    terminate called without an active exception
    
    bash: line 7: 16922 Aborted                 (core dumped) ./a.out
    

    It's UB so any explanation could be true, but one can be reasonably sure, without looking at the assembly, that what happens is:

    • A temporary is constructed.
    • It's bound to the reference.
      This is a reference being bound to a reference, so does not involve creation of a new temporary or slice.
    • The temporary is destroyed.
    • As part of that its dynamic type (vtable pointer) is changed to A, which is abstract.
    • The pure virtual in A is called.
    0 讨论(0)
提交回复
热议问题