是否有任何关键字可以在模板化派生类中重新定义模板化基类的“所有”方法?

时间:2010-02-19 00:22:27

标签: c++

我知道这看起来像一个愚蠢的问题,但在C ++中使用带有模板的面向对象的东西真的很麻烦。 例如,Foo是基类:

template <typename T>
class Foo {
  public:
    virtual void Method1() { }
    virtual void Method1(int a) { }
    virtual void Method2() { }
    virtual void Method2(int a) { }
    //... lots of other methods
};

是否有类似的东西:

template <typename T>
class Bar : public Foo<T> {
  public:
    using Foo<T>::*; //redefine all inherited methods from Foo
    virtual void Method1(int a) { }
    virtual void Method2(int a) { }
    //other methods overloading..
};

而不是:

template <typename T>
class Bar : public Foo<T> {
  public:
    using Foo<T>::Method1
    using Foo<T>::Method2
    //... lots of other methods

    virtual void Method1(int a) { }
    virtual void Method2(int a) { }
    //other methods overloading..
};

所以我们可以这样做:

int main() {
  Bar<int> b;
  b.Method1();
  b.Method2();
  //... lots of other methods

  //This obviously works without the 'using' keyword:
  Foo<int>* f = &b;
  f->Method1();
  f->Method2();
  //etc
  return 0;
}

3 个答案:

答案 0 :(得分:3)

不,没有类似的功能,但通常不需要。基本继承机制已经提供了您打算使用using做什么。

如果派生类中的重载隐藏了基类中的方法,或者您想要更改访问模式, 需要才能使用using

class A {
    void f() {}
public:
    void g(int) {}
    void h(int) {}
};

struct B : A {
    using A::f; // make f public
    void g(double) {}
    using A::g; // otherwise A::g is hidden by the overload
    // using A::h isn't needed
};

请注意,您仍然可以通过A::h()实例调用B,因为没有任何内容隐藏它。

答案 1 :(得分:0)

没有。模板特化是不与一般模板继承或以其他方式相关的单独类型。你应该确保它们具有相同的隐式接口,而C ++并不能使它变得特别容易。

另请参阅最近的这个问题,这很可能是您正在寻找的问题。 subclass as specialization - ie: adding a method in the specialization

答案 2 :(得分:0)

<强> 1。隐藏的是什么

我担心你的小例子有问题,我怀疑你的问题出在Hiding

让我们来说明Hiding是第一个:

struct Base { void foo(int) { std::cout << "Base" << std::endl; } };

struct Derived: Base { void foo(float) { std::cout << "Derived" << std::endl; } };

int main(int, char* argv[])
{
  Derived d;
  int integer = 1;
  float floating = 2;
  d.foo(floating);     // outputs "Derived" as expected
  d.foo(integer);      // outputs "Derived" too UhOh ?
}

这个问题被称为Hiding,这是编译时名称解析的问题。问题是在应用重载规则选择“正确”方法之前,编译器首先需要编译要考虑的方法集。为此,它将查看最专业的范围,然后一次向外扩展一个范围,直到找到它正在寻找的名称。不幸的是(出于效率原因,我猜),一旦找到具有名称的函数,它就会停止。

所以这里发生的是:

  1. foo中查找名为Derived的方法:{ void Derived::foo(float) }
  2. 然后停止......因此,在尝试解析foo int参数时,它会选择到目前为止看到的唯一方法,这可能有点令人惊讶。

    你是正确的,你可以用using关键字来胜过它,它带来了另一个范围的名称,以便编译器考虑它们。如果我在using Base::foo;定义中添加Derived,编译器将执行:

    1. foo中查找名为Derived的方法:{ void Derived::foo(float) } + using
    2. foo中添加名为Base的方法:{ void Derived::foo(float), void Base::foo(int) }
    3. 因此,你得到了你所希望的。

      <强> 2。如何重新定义方法

      既然您知道Hiding是什么,以及如何规避它,我想借此机会解决您的示例缺陷。

      你不应该重新定义这样的方法:

      struct Base { void foo(int) const { std::cout << "Base" << std::endl; } };
      struct Derived: Base { void foo(int) const { std::cout << "Derived" << std::endl; } };
      

      这里的问题是它只是Hiding而且可能会令人惊讶。

      void fooize(const Base& b) { b.foo(); }
      
      int main(int argc, char* argv[])
      {
        Derived d;
        d.foo();          // output "Derived"
        fooize(d);        // output "Base"
      }
      

      如果您想重新定义,则需要使用virtual关键字。然后你会用这种方式纠正你的课程:

      struct Base
      {
        virtual ~Base() {}       // Polymorphism means virtual destructor
        virtual foo(int) const { std::cout << "Base" << std::endl; }
      };
      
      struct Derived: Base
      {
        virtual ~Derived() {}    // Not necessary, but sweet reminder
        virtual foo(int) const;  // virtual not necessary, but a sweet reminder again :)
      };
      

      然后它将按预期工作。

      第3。多态烹饪书

      • 您不应重新定义非virtual
      • 的方法
      • 多态性因此意味着virtual Destructor(因为它将被重新定义)
      • 继承介绍多态,如果你不想要它,请使用Composition

      令人遗憾的是(对于Composition)C ++中没有“委托”概念,但是我们必须处理我们已经给出的卡片。

      最后要注意的是:如果该类有很多方法......它可能会受益于重新设计(请参阅std::string以获取不应该做的示例)。