Question

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 :)

Was it helpful?

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

OTHER TIPS

In C++, name lookup stops in the scope where the name is found. (There are some exceptions, linked to ADL, but they don't apply here.) The reason for this is to avoid changing the semantics of functions in your derived if names are added to the Base class.

Typically, this shouldn't be a problem, because you should implement all of the virtual functions in an interface in all of the derived classes. And virtual functions and non-virtual functions shouldn't share names. In your case, what you probably want in the base class is something like:

class Module
{
private:
    virtual Module& doBind( Module& mod ) = 0;

public
    Module& bind( Module& mod )
    {
        //  pre-conditions
        Module& results = doBind( mod );
        //  post-conditions and invariants
        return results;
    }
    Module& bind( Mixer& mix )
    {
        //  pre-conditions
        Module& results = doBind( static_cast<Module&>( mod) );
        //  post-conditions and invariants
        return results;
    }
};

Derived classes will implement their own versions of doBind, but nothing else.

One thing, though. The conversion (Module&)mix, in a context where the compiler cannot see the full definition of Module, is a reinterpret_cast, which is almost certainly not what you want. I used static_cast in my example, to align with what you've done, but it is, in fact, illegal if the compiler cannot see the definition of Module. In this particular case, in fact, there is no need what so ever for the second bind function, since Mixer& will convert implicitly to Module&, without the need for a conversion on your part. (But it's quite possible that this code is just a very simplified example, and that in your real code, you're actually doing something more complex.)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top