c ++模板界面

时间:2009-07-13 21:31:44

标签: c++ class templates oop

最好用伪代码描述:

class Thing {};

interface ThingGetter<T extends Thing> {
    T getThing();
}

class Product extends Thing {};

class ProductGetter<Product> {
    Product getThing() {
        // Some product code
    }
}

class SpecialProductGetter extends ProductGetter {
    Product getThing() {
        p = ProductGetter::getThing();
        // Do some special stuff;
        return p;
    }
}

class NeatProductGetter extends ProductGetter {
    Product getThing() {
        p = ProductGetter::getThing();
        // Do some neat stuff;
        return p;
    }
}

我也会为其他人提供其他“吸引力”。

我已经尝试用C ++编写它,但它不喜欢:

template <> class ThingGetter <Product> {

也不:

class NeatProductGetter : public ThingGetter <Product> {
  1. 您是否可以使用C ++对此进行建模而不使getThing返回Thing然后必须像疯了一样投射它?
  2. 如果是这样,怎么样?如果没有,最好的方法是什么?
  3. 谢谢!

2 个答案:

答案 0 :(得分:1)

在C ++中,这看起来像这样: (我已经将“class”改为“struct”以避免一堆“public:”声明。但这是相同的。)

class Thing { };

template <typename T>
struct ThingGetter {
    T getThing();
};

struct Product : public Thing  { };

struct ProductGetter : public ThingGetter<Product>{
    Product getThing() { return Product(); }
};

struct SpecialProductGetter : public ProductGetter {
    Product getThing() {
        Product p = this->ProductGetter::getThing();
        return p;
    }
};

struct NeatProductGetter : public ProductGetter {
    Product getThing() {
        Product p = ProductGetter::getThing();
        return p;
    }
};

...

SpecialProductGetter spg;
spg.getThing();
NeatProductGetter npg;
npg.getThing();

另一种解决方案是使用模板专业化:

struct Thing { };
struct Widget { };

template <typename T>
struct Getter {
    T getIt() = 0;
};

template <>
struct Getter<Thing> {
    Thing getIt() { return Thing(); }
};

template <>
struct Getter<Widget> {
    Widget getIt() { return Widget(); }
};
typedef Getter<Widget> WidgetGetter;

struct SpecialWidgetGetter : public WidgetGetter {
    Widget getIt() { return this->WidgetGetter::getIt(); }
};

struct FizzledWidgetGetter : public WidgetGetter {
    Widget getFizzledWidget() { return getIt().fizzle(); }
};


...

Getter<Thing> tg;
tg.getIt();
WidgetGetter wg;
wg.getIt();

答案 1 :(得分:1)

由于问题来自具有Java背景的人,我将用Java术语解释它。您想要定义一个通用接口,该接口将返回从T:

派生的对象
template<typename T>
struct getter
{
   virtual T* get() = 0; // just for the signature, no implementation
};

注意更改:将函数声明为virtual,以便它在派生对象中表现为polimorphically。返回值是指针而不是对象。如果在对象中保留一个对象,编译器将切片(剪切返回对象的非基本部分)返回。使用一些元编程魔法(或求助于boost),您可以让编译器测试T从给定类型派生的约束。

现在问题是你想要这样做的原因......如果你定义一个返回Thing by指针的非泛型接口(抽象类),你可以更容易地获得相同的语义:

struct Thing {};
struct AnotherThing : public Thing {};
struct getter
{
   virtual Thing* get() = 0;
};
struct AnotherGetter : public getter
{
   virtual AnotherThing* get() { return 0; }
};
struct Error : public getter
{
    int get() { return 0; } // error conflicting return type for get()
};
struct AnotherError : public getter
{
};
int main() {
   AnotherError e; // error, AnotherError is abstract (get is still pure virtual at this level)
}

编译器将要求从getter派生的所有可实例化类实现一个get()方法,该方法返回一个Thing by指针(或一个协变返回类型:指向从Thing派生的类的指针)。如果派生类试图返回另一个类型,则编译器会将其标记为错误。

问题,就像你发布它一样,如果你使用接口,那么这些对象只能作为指向基本Thing类的指针来处理。现在,这是否是一个问题是另一个问题......一般来说,如果你已经正确设计了你的层次结构,你应该能够使用polimorphically使用返回的对象,而不必采用向下转换。

请注意,如果您在层次结构中使用最多派生级别的不同getter,则每个get()方法都会从Thing层次结构中返回派生最多的元素,此时您根本不需要向下转换元素。 。只有在基础getter界面中使用不同的getter时,您才能获得所有(Thing*

的相同返回类型

重要的是要注意模板在编译时完全解析。这意味着,如果你通过接口使用不同的getter(引用/指向基本的getter),试图使用模板来解决需要(你真的需要它吗?)对于向下转换将无法帮助你。

也许在您的特定域名上发布更多详细信息,您打算在何处以及如何使用此代码,可以帮助提供更有用的回复。