2013-07-11 61 views
1

讓我們假設我有類這樣的結構:基類Object,其是用於BoolIntFloatBytesUnicode類父類。在我有一些功能,如Bool cast_bool() constInt cast_int() const等作爲Object類和所有子類中的虛擬函數之前,我已經分別實現了這些功能。C++:在父類覆蓋模板的成員函數

看來更好的解決方案是實現template <typename TYPE> TYPE cast() const函數。但是,由於C++禁止虛擬模板功能,我不知道如何完成此任務。我需要的是爲Object及其孩子提供template <typename TYPE> TYPE cast() const。通用Object::cast<TYPE>() const只會丟CastError;那麼對於每一個類型,如Bool,Int等,我將實現像Bool::cast<Bool>() const,Int::cast<Bool>() const等功能,我甚至計劃添加投到內置對象,但現在我只是超載operator bool() const,operator signed short() const等如果沒有實現中,模板必須從Object類切換到其通用形式,只是拋出一個錯誤。有沒有辦法做到這一點(也許我需要使用一些模式)?或者更容易離開Int cast_int() const等功能?提前致謝!

+0

如果您的數據轉換存儲在基類中,則沒有理由不能將模板成員函數添加到同一基類。然後讓子類調用它。或者,也許我誤解了這個問題。 – Twifty

回答

0

你在做什麼聽起來並不像一個很好的主意,C++是不是Java或C#...不過你可以做到這一點是這樣的:

class Object 
{ 
public: 

    template<typename T> 
    T& cast() 
    { 
      return cast_impl(std::declval<T>()); 
    } 

private: 
    virtual bool& cast_impl(bool&){ throw std::bad_cast(); } 
    virtual int& cast_impl(int&){ throw std::bad_cast(); } 
}; 

class Boolean : public Object 
{ 
    bool value_; 
public: 

private: 
    bool& cast_impl(bool) override 
    { 
     return value_; 
    } 
}; 
0

你可以保持一組標誌

enum Castablity{ 
    intable = 0x1, 
    floatable = 0x2, 
    doubleable = 0x4, 
    bytable = 0x8, 
    stringable = 0x10, 
    unicodable = 0x20, 
}; 

並在這些類別中保留一個virtual int castable() const函數,例如您的Int::castable()將返回intable | floatable | doublable | stringable。並且YOu需要另一個模板化映射,它在typedef中使用Castablity枚舉值並返回目標類型。

​​

和全球投功能

template <typename T, typename U> 
U cast(const T& original){ 
    if(!original.castable(type_value<U>::value)) 
     //throw exception 
    return detail::cast<U>(original.internal_data()); 
} 

你可以有將一個整數值,而不是在編譯時採取類型的虛擬方法。或者你可以有一個內部結構來存儲所有類型的對象值。像boost::any

,你可以寫詳細的命名空間的另一個專業化,將轉換,內部類型到目標類型

namespace detail{ 
    template <typename T> 
    /// you may have specialization for different types 
    struct casting_helper{ 
    static T cast(const internal_type& data){ 

    } 
    } 
    template <typename T> 
    T cast(const internal_data& data){ 
     return casting_helper<T>::cast(data); 
    } 
} 
3

在本例中添加一箇中間類像下面或只使用dynamic_cast沒有任何模板方法。

#include <iostream> 
#include <string> 
using namespace std; 

template <class> class ObjectImpl; 

class Object 
{ 
public: 
    virtual ~Object() {} 

    template <class T> 
    T cast() const 
    { 
     if (auto obj = dynamic_cast<const ObjectImpl<T>*>(this)) 
     { 
      return obj->cast(); 
     } 
     else 
     { 
      throw std::string("cast error"); 
     } 
    } 
}; 

template <class T> 
class ObjectImpl : public Object 
{ 
public: 
    virtual T cast() const = 0; 
}; 

class Bool : public ObjectImpl<bool> 
{ 
public: 
    bool cast() const override { return true; } 
}; 
class Float : public ObjectImpl<float> 
{ 
public: 
    float cast() const override { return 12.34f; } 
}; 

int main() 
{ 
    Object* obj = new Float; 

    cout << obj->cast<float>() << endl; 

    try 
    { 
     cout << obj->cast<bool>() << endl; 
    } 
    catch (std::string e) 
    { 
     cout << e << endl; 
    } 

    return 0; 
} 
0

另一種替代方法,如果你對運行時轉換很好。

class Object 
{ 
public: 

    template<typename T> 
    T& cast() 
    { 
      return *dynamic_cast<T*>(get()); 
    } 

private: 
    virtual void* get() = 0; 
}; 

class Boolean : public Object 
{ 
    bool value_; 
public: 

private: 
    void* get() override 
    { 
     return &value_; 
    } 
} 
0

您可以爲該對象創建一個類型包裝。

struct TypeWrapperBase 
{ 
protected: 
    static int m_counter; 
}; 

int TypeWrapperBase::m_counter = 0; 

template<typename T> 
struct TypeWrapper: 
    TypeWrapperBase 
{ 
    static int m_type; 
protected: 
    static int AllocateType() 
    { 
     m_counter++; 
     return m 
    } 
public: 
    static int GetType() 
    { 
     return m_type; 
    } 
}; 

template<typename T> 
int TypeWrapper<T>::m_type = TypeWrapperBase::m_counter++; 

void main() 
{ 
    std::cout << TypeWrapper<int>::GetType() << std::endl; // prints 0 
    std::cout << TypeWrapper<float>::GetType() << std::endl; // prints 1 
    std::cout << TypeWrapper<bool>::GetType() << std::endl; // prints 2 
} 

現在,您可以通過比較el1.GetType()和el2.GetType()來模擬任何對象。如果相等,則可以執行靜態轉換