0

I'm having some issues overriding a function and I don't know why it's not working. I keep looking online, but I haven't found anything. I should probably add that I'm using the c++11 standard right now just in case. Here is my code:

class SupervisedLearner {
public:
    ...
    virtual double measureAccuracy(Matrix& features, Matrix& labels, Matrix* pOutStats = NULL);
}

class NeuralNet: public SupervisedLearner {
public:
    ...
    double measureAccuracy(Matrix& features, Matrix& labels, Matrix* pOutStats = NULL) override;
}

The method measureAccuracy is then being called via a pointer to the generic SupervisedLearner class:

SupervisedLearner* learner = getLearner(model, r, parser.getLearnerExtra());
...
double accuracy = learner->measureAccuracy(trainFeatures, trainLabels, &stats);

Note that both the base class and the child class have implementations of the method. The program for some reason always goes to the SupervisedLearner::measureAccuracy function.

Can anyone see anything obviously wrong?

crunk1
  • 2,560
  • 1
  • 26
  • 32
  • 1
    Just a suggestion: use `override` if you override virtual functions in derived classes. –  Nov 08 '13 at 19:59
  • 1
    What does getLearner() instantiate? – helb Nov 08 '13 at 19:59
  • I should also add that I have tried to explicitly cast 'learner' to a NeuralNet*, but it didn't work. – crunk1 Nov 08 '13 at 20:02
  • @helb In this case, a new NeuralNet*. – crunk1 Nov 08 '13 at 20:03
  • @rightfold Thanks, I tried it, but it didn't work. "override" does serve as an identifier in c++11, though. See http://stackoverflow.com/questions/18198314/override-keyword-in-c – crunk1 Nov 08 '13 at 20:09
  • It was a suggestion, not a solution. It’s good practice to do it anyway. :) –  Nov 08 '13 at 20:11
  • Just try it without the last parameter defaulting to NULL. At a guess, that is making the signature different. – cup Nov 08 '13 at 20:11
  • @cup Thanks, good idea, but it didn't work. – crunk1 Nov 08 '13 at 20:18
  • 1
    Possibility (1) `getLearner` is actually not returning a pointer to `NeuralNet`. Test `dynamic_cast(learner) == nullptr`. Possibility (2) typo in one of the method names is causing the derived class's method to NOT actually be an override. – Casey Nov 08 '13 at 20:36
  • 1
    @ScottCrunketon Make sure the Matrix type is the same. Put the two classes in the same file to be sure. Also make sure you don't have another SupervisedLearner class you are accidentally deriving from... – helb Nov 08 '13 at 21:00
  • @Casey Thanks for your test. It helped me locate the problem. See my answer for what was wrong. – crunk1 Nov 08 '13 at 21:11

2 Answers2

0

Try adding the keyword virtual to your child function, that way the compiler knows it is a virtual function. By not adding the virtual, you are implementing a completely new function: Object = (constructor, destructor another measure function, parent measure function) When you run the code, the compiler will decide which function to use

If you add virtual to your child function it will look like this: Object = (constructor, destructor, child measure function, parent measure function) When you run the code with this the compiler will use the child function

Lux
  • 1,540
  • 1
  • 22
  • 28
  • 1
    If you have a function declared virtual in a parent class, it will effectively be virtual in all child classes. It's good practice to add the virtual keyword in the children, but wouldn't affect the outcome in this case. – Charlie Nov 09 '13 at 01:43
0

I figured out the problem. The problem was happening with a decorator class between the lines:

SupervisedLearner* learner = getLearner(model, r, parser.getLearnerExtra());
...
double accuracy = learner->measureAccuracy(trainFeatures, trainLabels, &stats);

So, the code looked like:

SupervisedLearner* learner = getLearner(model, r, parser.getLearnerExtra());
...
learner = new Normalize( learner );
...
double accuracy = learner->measureAccuracy(trainFeatures, trainLabels, &stats);

The Normalize decorator looks like:

class Normalize: public SupervisedLearner {
private:
    SupervisedLearner* innerLearner;
public:
    Normalize(SupervisedLearner* learner) : learner(innerLearner) {}
    ...
}

The decorator did not override the SupervisedLearner method. Thanks everyone for the help. Thanks @Casey for the dynamic_cast(learner) == nullptr tip.

crunk1
  • 2,560
  • 1
  • 26
  • 32