Pergunta

I recently started using C++/Cli for wrapping purposes. Now I'm at a point where I've to know more about the internals.

Consider the following code:

Header file (ignoring .NET namespaces for this example):

public ref class BaseyClass
{
    protected:
        delegate void TestMethodDelegate(); // TestMethod delegate
        BaseyClass();                       // constructor            
        virtual void TestMethod();          // member: method
        GCHandle _testMethodHandle;         // member: method handle
};


CPP file (ignoring .NET namespaces for this example):

BaseyClass::BaseyClass()
{
    _testMethodHandle
          = GCHandle::Alloc(
                       gcnew TestMethodDelegate(this, &BaseyClass::TestMethod));
}

void TestMethod()
{
}

Eventually this class will be used as base class (for a DerivedClass) later and the method "TestMethod()" gets overridden and called from unmanaged code through the delegate pointer.

Now the question: Which method will be referenced by the delegate?

BaseyClass::TestMethod();

or

DerivedClass::TestMethod();

Personally I think the "BaseyClass::TestMethod()" will be referenced by the delegate because even when it's overridden, the delegate points to the (base-)address of BaseyClass. Hence a DerivedClass cannot override the "TestMethod" and use the delegate from BaseyClass.

I just want to be sure. Thanks for your comments and enlightment.

Foi útil?

Solução

The delegate will be a reference to the derived class's TestMethod. Even though you're passing &BaseyClass::TestMethod, that's a virtual method, you're also passing this, which is the derived type, and both of those are taken into account when the delegate is created.

Other notes:

  • TestMethodDelegate doesn't need to be inside the class definition. The more standard way is to have the delegate outside of the class, just in the namespace. (Or use the existing built-in one, Action.)
  • You don't need to GCHandle::Alloc (I assume that's what you meant by Allow). Instead, declare _testMethodHandle as TestMethodDelegate^ (or Action^). In general, you shouldn't need to deal with GCHandle unless you're interfacing with unmanaged code, and this code is all managed.

Here's my test code:

public ref class BaseyClass
{
public:
    BaseyClass() { this->_testMethodHandle = gcnew Action(this, &BaseyClass::TestMethod); }
    virtual void TestMethod() { Debug::WriteLine("BaseyClass::TestMethod"); }
    Action^ _testMethodHandle;
};

public ref class DerivedClass : BaseyClass
{
public:
    virtual void TestMethod() override { Debug::WriteLine("DerivedClass::TestMethod"); }
};


int main(array<System::String ^> ^args)
{
    BaseyClass^ base = gcnew DerivedClass();
    base->_testMethodHandle();
    return 0;
}

Output:

DerivedClass::TestMethod

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top