Search code examples
c++linker-errorsnew-operator

C++ Undefined Reference to Function of Dynamically Created Class Member


I have four different C++ classes; Comp(), which contains Parent(), which has two children ChildA() and ChildB(). I want to dynamically create an instance of ChildA or ChildB inside of Comp() depending on some parameter.

My code looks a bit like this:

class Parent {
  public:
    foo();
};

class ChildA : public Parent {
  public:
    foo(); // Overrides Parent.foo()
};

class ChildB : public Parent {
  public:
    foo(); // Overrides Parent.foo()
};

class Comp {
  public:
    Init(uint8_t someParam){
      if(someParam){
        obj = new ChildA();
      }
      else{
        obj = new ChildB();
      }
    }

    doFoo(){
        obj->foo();
    }
 
  private:
    Parent* obj;
};

However, this does not compile. It's throwing me linker errors saying that I have an undefined reference to Parent::foo()

/build/libComp.a(Comp.cpp.o): In function `Comp::doFoo()':
Comp.cpp:(.text._ZN6Memory8readByteEt+0x4e): undefined reference to `Parent::foo()'

I feel like I'm missing something fundamental here. I'm coming from a background in Python programming so I haven't quite switched my thought process over to C++ yet. Am I allowed to use classes this way?


Solution

  • As you are a Python programmer you got used to the world where every method is a virtual one, and the overload means that you just replace the value in the dict. C++ is somewhat different.

    So the first solution is to define the Parent::foo method. You have declared it, the class is not a template - so you have to define the body somewhere. Anyway that wouldn't help you as calling obj->foo(); means calling the Parent::foo() method, and I guess that is not what you want.

    Now we are moving to the world of virtual methods: in C++ you have to declare a method as virtual explicitly:

    class Parent {
      public:
        virtual foo();
    };
    

    You still need to define the body of Parent::foo() somewhere.

    If you don't want to define it by design, you may make this method abstract (thus the class Parent becomes abstract as well, and no instance of this class can be created):

    class Parent {
      public:
        virtual foo() = 0;
    };
    

    You don't need to declare the method foo of the derived classes as virtual (they will be anyway), but the best practice is to add either a override or final specifier:

    class ChildA : public Parent {
      public:
        foo() final; // Overrides Parent.foo()
    };
    
    class ChildB : public Parent {
      public:
        foo() override; // Overrides Parent.foo()
    };
    

    The difference is that you cannot override this method for ClassA and you can do this for the ClassB.