-1

How to have multiple virtual functions along inheritance chain? Why does the call to this->Init() in 'MoreSpecific' class cause unresolved external symbol error?

When this code is encountered it will always be dealing with an instance of MostSpecificA or MostSpecificB which should then be able to access the child class implementations.

class GenericInterface
{
public:
   virtual void Init() = 0; //virtual function
   virtual void Startup() = 0;
};

class MoreSpecific : public GenericInterface
{
   virtual void Init() = 0; //we cannot yet define Init implementation here, not enough information
   
   void Startup() { 
      this->Init(); //this throws unresolved external symbol error
   }

   //other shared functionality
};

class MostSpecificA : public MoreSpecific
{
   void Init() {
       //the implemention for MostSpecificA
   }
};

class MostSpecificB : public MoreSpecific
{
   void Init() {
       //the implemention for MostSpecificB
   }
};

Edit, actually the above code does work. The error occurs when calling Init() from the constructor. Following code produces unresolved external symbol error, which matches what is occurring in my code.

class GenericInterface
{
public:
    virtual void Init() = 0; //virtual function

};

class MoreSpecific : public GenericInterface
{
public:
    virtual void Init() = 0; //we cannot yet define Init implementation here, not enough information

    MoreSpecific() {
        this->Init();
    }
    //other shared functionality
};

class MostSpecificA : public MoreSpecific
{
public:
    MostSpecificA() 
        : MoreSpecific()
    {

    }

    void Init() {
        //the implemention for MostSpecificA
    }
};

class MostSpecificB : public MoreSpecific
{
    void Init() {
        //the implemention for MostSpecificB
    }
};
DaManJ
  • 373
  • 2
  • 15
  • 1
    Please copy-paste the error message into your question instead of paraphrasing it. – JaMiT Feb 17 '21 at 05:24
  • 1
    Looks fine to me. Of course you're clearly not showing _actual_ code because this can't possibly compile -- the class definitions don't even end with a semi-colon. – paddy Feb 17 '21 at 05:32
  • Is your code snippet compiled? There are some missing `;` after class definition. Also I presume you're calling `Startup` function in constructor where inheritance are not established yet. – Louis Go Feb 17 '21 at 05:34
  • 2
    An additional problem with this is that all your subclasses are hiding these public methods by implicitly declaring them private. They must be in the public section of the class if you wish to use them from outside. Fixing that, and the semi-colon issue, and it's just fine. https://godbolt.org/z/PYo49b – paddy Feb 17 '21 at 05:38
  • As @paddy said, your example doesn't reproduce the problem. [Mre] would help. – Louis Go Feb 17 '21 at 05:40
  • @paddy added semi-colons, and actual issue i'm encountering which is occurring when this is done in class contructor – DaManJ Feb 17 '21 at 06:48
  • `Unresolved external symbol error` is a linker error. It is not 'thrown' or otherwise produced by your code but by not providing all the object files to the linker. NB There are no 'nested functions' in C++. – user207421 Feb 17 '21 at 06:50
  • 3
    Well you can't do it there, because the function does not exist. Your object is not fully constructed. The class `MoreSpecific` has no knowledge of `MostSpecificA` or any other subclass until _after_ the object is fully constructed. Only _then_ are you allowed to invoke calls via the vtable. You should never call virtual functions in a constructor or a destructor unless your class is declared `final`. – paddy Feb 17 '21 at 06:50
  • @paddy yeah, i was just thinking it is because the child class is not yet constructed so the method cannot be accessed. that is the issue then. thanks. – DaManJ Feb 17 '21 at 06:52
  • Note that this is precisely the reason for using the pattern of having a `Init` method or `Startup` or whatever from your original example. You construct the object safely and _then_ the caller is expected to invoke this secondary initialization that performs more complex stuff via virtual methods etc. – paddy Feb 17 '21 at 06:54
  • See also [Calling virtual functions inside constructors](https://stackoverflow.com/questions/962132/calling-virtual-functions-inside-constructors). – JaMiT Feb 20 '21 at 16:41

1 Answers1

0

Calling virtual method from constructor/destructor doesn't use virtual dispatch, and just call the method in a non-virtual way.

So:

virtual void Init() = 0;

MoreSpecific() { this->Init(); } // call MoreSpecific::Init, but no definition provided

Init is generally a wrong pattern, and initialization should go directly in constructor without virtual call.

but if you really want to use Init, you have to create a factory and call Init once object is created, something like:

template <typename T>
T Create()
{
    T res{};
    res.Init();
    return res;
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302