Calling methods of class derived from an abstract

2019-07-15 11:43发布

问题:

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?

回答1:

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.



回答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;
    }
}


回答3:

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.



回答4:

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.