C ++为每个派生类

时间:2017-07-31 18:36:13

标签: c++ inheritance interface static crtp

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

我有以下问题。

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

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

但是我当然不能简单地继承静态成员并期望它们在每个子类中都是唯一的。我试图使用奇怪的重复模板模式(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);
}

2 个答案:

答案 0 :(得分:1)

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

相反,您可以使用std::map和type-id哈希来执行类似操作,而无需使基类混乱。此外,这允许您使用任何类型,例如:

#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;
}

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

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

希望可以提供帮助。

答案 1 :(得分:0)

此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;
 }