2

You'll have to forgive me if this is a really basic question; I haven't used C++ this much in a long time so I've forgotten how a lot of it works.

Anyway, I have a base class and a couple derived classes like this (super oversimplified, but the gist is the same):

class Base
{
public:
   Base () { }
   int SomeFunction (int x, int y); // abstract definition
};

class Derived1 : public Base
{
public:
   Derived1() : Base() { }
   int SomeFunction (int x, int y)
   {
      // actual implementation
      return 4;
   }
};

class Derived2 : public Base
{
public:
   Derived2() : Base() { }
   int SomeFunction (int x, int y)
   {
      // actual implementation
      return 7;
   }
};

Later on in main I have a list of Base objects:

Base *baseobjects[10];

Later I fill that array with instances of Derived1 and Derived2. That works with baseobjects[i] = &newDerived1 (where newDerived1 is an instance of the Derived1 class). That's all fine.

What I can't seem to figure out is how to later iterate through the baseobjects array and call SomeFunction on every instance in the list without explicitly knowing which derived class I'm using. I've done this in C# and it works fine, but apparently my C++ syntax is off:

int result = baseobjects[i]->SomeFunction(a, b);

That gives me a LNK2019 error when I try to compile, apparently because it's looking at the Base class for the implementation and it isn't there. I'm assuming I have to use some pointer tricks to get it to look at the proper derived method, but nothing I've tried yet has worked. Any suggestions?

Andrew
  • 4,953
  • 15
  • 40
  • 58

4 Answers4

8

Your method should be declared virtual. And in your case, probably pure virtual.

class Base
{
public:
   Base () { }
   virtual int SomeFunction (int x, int y) = 0; // abstract definition
};

Note that, while this is not absolutely required, you might as well declare a virtual destructor. Do it if you ever delete a derived instance trough a pointer of the base class.

class Base
{
public:
   //Base () {} // This is not required, the default provided constructor is similar.
   virtual ~Base() {} // virtual destructor.
   virtual int SomeFunction (int x, int y) = 0; // abstract definition
};

Edit:

Also, regarding the link error you posted:

Either you forgot the = 0, either you are calling Base::SomeFunction() from somewhere.

As Thomas Edleson points out, = 0 does not mean that your function has no implementation: it can have one, but it only requires the derived classes to (re)implement it to not being abstract.

If you are interested in this topic, I suggest you read this post.

Community
  • 1
  • 1
ereOn
  • 53,676
  • 39
  • 161
  • 238
  • Either make it pure.. or add `{}` after the function name. – Nawaz Feb 19 '11 at 16:36
  • When I try this and compile, I get a different linking error: `LNK2001: unresolved external symbol "public: virtual int__thiscall Base::SomeFunction(int x, int y)"` and another: `error LNK1120: 1 unresolved externals`. – Andrew Feb 19 '11 at 16:37
  • 1
    @Nawaz: wouldn't the method lack a `return` value with an empty body (`{}`) ? Or is it some specific syntax I've never heard of ? – ereOn Feb 19 '11 at 16:38
  • @Nawaz - Adding `{}` forces me to write an implementation in the base class, which results in a slew of other errors since `Base` is no longer abstract. – Andrew Feb 19 '11 at 16:39
  • 1
    @Andrew S. Arnold: Did you put the `= 0` ? If so, the linker should never ask for this function because it knows it has no implementation. Be sure to clean your working directory (all old object files) and try again. – ereOn Feb 19 '11 at 16:40
  • @ereOn: Pure virtual does not mean "has no implementation". – Thomas Edleson Feb 19 '11 at 16:45
  • @ereOn: My point was : either make it pure, or define it. Since I was eating, so I typed it with my left hand, I made it as minimal as possible for me :D – Nawaz Feb 19 '11 at 16:46
  • @Thomas Edleson: You're right good point. My wording was inaccurate. I will update my answer in this regard. Thanks. – ereOn Feb 19 '11 at 16:50
  • @Thomas Edleson: Well, once again my wording was a bit off... I meant... well : read the updated answer, you'll see what I meant ;) – ereOn Feb 19 '11 at 16:55
  • With regards to the error, yeah I'd omitted the `=0`; I'm getting different problems now—an "access violation reading location 0xcccccccc" when I run the program. Probably something to do with how I'm instantiating my derived classes. – Andrew Feb 19 '11 at 16:56
  • @Andrew S. Arnold: My guess is you have some other mistake not shown in this question. However, your problem regarding the inheritance and virtual function should be solved. You should probably ask another question for your other problem. – ereOn Feb 19 '11 at 16:59
2

If you want to override a method, it must be virtual.

class Base
{
public:
   Base () { }
   virtual int SomeFunction (int x, int y); // abstract definition
}

Seccond thing is that your derivated classes did not extends of your base-class.

class Derived1 : public Base
{ 
 public:
    Derived1() : Base() { }
    int SomeFunction (int x, int y)
    {
        // actual implementation
        return 4;
    }
}
Till
  • 994
  • 5
  • 18
1

You have to declare the member function SomeFunction()

  1. virtual
  2. abstract

So the declaration for Base should look like this:

class Base
{
public:
    Base() { }
    virtual int SomeFunction(int x, int y) = 0;
};

You can omit the virtual keyword in the derived classes.

markus
  • 495
  • 4
  • 5
0

To just slightly elaborate on ereOn's answer, you do need to declare you base class function (ie: your abstract definition) in order for your derived classes to be able to override it. What he didn't clarify though is that other than that, what you've posted is fine (that is, the calls to the function you posted will then work without any modification).

Note also, that if you're after a pure abstract definition, you should append = 0 to your function declaration as follows:

class Base
{
public:
   Base () { }
   virtual int SomeFunction (int x, int y) = 0; // pure abstract definition
};

This lets the compiler know that classes derived from Base must supply their own implementation of SomeFunction.

Mac
  • 14,615
  • 9
  • 62
  • 80
  • Hmmm... getting closer. This compiles, but when running I get an access violation error at the line where I call the function (`int result = baseobjects[i]->SomeFunction(a, b);`). – Andrew Feb 19 '11 at 16:42
  • 1
    Not true; pure virtual specifies that derived classes (at least one in the hierarchy) must override the method, but the base can still provide an implementation. – Thomas Edleson Feb 19 '11 at 16:44
  • see [this thread](http://stackoverflow.com/questions/2089083/pure-virtual-function-with-implementation) for more details. – ereOn Feb 19 '11 at 17:00
  • @Thomas: true. I even actually knew that - dunno why I wrote it that way. I'll change it to be more accurate. – Mac Feb 20 '11 at 05:09