模板作为C++中虚拟功能的替代品

Templates as an alternative to virtual functions in C++

本文关键字:虚拟 功能 替代品 C++      更新时间:2023-10-16

>我在基类中定义了一个昂贵的函数,它依赖于其派生类的低级信息:

class BaseClass{
 ...
 // Defined in derived class
 virtual int low_level(int)=0;
 // Expensive function depending on the pure virtual function
 void myExpensiveFunction(){
   for(...){
     for(...){
       for(...){
         ... = low_level(...);
         ...
       }
     }
   }
 }
};
class DerivedClass : public BaseClass{
   // A very cheap operation that can be inlined:
   inline virtual int low_level(int i){
     return a[i];
   }
   // Calling the base class function
   void test(){
     myExpensiveFunction();
   }
};

如果我理解正确,低级函数是虚拟的这一事实会阻止它在上面的代码中内联。现在,我正在考虑一种解决此问题的方法,并想到了以下解决方案,其中我将指向派生类成员函数的指针作为模板参数传递:

class BaseClass{
 ...
 // The function is now templated by the derived function:
 template<typename D, int (D::*low_level)(int)>
 void myExpensiveFunction(){
   for(...){
     for(...){
       for(...){
         ... = static_cast<D*>(this)->low_level(...);
         ...
       }
     }
   }
 }
};
class DerivedClass : public BaseClass{
   // A very cheap operation that can be inlined:
   inline int low_level(int i){
     return a[i];
   }
   // Calling the base class function
   void test(){
     myExpensiveFunction<DerivedClass,&DerivedClass::low_level>();
   }
};

这种策略有意义吗?我想当昂贵的基类函数在派生类中扩展时,低级操作将被内联。

我测试了实现它,它可以编译和工作,但我没有看到任何明显的性能差异。

亲切问候乔尔

使用指向基类的成员指针将要调用的函数传递给基类并不比使用虚函数真正改善。事实上,我预计这会让情况变得更糟。另一种方法是使用带有inline函数调用运算符的函数对象并调用 this。"正常"的方法是反转类层次结构并使用奇怪的重复模板模式:这个想法是创建一个模板,该模板将派生自其模板参数。模板参数应提供自定义点,例如函数low_level

根据情况,您还可以尝试完全避免继承,而是执行以下操作:

template<typename LL>
class HighLevel {
  LL lowLevel;
  public:
    HighLevel(LL const &ll) : lowLevel(ll) { }
    void myExpensiveFunction() {
      for(...) {
        for(...) {
          for(...) {
            ... = lowLevel.low_level(...);
            ...
          }
        }
      }
    }
};
class LowLevel {
  public:
    inline int low_level(int i) { // note: not virtual
      return a[i];
    }
};

用于:

HighLevel<LowLevel> hl;
hl.myExpensiveFunction();

如果您不希望不同类型的HighLevel<...>对象漂浮,则可以从抽象的非模板class HighLevelBase中派生所有这些对象,该该公开在模板中实现的virtual void myExpensiveFunction() = 0

这是否对你的情况有意义,如果没有更多信息,我无法判断,但我发现C++通常提供比继承更好的工具来解决特定问题。