0
votes

I am trying to have a non-virtual base class method call a derived method that overrides one of the base class's virtual methods. For the life of me, I can't get it to work. See the code below:

public ref class BaseClass
{
    virtual void OverriddenMethod(){}

    void Run()
    {
        // Do some initial work here.

        // Call the derived class's version of OverridenMethod to do final work:
        OverriddenMethod();
    }
};

public ref class DerivedClass : public BaseClass
{
    virtual void OverriddenMethod() override
    {
        // Do some final work here.
    }
};

int main()
{
    DerivedClass^ DC = gcnew DerivedClass();
    DC->Run();
}

Using the code above, the base class's OverriddenMethod() gets called instead of the derived class's OverriddenMethod(), which isn't what I want. I was under the impression that, when using polymorphism, a call to a base class method that is overridden should instead call the overriding method of the derived class.

I have also tried using abstract:

public ref class BaseClass abstract
{
    virtual void OverriddenMethod() abstract;

    void Run()
    {
        // Do some initial work here.

        // Call the derived class's version of OverridenMethod to do final work:
        OverriddenMethod();
    }
};

public ref class DerivedClass : public BaseClass
{
    void OverriddenMethod()
    {
        // Do some final work here.
    }
};

int main()
{
    DerivedClass^ DC = gcnew DerivedClass();
    DC->Run();
}

But this gives a C3278 compiler error (direct call of interface method 'interface method' will fail at runtime) when OverriddenMethod is called inside of the BaseClass::Run() definition.

2
Mgetz: Thanks for pointing me to the article. However, it only discusses calling the overridden methods externally using references of the base and derived classes. My issue is calling the overridden method from within the base class. Also, I used override in the top example, I did not in the second example because it was using abstract.pcdangio
@pcdangio you need to use override regardless in this particular case. Also note that you need to set access modifiers so that the dirived class can override the base classMgetz

2 Answers

1
votes

Solution by OP.

public ref class BaseClass abstract
{
    virtual void BaseClass::OverriddenMethod() abstract;

    void BaseClass::Run()
    {
        // Do some initial work here.

        // Call the derived class's version of OverridenMethod to do final work:
        BaseClass::OverriddenMethod();  // DONT DO THIS!!!!!!!!
        OverriddenMethod(); // DO THIS INSTEAD!!!!!
    }
};

The issue here was because I was using a header for definitions and a cpp file for implementations of my base class. In the cpp file, I typically use ClassName::MemberName notation to refer to any of ClassName's members. However, doing so in this case forces the base class's virtual method to get called instead of the overridden method in the derived class.

This is why, when using the abstract keyword, I was getting the C3278 error when calling OverriddenMethod() inside of the Run() definition of the base class. Its because I was calling BaseClass::OverriddenMethod(), which points to nothing but an abstract definition.

1
votes

First of all at least your first example of code shall not be compiled because method Run has private access control.

I tried your code with some modifications in names for the sake of simplicity and I got the required result

#include "stdafx.h"

using namespace System;

public ref class A
{
public:
    void f() { g(); }
    virtual void g() { Console::WriteLine( "A::g()" ); }
};

public ref class B : public A
{
public:
    virtual void g() override { Console::WriteLine( "B::g()" ); }
};


int main(array<System::String ^> ^args)
{
    A ^pa = gcnew B();
    pa->f();
    return 0;
}

The output is

B::g()

Or classes could be defined as

public ref class A
{
public:
    void f() { g(); }
protected:
    virtual void g() { Console::WriteLine( "A::g()" ); }
};

public ref class B : public A
{
protected:
    virtual void g() override { Console::WriteLine( "B::g()" ); }
};

The result is the same that is the virtual function of the derived class is called.