【问题标题】:C++ Separated static field for each derived class每个派生类的 C++ 分隔静态字段
【发布时间】:2018-01-07 10:43:50
【问题描述】:

想解决我的问题很长一段时间,当我没有其他想法只能在这里问时,我终于明白了。

我有以下问题。

短版。如何从基类继承静态字段,但在每个派生类中使其唯一并保持将这些类向上转换为父类的可能性?

长版。我需要为一组类创建某种基本接口。这些类中的每一个都需要有一个静态字段和一个静态方法。但我希望能够将所有这些类作为参数传递给一个使用这些静态成员的通用函数。所以我在考虑从一个基类继承它们。

但我当然不能简单地继承静态成员并期望它们在每个子类中都是唯一的。我试图使用奇怪重复模板模式(CRTP),但它迫使我也制作这个通用函数模板,并在每次调用期间直接给它类名。这对我不利。

此外,当使用多级继承时(即,当我想从派生自此模板基类的类派生一个类时)时,我在使 CRTP 工作时遇到问题。有什么办法可以达到我的需要吗?

我知道已经有人问过类似的问题,但其中大多数作者都对 CRTP 感到满意。对我来说,这似乎还不够好。

 //pseudo-code for what I need, doesn't work of course
class Base {
public:
   static int x;
   static int GetX() {return x;}
}

class Derived : public Base {};
class NextDerived : public Derived {};
class NextDerived2 : public Derived {};

void Foo(Base& a) {a.x = 10;}

int main {
    NextDerived d;
    NextDerived2 d2;
    Foo(d);
    Foo(d2); //both Foos modify different static variables
}

//CRTP attempt
template <class C> 
class Base {
public:
   static int x;
   static int GetX() {return x}
};

class Derived : public Base<Derived> {};
int Derived::x = 0;

template <class C>
void Foo(Base<C>& b) {
   b.x = 10;
   return;
};

int main() {
   Derived d;

   Foo<Derived>(d);
}

【问题讨论】:

  • 这听起来像是模板的工作。
  • CRTP 是您问题的解决方案。我看不到任何其他方法可以为每个子类设置不同的静态变量。 CRTP 解决方案有什么问题?
  • 你为什么写Foo&lt;Derived&gt;(d);Foo(d); 应该没问题。
  • 为什么要将它们保留在基类中?将静态数据移动到派生类并使用虚拟接口来访问它们。您可以在派生类上使用 CRTP。或者在基类上使用 CRTP 并制作一个更通用的基类,使用 virtual 来访问您需要的内容。
  • @AndreasH。哇。这么简单的错误,我因此浪费了好几天。我一定在某处听说过这种调用模板函数的方式。我还不太擅长模板。我刚刚测试了你的建议,它就像一个魅力。我什至可以从 Derived 派生另一个类,它仍然有效。似乎是一个解决方案:D

标签: c++ inheritance interface static crtp


【解决方案1】:

请记住,还必须定义静态变量。因此,对于需要单独静态变量的每个派生类型,您也需要定义它。

相反,您可以使用 std::map 和类型 ID 哈希来执行类似的操作,而无需弄乱您的基类。此外,这允许您使用 any 类型,例如:

#include <iostream>
#include <map>
#define out(v) std::cout << v << std::endl

static std::map<std::size_t, int> ExsAndOhs;

template < typename T >
static std::size_t type_id() // in case you don't want RTTI on
{
    static char tid;
    return reinterpret_cast<std::size_t>(&tid);
}

template < typename T >
void Foo(int _x) { ExsAndOhs[type_id<T>()] = _x; }

template < typename T >
void Foo(T& obj, int _x) { ExsAndOhs[type_id<T>()] = _x; }

template < typename T >
void Print() { out(ExsAndOhs[type_id<T>()]); }

template < typename T >
void Print(T& obj) { out(ExsAndOhs[type_id<T>()]); }


class Base {};
class Derived : public Base {};
class D2 : public Base {};

int main(int argc, char* argv[])
{
    // using explicit templates
    Foo<Base>(100);
    Foo<Derived>(10);
    Foo<D2>(42);
    Foo<long>(65535);
    Foo<int>(1955);
    Print<Base>();
    Print<Derived>();
    Print<D2>();
    Print<long>();
    Print<int>();


    Base b;
    Derived d;
    D2 d2;
    int x = 1;
    long y = 1;
    // using template deduction
    Foo(b, 10);
    Foo(d, 42);
    Foo(d2, 100);
    Print(b);
    Print(d);
    Print(d2);
    Print(x); // still prints 1955
    Print(y); // still prints 65535

    return 0;
}

这也避免了声明每个派生类静态成员的需要。

对于您的特定用例,这可能不是一个好的解决方案,但它是实现您所要求的替代方案。

希望能有所帮助。

【讨论】:

    【解决方案2】:

    这种 CRTP 样式适合您吗?

     #include <iostream>
    
     using namespace std;
    
     template<class T>
     class Base {
     public:
        static int x;
        static int GetX() {return x;}
     };
    
     template<class T>
     class Derived : public Base <Derived<T> >{};
     class NextDerived : public Derived<NextDerived> {};
     class NextDerived2 : public Derived<NextDerived2> {};
    
     static int count = 0;
    
     template<class T> int Base<T>::x = 0;
    
    
     template<class T>
     void Foo(Base<Derived<T> >& a) {
         a.x = count++;
     };
    
     int main() {
         NextDerived d;
         NextDerived2 d2;
         Foo(d);
         Foo(d2);
    
         cout << d.GetX() << " " << d2.GetX() << endl;
         return 0;
     }
    

    【讨论】:

      猜你喜欢
      • 2010-11-22
      • 2011-08-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-16
      • 2011-09-23
      • 2016-03-27
      • 1970-01-01
      相关资源
      最近更新 更多