带有接口对象的c++模板

C++ templates with interface objects

本文关键字:c++ 模板 对象 接口      更新时间:2023-10-16

我有以下无法编译的代码:

class Base {
    public:
        virtual ~Base() { };
};
class Derived : public Base { };
class NotDerived { };
template <typename T>
class Group { };
int main() {
    Group<Base> *g = NULL;
    g = new Group<Base>();       // Works
    g = new Group<Derived>();    // Error, but I want it to work
    g = new Group<NotDerived>(); // Error, as expected
}

我知道这不会编译,因为gGroup<Derived>是不同的类型。为了在Java中完成此工作,我会做一些诸如Group<? extends Base> g的事情,但据我所知,c++没有该关键字。我们能做些什么呢?

编辑:我想澄清一下,我不希望有可能将不从Base派生的类型设置为g。我已经更新了我的例子来解释这一点。

编辑2:我的问题有两个解决方案。我发现戴夫的方法很简单,很容易定义。但是Bowie的(以及Mark添加的)更适合我的需求。

Group<Base>Group<Derived>是完全不相关的,不同的类。指向它们的指针不能在任何方向上转换。

如果您需要运行时多态行为,您的类模板Group可以从一个公共的(非模板化的)基类派生:

class Group // base
{
   virtual ~Group() { }
};
template <typename T>
class ConcreteGroup : public Group
{
  // ...
  T * m_impl;
};
Group * g1 = new ConcreteGroup<A>;
Group * g1 = new ConcreteGroup<B>;

你可以把Group

所有Group T != Base.
class Base {
    public:
        virtual ~Base() { };
};
class Derived : public Base { };

template <typename T> class Group;
struct Empty { };
template <typename T>
struct base_for_group_t {
    typedef Group<Base> type;
};
template <>
struct base_for_group_t<Base> {
    typedef Empty type;
};
template <typename T>
class Group : public base_for_group_t<T>::type { };
int main() {
    Group<Base> *g = 0;
    g = new Group<Base>();    // Works
    g = new Group<Derived>(); //  now works
}

Bowie Owens's Answer处理解决原始问题所需的协方差。至于你在编辑问题中要求的约束,你可以通过使用类型特征来实现。

template <typename T, class Enable = void> class Group;
template <typename T>
class Group<T, typename enable_if<is_base_of<Base, T>::value>::type> 
    : public base_for_group_t<T>::type { };

我认为c++不支持这个。c++模板完全在编译时处理,所以它不支持多态性。这意味着在赋值表达式的两边,模板参数的类型应该完全相同。

我想我明白你的意思了。我不确定这是最好的方法(您可能想看看Boost.Factory)。

template <class T>
class Factory {
public:
  virtual T* operator()() = 0;
};
template <class Derived, class Base>
class ConcreteFactory : public Factory<Base> {
public:
  virtual Base* operator()() {
    return new Derived();
  }
};
class Base {
public:
  virtual ~Base() {};
};
class Derived1 : public Base { };
class Derived2: public Base {};
class NotDerived {};
int main()
{
  Factory<Base>* g;
  g = new ConcreteFactory<Derived1, Base>;
  g = new ConcreteFactory<Derived2, Base>;
  //  g = new ConcreteFactory<NotDerived, Base>; // Will not work if you try to do this
}