2

是否有可能以这样一种方式实现一个类模板,如果它们的模板参数相关,一个对象可以转换为另一个对象?这是一个展示这个想法的例子(当然它不会编译):

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& 和 T* 的函数的接口,因此我无法实现模板复制构造函数。

我正在编写一个通用的 Iterator 类,它可以容纳任何 STL 迭代器,除了类型擦除之外,我还希望它是多态的,即我可以写这样的东西:

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

UPD:那是我的错误,我实际上不需要将 Foo* 转换为 Foo* 来实现 MyIterator,所以我认为这个问题不再实际。

4

3 回答 3

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。运气好的话,您可以将该模板用于您的目的(我还没有测试过)。

于 2011-02-05T18:28:00.247 回答
4

虽然其他答案指出这种关系不是模板“内置”的,但您应该注意,可以构建功能来处理这种关系。例如,boost::shared_dynamic_cast和朋友给出的

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

让你在boost::shared_ptr<A>and之间转换boost::shared_ptr<B>

请注意,如果您确实要实现这样的事情,则必须小心 MyIterator 支持的操作。例如,使用你的例子MyIterator<Base>(std::list<Derived>::iterator),你不应该有一个左值版本operator*(),例如,

  *myIter = someBaseValue;

不应该编译。

于 2011-02-05T18:49:39.663 回答
1

Foo<Derived>不继承Foo<Base>,所以你不能将前者转换为后者。此外,您的假设是错误的:dynamic_cast将失败。

您可以创建一个新的实例对象Foo<Base>来复制您的Foo<Derived>实例,但我想这就是您现在要寻找的。

于 2011-02-05T18:28:53.970 回答