【问题标题】:Overloading c++ template class method重载c++模板类方法
【发布时间】:2010-12-24 11:14:43
【问题描述】:

我可以在扩展其特化的类中重载模板类函数吗?

我有以下一段代码(我已尝试将其简化到最低限度):

#include <iostream>

using namespace std;

class X {
 public:
  unsigned test_x() {
    return 1;
  }
};

class Y {
 public:
  unsigned test_y() {
    return 2;
  }
};

template <typename T, typename U>
class A {

 public: 

  unsigned foo(U i) {
    cout << "A" << endl;   
    return i.test_x();
  }

  unsigned bar(T i) {
    return foo(i);
  }

};

class B : public A<Y, X> {
 public:
  unsigned foo(Y i) {
    cout << "B" << endl;   
    return i.test_y();
  }
};

int  main() {

  B b = B();
  Y y = Y();
  cout << "Hello: " << b.bar(y) << endl;   
  return 0;

}

但是编译器会产生以下错误:

hello.cc: In member function ‘unsigned int A<T, U>::bar(T) [with T = Y, U = X]’:
hello.cc:47:   instantiated from here
hello.cc:30: error: no matching function for call to ‘A<Y, X>::foo(Y&)’
hello.cc:24: note: candidates are: unsigned int A<T, U>::foo(U) [with T = Y, U = X]

基本上我想在其派生类 B 中重载函数 A::foo()。

【问题讨论】:

    标签: c++ templates class


    【解决方案1】:

    显然你要问的是所谓的“静态多态性”,它是通过“奇怪地重复出现的模板模式”来实现的:

    template <typename Derived, typename T, typename U>
    class A {
     public:
    
      unsigned foo(U i) {
        cout << "A" << endl;   
        return i.test_x();
      }
    
      unsigned bar(T i) {
        return static_cast<Derived*>(this)->foo(i);
      }
    
    };
    
    class B : public A<B, Y, X> {
     public:
      // Uncomment this line if you really want to overload foo
      // instead of overriding. It's optional in this specific case.
      //using A::foo; 
    
      unsigned foo(Y i) {
        cout << "B" << endl;   
        return i.test_y();
      }
    };
    

    【讨论】:

      【解决方案2】:

      我不认为派生类中的重载不能从要调用它们的基类中使用。

      你可以做的是提取foo方法,这样你就可以将它专门用于B.

      #include <iostream>
      
      using namespace std;
      
      class X {
       public:
        unsigned test_x() {
          return 1;
        }
      };
      
      class Y {
       public:
        unsigned test_y() {
          return 2;
        }
      };
      
      template <typename T, typename U>
      struct Foo
      {
          unsigned foo(U i) {
          cout << "A" << endl;
          return i.test_x();
        }
      };
      
      template <typename T, typename U>
      class A : public Foo<T, U> {
      
       public:
        unsigned bar(T i) {
          return this->foo(i);
        }
      };
      
      template <>
      struct Foo<Y, X>
      {
       public:
        unsigned foo(Y i) {
          cout << "B" << endl;
          return i.test_y();
        }
      };
      
      class B : public A<Y, X> {
      };
      
      int  main() {
      
        B b = B();
        Y y = Y();
        cout << "Hello: " << b.bar(y) << endl;
        return 0;
      }
      

      【讨论】:

        【解决方案3】:

        编辑:我的第一个答案不正确。

        当您使用类YX 实例化A 时,foo(T) 的调用会产生错误,因为A 中没有定义适当的重载方法。在A中声明一个foo(T)的纯虚方法并在B中实现这个方法就足够了。

        template <typename T, typename U>
        class A {
        public: 
          virtual unsigned foo(T i) = 0;
          unsigned foo(U i) { /* as above */ }
          unsigned bar(T i) {
            return foo(i); // calls abstract foo(T)
          }
        };
        /* B is left untouched */
        

        编译它会生成这个输出:

        B
        Hello: 2
        

        【讨论】:

        • -1 没有抓住问题的重点。 OP 不想将A::fooB 类型的对象一起使用(名称隐藏问题),他想在A::bar 中使用B::foo(基类需要注意派生类中的重载)。跨度>
        • 我明白问题的重点。如果您不将A::foo 导入B 的范围B::foo 将完全隐藏A::foo。 OP 想用 B::foo 重载 A::foo 并且只适用于 using 声明。
        • 您可以尝试使用编译器来查看您的建议是否修复了代码。唯一调用foo 的地方是A::bar。就A 而言,B 可能存在也可能不存在,B 中的 using 声明完全无关。
        • 现在好多了。然而,现在这个变化打破了A。为了保持 A 的行为不变,该函数可能不应该是纯函数,而是实现为 virtual unsigned foo(T i) { return foo(static_cast&lt;U&gt;(i));} 它开始看起来 A 类可能在概念上首先被破坏了......
        猜你喜欢
        • 2021-10-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-12
        • 1970-01-01
        • 1970-01-01
        • 2018-05-27
        • 1970-01-01
        相关资源
        最近更新 更多