Search code examples
c++delegateswindows-runtimec++-cxpure-virtual

C++/CX Delegate in base constructor fails with pure virtual call assertion


I can't understand why the following code fails with a purvirt call and calls abort();

This is a WinRT project using C++/CX

namespace Test {
    public delegate void TickHandle();

    ref class Clock {
    public:
        event TickHandle^ Tick;
    };


    ref class Base {
    internal:
        Base() :
            m_clock(ref new Clock())
        {
            std::cout << "Base::Base" << std::endl;
            m_clock->Tick += ref new Test::TickHandle(this, &Test::Base::OnTick);
            OnTick();
        }
    protected:
        virtual void Foo() = 0;

    private:
        Clock^ m_clock;

        void OnTick()
        {
            std::cout << "Tick" << std::endl;
        }
    };

    ref class Derive : public Base{
    internal:
        Derive() 
        {
            std::cout << "Derive::Derive" << std::endl;
        }
    protected:
        void Foo() override
        {
            std::cout << "Derive::Foo" << std::endl;
        }
    };

    void main()
    {
        auto y = ref new Test::Derive();
    }
}

The registration to the Tick event is the faulting line which for some reason is considered as a pure virtual call to I-don't-know-what.

I played around with this example and noticed a few things:

  1. This only happens if the Base class is pure virtual (notice the Foo() = 0)

  2. It doesn't matter if Base::Tick is private \ public \ protected etc...

  3. I can (obviously) call OnTick() from Base constructor and it works

Anyone got an explanation?


Solution

  • C++/CX is just a compiler wrapper to make COM objects easy. This means objects implementing IUnknown. In the constructor of Base, the virtual function table for IUnknown has yet to be initialized, so all entrys are "pure virtual". When you attempt to register the tick handler, it wants to add a reference to this by calling IUnknown::AddRef which until the object is fully constructed still points to the "pure virtual" implementation.