[英]C++ Templates and Subclasses?
所以,我正在学习C ++,而且我遇到了一些我知道如何用Java做的事情,而不是用C ++ :)。
我有一个容器对象的模板,定义如下:
template <class T>
class Container {
vector<T> contained;
public:
void add(T givenObject) {
this->contained.push_back(givenObject);
}
T get(string givenIdentifier) throw (exception) {
for (int i = 0; i < this->contained.size(); i++) {
if (this->contained[i].getIdentifier() == givenIdentifier) {
return this->contained[i];
}
}
throw new exception("An error has occured which has caused the object you requested to not be found. Please report this bug.");
}
bool empty() {
return this->contained.empty();
}
bool identifierExists(string givenIdentifier) {
for (int i = 0; i < this->contained.size(); i++) {
if (this->contained[i].getIdentifier() == givenIdentifier) {
return true;
}
}
return false;
}
};
这实际上非常有效,只有一个小问题。 它归结为两行:第一行是模板定义,第二行是
this->contained[i].getIdentifer()
在Java中,当声明Generic(模板)时,可以定义一个超类/接口,T的所有成员必须扩展它才能不创建错误。 但是,我不确定在C ++中这样做的方法,我担心的是将这里的实现耦合到一个可能没有定义的getIdentifier方法是糟糕的设计。
现在,如果是这样的话,这不是一个大问题,这只是一个帮助我学习语言的挑战项目,但我喜欢尝试做正确的事情。 有办法做我想的吗? 我知道你可以用原语来做,例如:
template <int T>
是有效的,但是当我尝试使用用户定义的类时,我收到编译器错误。 有什么建议么?
您不可能对模板类型参数设置人为限制。 如果给定的类型不支持您使用它的方式,您将收到编译器错误。 一个名为“概念”的功能,基本上允许这个,将被添加到下一个C ++标准,但由于时间限制,它被推迟到下一个标准。 如果T没有可见的getIdentifier()
函数,则实例化将不会编译。
模板参数需要在编译时推导出来。 template<int T>
有效,因为第一个模板参数是一个整数; 你可以使用任何常量整数来实例化它。 如果您尝试将其与非const整数变量一起使用,则无法编译。 类的实例不是编译时常量,因此不能使用它。
你已经得到了其他几个答案,两者都很好(特别是@dauphic's,IMO)。 我只是补充一点,你给出的代码看起来非常像是对std::map
的低效模仿。 在大多数情况下, std::map
可能会更好。 如果你查看它的界面,它还会向你展示一种方法来解决你的容器直接指定getIdentifier()
- 而不是直接使用像getIdentifier()
这样的东西,它使用默认为std::less<T>
的比较函数std::less<T>
,它将(反过来)使用T::operator<
- 但如果您愿意,也可以指定完全不同的比较函子。
我还应该指出,虽然其他人已经指出如果你使用getIdentifier
(或其他)你会得到一个编译错误,并尝试实例化一个不提供它的类。 但是,我觉得有必要警告你,你得到的错误信息可能很长,很复杂,而且很难破译。 这是特别容易,如果有这确实有一些其他类型getIdentifier
可用的成员。 在这种情况下,您得到的错误消息说“无法从type A
转换为type B
”,其中type A
是您用于实例化容器的任何类型, type B
是发生的任何type B
(通常完全不相关)类型拥有一个getIdentifier
成员。 发生的事情是编译器看到你已经使用了getIdentifier
,并且看到type B
有那个,所以它试图将你的type A
对象转换为type B
对象,并发现它不能,所以这就是它所告诉的你在错误信息中。
PS是的,我知道这不仅仅是一个评论,而是一个答案。 我为此道歉,但它不会真正适合评论。
你不需要做任何事情。 如果contained[i]
没有getIdentifer()
函数,则会出现编译时错误(就像在Java中使用接口一样,就像在使用模板之外一样)。
详细说明:如果你要写,
int x = 10;
long id = x.getIdentifer();
这将被视为“糟糕的设计”。 这只是一个错误,编译器会抓住它。 这正是你的例子中会发生的事情。
C ++在编译时多态(即模板)和运行时多态(即继承)之间绘制了一条相当明显的界限。 因此语言不支持您想要做的事情。
执行您正在做的事情的一种典型做法是除了T之外还提供可以获取给定T的标识符的类型。这将两种行为分离为两种类型,您可以指定(英语)必须的接口实施。
template <class T, class StringIdForT>
class Container
{
...
bool identifierExists(string givenIdentifier)
{
StringIdForT idGetter;
for (int i = 0; i < this->contained.size(); i++)
{
if (idGetter.getIdentifier(this->contained[i]) == givenIdentifier)
{
return true;
}
}
return false;
}
};
您有类似的问题,StringIdForT仍然必须定义指定的方法
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.