3

This is my situation:

class Filter3by3 {
public:
   virtual inline Mat convolution((Mat & mat, int i, int j, int rows, int cols) { 
 code

   }
};

class MySobel: public Filter3by3 {
public:
  inline Vec3b convolution(Mat & mat, int i, int j, int rows, int cols) {
    code
  }
};

Now, when I call:

Filter3by3 f = choose_filter(filtername); // Returns a Sobel filter
Mat mat;
s.convolution(args);

The base class method is called. I am quite newbie at c++ method binding rules, so can you tell me where I am wrong? I appreciate your help.

UPDATE It appears that even with virtual inline Mat convolution((Mat & mat, int i, int j, int rows, int cols) It does not work.

This is a running program, compiled with g++ -std=c++11

#include <iostream>

using namespace std;

class Filter {
public:
  Filter() { }
  virtual int ehi() {
    cout << "1" << endl;
    return 1;
  }

};

class SubFilter : public Filter {
public:
  SubFilter() : Filter() { }

  int ehi() {
    cout << "2" << endl;
    return 2;
  }

};

  Filter choose_filter(){
    SubFilter f;
    return f;
  }

  int main(int argc, char* argv[]) {

     Filter f = choose_filter();
     f.ehi();
     return 0;
  }

It prints 1 instead of 2. I used virtual to ensure dynamic binding, but it does not seem to be enough, also with "override" keyword.

diningphil
  • 416
  • 5
  • 18
  • 2
    To override a function it need to have the exact signature of the base class. Since you change the return-type you're not overriding the base-class function. However with the code you show the correct function should be called. Is that copy-paste from your *actual* code? Can you please try to create a [Minimal, Complete, and Verifiable Example](http://stackoverflow.com/help/mcve) and show us. – Some programmer dude Feb 04 '17 at 17:05
  • 1
    Regarding your edit, are you calling the virtual function on `f` or `s`? What is `s`? And if it's really `f` then you should probably be reading about [*object slicing*](http://stackoverflow.com/questions/274626/what-is-object-slicing). – Some programmer dude Feb 04 '17 at 17:12
  • Polymorphism only works using pointers or references to the base class. You have object slicing. – Some programmer dude Feb 04 '17 at 17:32
  • Advice: embrace `override`. – Jesper Juhl Feb 04 '17 at 17:38

3 Answers3

6

An overridden method has to have the same signature, i.e. argument and return types, as the base method. The compiler can notify you if these do not match if you add the override keyword to the signature.

The Techel
  • 918
  • 8
  • 13
  • 1
    Just one minor correction: covariant return types are okay, although rare. That is, different return types are allowed if the function in the base class and the function in the derived class both return pointers or both return references and the return type of the function in the derived class is a pointer or reference to a type that is derived from the type that the pointer or reference that the function in the base class returns. (Phew; that was exhausting!) e.g., `derived* D::f()` overrides `virtual base* B::f()` when `D` is derived from `B` and `derived` is derived from `base`. – Pete Becker Feb 04 '17 at 17:41
1

There's a keyword in c++ called override. It exactly solve the problem you mentioned:

struct MySobe l: Filter3by3 {
    inline Vec3b convolution(Mat & mat, int i, int j, int rows, int cols) override { code }
};

The presence of the override ensure that the method really overrides the base class method.

In your code, it will cause a compilation error because the derived class does not overrides, since the signature are different.

Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
1

When you assign an object of derived class to an object of base class like that, you not achieving dynamic dispatch, you achieve slicing (all of the additional data members of SubFilter are lost)

  Filter choose_filter(){
    SubFilter f;
    return f;
  }

Instead you should pass it by (safe) pointer or reference, like this:

  std::shared_ptr<Filter> choose_filter(){
    return std::make_shared<SubFilter>();
  }

  int main(int argc, char* argv[]) {

     auto f = choose_filter();
     f->ehi();
     return 0;
  }
w1ck3dg0ph3r
  • 1,011
  • 6
  • 5
  • Tried, but it doesn't compile – diningphil Feb 04 '17 at 18:08
  • `shared_ptr` and `auto` were introduced in c++11, also `#include ` for `shared_ptr`. Plain pointers or references would work the same, minus memory leak potential. [Check this out](http://en.cppreference.com/w/cpp/language/virtual). – w1ck3dg0ph3r Feb 04 '17 at 18:19