2011-02-05 56 views
2

是否有可能以某種方式實現類模板,即如果一個對象的模板參數相關,則可以將其轉換爲另一個對象?這裏是一個的exaple顯示的想法(當然它不會編譯):如何在C++中實現模板類協方差?

struct Base {}; 
struct Derived : Base {}; 

template <typename T> class Foo { 
    virtual ~Foo() {} 
    virtual T* some_function() = 0; 
}; 

Foo<Derived>* derived = ...; 
Foo<Base>* base = derived; 

這裏的另一個問題是,foo是用作包含返回牛逼&和T *功能的接口一個抽象類,所以我不能實現模板拷貝構造函數。

我正在寫一個通用的迭代器類可以保存任何STL迭代器,並且除了類型擦除我想它是多態的,即我可以寫這樣的事:

std::list<Derived> l; 
MyIterator<Base> it(l.begin()); 

UPD :這是我的錯誤,我實際上並不需要將Foo *轉換爲Foo *來實現MyIterator,所以我認爲這個問題不再是現實。

+1

我非常懷疑'dynamic_cast`會做你想在這裏。 – aschepler 2011-02-05 18:21:59

+0

糟糕!你是對的,它返回NULL :) – lizarisk 2011-02-05 18:27:24

回答

4

模板參數與您指向的對象的內容無關。沒有理由這應該工作。爲了說明

struct Base { }; 
struct Derived : Base {}; 

template<typename T> struct A { int foo; }; 
template<> struct A<Base> { int foo; int bar; }; 

A<Derived> a; 
A<Base> *b = &a; // assume this would work 
b->bar = 0; // oops! 

你最終還是會訪問整數bar並不真正存在於a


好的,現在您已經提供了一些更多的信息,很明顯,您希望做一些完全不同的事情。下面是一些入門:

template<typename T> 
struct MyIterator : std::iterator<...> { 
    MyIterator():ibase() { } 
    template<typename U> 
    MyIterator(U u):ibase(new Impl<U>(u)) { } 
    MyIterator(MyIterator const& a):ibase(a.ibase->clone()) 

    MyIterator &operator=(MyIterator m) { 
    m.ibase.swap(ibase); 
    return *this; 
    } 

    MyIterator &operator++() { ibase->inc(); return *this; } 
    MyIterator &operator--() { ibase->dec(); return *this; } 
    T &operator*() { return ibase->deref(); } 
    // ... 

private: 
    struct IBase { 
    virtual ~IBase() { } 
    virtual T &deref() = 0; 
    virtual void inc() = 0; 
    virtual void dec() = 0; 
    // ... 

    virtual IBase *clone() = 0; 
    }; 
    template<typename U> 
    struct Impl : IBase { 
    Impl(U u):u(u) { } 
    virtual T &deref() { return *u; } 
    virtual void inc() { ++u; } 
    virtual void dec() { --u; } 
    virtual IBase *clone() { return new Impl(*this); } 
    U u; 
    }; 

    boost::scoped_ptr<IBase> ibase; 
}; 

然後你可以使用它作爲

MyIterator<Base> it(l.begin()); 
++it; 
Base &b = *it; 

你可能想看看any_iterator。有一點運氣,你可以使用該模板來達到你的目的(我還沒有測試過)。

+0

哦,這麼簡單!我寫了幾乎完全相同的代碼,但IBase和Impl作爲全局類(不是嵌套的) - 這是我誤認爲讓我卡住了,因爲Impl從Ibase繼承 :: value_type>,這與T不同,所以指針不是協變的。現在我把它們放在MyIterator中,一切正常:) – lizarisk 2011-02-06 00:16:17

1

Foo<Derived>不繼承Foo<Base>,所以你不能將前者轉換爲後者。此外,你的假設是錯誤的:dynamic_cast將失敗。

你可以創建一個Foo<Base>實例的新對象,它複製你的Foo<Derived>實例,但我想這就是你現在要找的。

4

雖然其他答案指出這種關係不是用模板「內置」的,但應該注意,可以構建功能來處理這種關係。例如,boost::shared_dynamic_cast and friends給出

class A { ... }; 
class B : public A { ... }; 

讓你boost::shared_ptr<A>boost::shared_ptr<B>之間施放。

請注意,如果您確實需要執行類似的操作,則必須注意MyIterator支持的操作。例如,使用您的MyIterator<Base>(std::list<Derived>::iterator)例如,你不應該有operator*()左值版本,例如,

*myIter = someBaseValue; 

不應該編譯。