2017-07-31 59 views
3

長時間以來,我一直在考慮解決我的問題,而當我沒有其他想法時,我終於明白了,只是在此問一問。C++每個派生類的分隔靜態字段

我有以下問題。

簡短版本。如何從基類繼承靜態字段,但在每個派生類中使其唯一,並保留將這些類轉發到父類的可能性?

長版。我需要爲一組類創建一些基本接口。每個類都需要有一個靜態字段和一個靜態方法。但我希望能夠將所有這些類作爲參數傳遞給一個使用這些靜態成員的通用函數。所以我在考慮從一個基類繼承它們。

但我當然不能簡單地繼承靜態成員,並期望它們在每個子類中都是唯一的。我試圖使用好奇的循環模板模式(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); 
} 
+0

這聽起來像一個模板的工作。 –

+1

CRTP是解決您的問題的方案。我沒有看到任何其他方式爲每個子類使用不同的靜態變量。 CRTP解決方案有什麼問題? –

+0

爲什麼寫'Foo (d);'? 'Foo(d);'應該很好。 –

回答

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

這也避免了需要聲明的每個派生類的靜態成員。

對於您的特定用例,這可能不是一個好的解決方案,但它是實現您要求的另一種選擇。

希望能有所幫助。

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