C ++:继承函数并重新定义它们

时间:2014-02-21 11:38:25

标签: c++ function inheritance parent-child virtual

我在接口,继承和重新定义方面遇到了一些问题。在这种情况下,我不确定为什么C ++的行为如此,所以如果有人可以解释并帮助我。我有这个课程:

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() {}
};

所以,如果在我的主文件中我有这个:

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

  prod1.bind(prod2);

  return 0;
}

我收到此错误:

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

如果我有这个:

prod1.in_out::bind(prod2);

它按预期工作。

我不明白的是,编译器是否应该区分这些?

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

我想问题可能是mixerprod都是module(和in_out)的孩子。也许当在main中调用函数bind时,它会在prod的定义中查找它,并且只找到bind(mixer)?那么bind(module)呢?在这种情况下它是私有的吗?

我想要的是,无论我拨打prod.bind(prod)还是prod.bind(mixer),它都会在prod的级别区分它们,所以我不必致电{ {1}}从那里开始。

非常感谢:)

2 个答案:

答案 0 :(得分:3)

问题是当你定义了类prod并声明了函数bind

virtual module& bind(mixer &mix);

在类范围中,您隐藏了具有相同基类名称的所有其他函数。那么你打电话给

prod1.bind(prod2);

编译器在类范围内只看到一个候选者:上面显示的函数。并且它无法将参考产品转换为参考混频器。

你应该在课程定义中写一下

using in_out::bind;

正如 @Alex 在他的评论中指出的那样,如果使用多态,你必须使类模块的析构函数成为虚拟。

编辑:如果要将pfn_inout替换为in_out,因为没有pfn_inout的定义,则会成功编译以下代码

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

答案 1 :(得分:1)

在C ++中,名称查找在找到名称的范围内停止。 (有一些例外,与ADL相关,但它们不适用 这里。)原因是为了避免改变语义 如果将名称添加到Base,则派生中的函数 类。

通常,这应该不是问题,因为你应该这样做 在所有的接口中实现所有虚函数 派生类。而虚拟功能和非虚拟功能 函数不应共享名称。在你的情况下,你是什么 可能在基类中想要的是:

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

派生类将实现自己的doBind版本, 但没有别的。

但有一件事是。转化(Module&)mix,在上下文中 编译器无法看到Module的完整定义, 是reinterpret_cast,几乎可以肯定不是 你要。我在我的示例中使用了static_cast来与之对齐 你做了什么,但实际上,如果编译器是非法的 看不到Module的定义。在这种特殊情况下, 事实上,第二个bind没有必要。 函数,因为Mixer&会隐式转换为Module&, 无需您进行转换。 (但它确实如此 可能这个代码只是一个非常简单的例子,而且 在你的真实代码中,你实际上正在做更多的事情 复杂。)