2011-12-22 82 views
3

我有一個類(Voxel)與子類可能或可能不具有許多不同的屬性(材料,密度等)與get和set方法。現在,我想要寫一些代碼如下:類型特徵與靜態成員的優點?

template <typename VoxelType> 
void process(VoxelType voxel) 
{ 
    if(VOXEL_HAS_MATERIAL) 
    { 
    //Do some work which involves calling get/setMaterial() 
    } 
    if(VOXEL_HAS_DENSITY) 
    { 
    //Do some work which involves calling get/setDensity() 
    } 
} 

因此,我要像落實VOXEL_HAS_MATERIALVOXEL_HAS_DENSITY部分。兩個簡單的選項是:

  1. 靜態hasMaterial()hasDensity()方法添加到Voxel類,在派生類中重寫。
  2. 創建一個類型特徵類hasMaterial()hasDensity(),並專門爲每個Voxel子類。

使用方法(2)允許爲原始類型(int等)定義特徵,但在我的情況下這沒有用。在這裏使用類型特徵是否還有其他優點,還是應該採用更簡單的靜態方法?

注意:我也知道基於SFINAE的方法,我將分別考慮。

編輯1:我已更改示例代碼以顯示使用模板。我正在尋找這個問題的靜態而非運行時解決方案。理想情況下,如果編譯器確定它們不能針對給定類型執行,編譯器將能夠去除if語句中的代碼。

+1

「無效過程(體素體素)」 - 你的意思是「SomeVoxelSubclass體素」? – Abyx 2011-12-22 09:29:50

+2

你是什麼意思「在派生類中重寫的靜態方法」? – 2011-12-22 09:30:27

+0

感謝您的評論 - 我實際上使用模板並更新了代碼示例以反映這一點。不想誤導我只是簡化了一些代碼;-) – PolyVox 2011-12-22 10:01:32

回答

2

類型特徵很有用,因爲它們可以很容易地添加到類型中,即使您無法更改類型本身。此外,使用類型特徵,你可以簡單地提供一個合理的默認值(例如,你可以將hasMaterialhasDensity委託給類的合適的靜態成員),然後你只需要對不適用於這個類的類進行特化默認。

+0

好的,謝謝,這些都很有用。 – PolyVox 2011-12-22 10:08:04

+0

在這個主題中有很多很好的信息,但是這個答案是最直接回答我的問題的答案。公認。 – PolyVox 2011-12-22 15:28:13

4

爲什麼這些方法應該是靜態的?只需在Voxel類中聲明方法virtual bool hasMaterial();virtual bool hasDensity();,並在任何子類中覆蓋它們。在子類中返回true,否則返回false。

你可以再做:

void process(Voxel* voxel) 
{ 
    if(voxel->hasMaterial()) 
    { 
     //Do some work which involves calling get/setMaterial() 
    } 
    if(voxel->hasDensity()) 
    { 
     //Do some work which involves calling get/setDensity() 
    } 
} 

然後,您可以創建一個類似與材料和密度的getter和setter類的接口,也讓他們繼承。

+0

與靜態成員或類型特徵相比,這會產生額外的運行時間開銷。 – 2011-12-22 09:34:21

+1

是的,但是它說他希望它完全優化? – 2011-12-22 09:35:50

+0

感謝您的評論,但我想要一個編譯時解決方案,以便理想情況下,冗餘if可以被編譯器刪除。在這種情況下,性能很重要。我更新了代碼以演示在我的代碼中使用模板。 – PolyVox 2011-12-22 10:06:19

2

靜態成員不能被覆蓋。你應該讓它們變成虛擬的。我想你的設計有問題,如果可能的話粘貼一些uml圖或你的源代碼。

+0

我不知道這個限制。我知道靜態成員不能是虛擬的,但我不知道你根本無法覆蓋它們。我會測試並進一步觀察。 – PolyVox 2011-12-22 10:10:00

+0

好吧,事實證明我的意思是'隱藏'而不是'重寫'。子類可以通過重新定義它們來隱藏基類中的靜態函數。 – PolyVox 2011-12-22 10:39:42

+0

我會建議你避免隱藏方法,這可能會在將來產生很多問題。我仍然認爲你的設計中存在某種問題。在這種情況下,UML圖表或源代碼可能有助於解決您的問題。 – AlexTheo 2011-12-22 11:15:40

1

不使用運行時,而是使用靜態檢查。

首先,定義該宏:

#define HAS_MEMBER_VARIABLE(NEW_STRUCT, VAR)         \ 
template<typename T> struct NEW_STRUCT {          \ 
    struct Fallback { int VAR; }; /* introduce member name "VAR" */    \ 
    struct Derived : T, Fallback { };           \ 
                       \ 
    template<typename C, C> struct ChT;           \ 
                       \ 
    template<typename C> static char (&f(ChT<int Fallback::*, &C::VAR>*))[1]; \ 
    template<typename C> static char (&f(...))[2];        \ 
                       \ 
    static bool const value = sizeof(f<Derived>(0)) == 2;      \ 
}; 

,其檢查在一個類是否存在一個成員變量。

然後使用SFINAE做一些事情,如果變量存在,像下面的例子:

#include <iostream> 

#define HAS_MEMBER_VARIABLE(NEW_STRUCT, VAR)         \ 
template<typename T> struct NEW_STRUCT {          \ 
    struct Fallback { int VAR; }; /* introduce member name "VAR" */    \ 
    struct Derived : T, Fallback { };           \ 
                       \ 
    template<typename C, C> struct ChT;           \ 
                       \ 
    template<typename C> static char (&f(ChT<int Fallback::*, &C::VAR>*))[1]; \ 
    template<typename C> static char (&f(...))[2];        \ 
                       \ 
    static bool const value = sizeof(f<Derived>(0)) == 2;      \ 
}; 

HAS_MEMBER_VARIABLE(x_check, x) 

struct A 
{ 
    int x; 
}; 
struct B 
{ 
    float notX; 
}; 

template< typename T, bool hasX = x_check<T>::value > 
struct doX 
{ 
    static void foo(const T & t) 
    { 
     std::cout<<"type has x variable, and it's value is "<<t.x<<std::endl; 
    } 
}; 
template< typename T > 
struct doX< T, false > 
{ 
    static void foo(const T &) 
    { 
     std::cout<<"type has no x variable"<<std::endl; 
    } 
}; 

template< typename T > 
void doFoo(const T& t) 
{ 
    doX< T, x_check<T>::value >::foo(t); 
}; 

int main() 
{ 
    A a; a.x = 6; 
    B b; b.notX = 3.6; 

    std::cout<<"Calling foo() on A : "; 
    doFoo(a); 
    std::cout<<"Calling foo() on B : "; 
    doFoo(b); 
} 
+0

這是一個很好的答案,但我確實聲明我知道基於SFINAE的方法,並會分開考慮它們。我會標記爲有用但不能接受爲正確的答案。 – PolyVox 2011-12-22 10:13:00