【问题标题】:Odd behavior with inheritance and c++继承和 C++ 的奇怪行为
【发布时间】:2012-11-08 03:00:14
【问题描述】:

所以我在尝试制作的一些类层次结构中出现了一些奇怪的行为。我正在实现图形,我正在通过制作一个将由 AdjacencyMatrixGraph 和 AdjacencyListGraph 实现的 Graph 类来做到这一点,因此它们可以用作用任何想要使用它们的东西来绘制图表。

我在 Graph 中有一个纯虚函数,它被 AdjacencyMatrixGraph 中的函数覆盖,但是我有一个同名的非虚函数,但在 Graph 中有不同的签名。访问 AdjacencyMatrix 类时,我无法调用 Graph 类的非虚拟方法,但是当我重命名非虚拟方法时,它可以正常工作。

像这样:

当类看起来像这样时

class Graph
{
public:
   virtual void addVertex(Vertex vert, bool bidirectional)=0;
   void addVertex(unsigned int from, unsigned int to, double weight, bool bidirectional)
}

class AdjacencyMatrixGraph : public Graph
{
...
}




AdjacencyMatrixGraph test;
Vertex vert;
test.addVertex(vert,false);   //this statement compiles and works fine
test.addVertex(0,0,10.f,false)  //this statement fails to compile and says cadidates are addVertex(Vertex, bool)

但是,如果我像这样重命名非虚拟方法

class Graph
{
public:
   virtual void addVertex(Vertex vert, bool bidirectional)=0;
   void addVert(unsigned int from, unsigned int to, double weight, bool bidirectional)
}

AdjacencyMatrixGraph test;
Vertex vert;
test.addVertex(vert,false);   //this statement compiles and works fine
test.addVert(0,0,10.f,false)  //this statement compiles and works fine

这对我来说毫无意义,因为我认为编译器将 addVertex(Vertex, bool) 和 addVertex(unsigned int,unsigned int, double, bool) 视为两个完全不同的符号。所以不应该被继承覆盖,即使它不应该是不可能的,因为符号采用不同的参数。

【问题讨论】:

    标签: c++ inheritance virtual subclass superclass


    【解决方案1】:

    在这种情况下,AdjacencyMatrixGraph 隐藏了Graph::addVertex(unsigned int from, unsigned int to, double weight, bool bidirectional)。要将函数带入作用域,请使用using 声明,如下所示:

    class A
    {
    public:
    virtual void foo(int) = 0;
    virtual void foo(std::string) { std::cout << "foo(string)" << std::endl; }
    };
    
    class B : public A
    {
    public:
    using A::foo; //this unhides A::foo(std::string)
    virtual void foo(int) { std::cout << "foo(int)" << std::endl; }
    };
    
    int main()
    {
    B b;
    b.foo(1);
    b.foo("hello");
    }
    

    【讨论】:

      【解决方案2】:

      派生类中的定义隐藏基类重载声明。

      要将它们带入派生类的范围,请使用using 声明,例如

      using Graph::addVertex;
      

      在派生类中。

      顺便说一句,这是FAQ。在询问之前检查常见问题解答通常是个好主意。甚至只是一般情况下。 :-)

      【讨论】:

      • 这很有帮助,谢谢,但是为什么呢?虽然我可以继续我的工作,但知道为什么会发生这种情况对我的帮助不仅仅是知道我发生了。
      • @TheDude:对于“为什么”没有真正好的答案,这只是一个艰难的语言设计决策。使用当前规则,通过派生定义隐藏基类重载与通过在内部范围中定义具有相同名称的变量来隐藏外部范围变量(例如)的工作方式相同。因此,现行规则强调统一规则。此外,当前规则防止在基类中添加重载 M,以免(默认情况下)影响具有 M 的派生类的代码中的重载决议。因此当前规则还强调 可预测性。可以做出其他选择。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多