ZivS ZivS - 4 months ago 11
C++ Question

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?

Answer

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.