Search code examples
c++functioninheritanceparent-childvirtual

C++: inheriting functions and redefining them


I am having some problems with interfaces, inheritance and redefinition. In this case I am not sure why exactly C++ behaves like this, so if someone could explain and help me with this. I have this classes:

module.h:

class mixer;

class module {

public:

  module(std::string name_) : name(name_) {}
  ~module() {}

  virtual module& bind(module &mod) = 0;
  virtual module& bind(mixer &mix) { return ((module&)mix); }

  std::string get_name() 
  {
    return name;
  }

  std::string name;
};

in_out.h:

class in_out : public module {

public:

  in_out(std::string name_) : module(name_) {}
  ~in_out() {}

  virtual module& bind(module &mod)
  {
    std::cout << "bind in_out in " << mod.name << std::endl;
    return mod;
  }

};

prod.h:

class prod : public in_out {

public:

  prod(std::string name_)
    : in_out(name_)
  {}

  ~prod() {}

  virtual module& bind(mixer &mix)
  {
    std::cout << "bind mixer in " << get_name() << std::endl;
    return mix;
  }

};

mixer.h:

class mixer : public in_out {

public:

  mixer(std::string name_)
    : in_out(name_)
  {}

  ~mixer() {}
};

So, if in my main file I have this:

int main(int argc, char *argv[])
{
  prod  prod1("prod1");
  prod  prod2("prod2");
  mixer mixer1("mixer1");
  mixer mixer2("mixer2");

  prod1.bind(prod2);

  return 0;
}

I get this error:

main.cpp: In function ‘int main(int, char**)’:
main.cpp:12:19: error: no matching function for call to ‘prod::bind(prod&)’
main.cpp:12:19: note: candidate is:
prod.h:19:23: note: virtual pfn_module& prod::bind(mixer&)
prod.h:19:23: note:   no known conversion for argument 1 from ‘prod’ to ‘mixer&’
make: *** [main] Error 1

If I have this instead:

prod1.in_out::bind(prod2);

It works as expected.

What I do not understand is, shouldn't the compiler distinguish between these?

virtual module& bind(module &mod) = 0;
// and
virtual module& bind(mixer &mix) { return ((module&)mix); }

I guess the problem could be that both mixer and prod are child of module (and in_out). Maybe when the function bind is called in main, it looks for it in the definition of prod and only finds bind(mixer)? What about bind(module)? Is it private in that context?

What I would like to have is, no matter what I call prod.bind(prod) or prod.bind(mixer), it distinguishes them at prod's level, so I don't have to call .in_out from there.

Thanks a lot :)


Solution

  • The problem is that when you defined class prod and declared function bind

    virtual module& bind(mixer &mix);
    

    in the class scope you hided all other functions with the same name of the base class. So then you called

    prod1.bind(prod2);
    

    the compiler sees only one candidate in the class scope: the function shown above. And it can not convert reference prod to reference mixer.

    You should write in the class definition

    using in_out::bind;
    

    And as @Alex pointed out in his comment you have to make the destructor of class module virtual if you use polymorphism.

    EDIT: If to substitute pfn_inout for in_out because there is no definition of pfn_inout then the following code is compiled successfuly

    #include <iostream>
    #include <string>
    
    class mixer;
    
    class module {
    
    public:
    
      module(std::string name_) : name(name_) {}
      ~module() {}
    
      virtual module& bind(module &mod) = 0;
      virtual module& bind(mixer &mix) { return ((module&)mix); }
    
      std::string get_name() 
      {
        return name;
      }
    
      std::string name;
    };
    
    class in_out : public module {
    
    public:
    
      in_out(std::string name_) : module(name_) {}
      ~in_out() {}
    
      virtual module& bind(module &mod)
      {
        std::cout << "bind in_out in " << mod.name << std::endl;
        return mod;
      }
    
    };
    
    class mixer : public in_out {
    
    public:
    
      mixer(std::string name_)
        : in_out(name_)
      {}
    
      ~mixer() {}
    };
    
    class prod : public in_out {
    
    public:
        using in_out::bind;
    
      prod(std::string name_)
        : in_out(name_)
      {}
    
      ~prod() {}
    
      virtual module& bind(mixer &mix)
      {
        std::cout << "bind mixer in " << get_name() << std::endl;
        return mix;
      }
    
    };
    
    
    int main() 
    {
      prod  prod1("prod1");
      prod  prod2("prod2");
      mixer mixer1("mixer1");
      mixer mixer2("mixer2");
    
      prod1.bind(prod2);
    
        return 0;
    }