最好用伪代码描述:
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> {
Thing
然后必须像疯了一样投射它?谢谢!
答案 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),试图使用模板来解决需要(你真的需要它吗?)对于向下转换将无法帮助你。
也许在您的特定域名上发布更多详细信息,您打算在何处以及如何使用此代码,可以帮助提供更有用的回复。