所以,我正在学习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>
是有效的,但是当我尝试使用用户定义的类时,我收到编译器错误。有什么建议吗?
答案 0 :(得分:5)
您无法对模板类型参数设置人为限制。如果给定的类型不支持您使用它的方式,您将收到编译器错误。一个名为“概念”的功能,基本上允许这个,将被添加到下一个C ++标准,但由于时间限制,它被推迟到下一个标准。如果T没有可见的getIdentifier()
函数,则实例化将不会编译。
模板参数需要在编译时推导出来。 template<int T>
有效,因为第一个模板参数是整数;你可以使用任何常量整数来实例化它。如果您尝试将其与非const整数变量一起使用,则无法编译。类的实例不是编译时常量,因此无法使用。
答案 1 :(得分:3)
你已经得到了其他几个答案,两者都很好(特别是@dauphic's,IMO)。我只是补充说,你给出的代码看起来非常像是std::map
的低效模仿。在大多数情况下,std::map
可能会更好。如果您查看其界面,它还会向您显示一种方法,可以将容器与直接指定getIdentifier()
分开 - 而不是直接使用getIdentifier()
之类的内容,而是使用默认的比较函数到std::less<T>
,它将(反过来)使用T::operator<
- 但如果您愿意,也可以指定一个完全不同的比较函子。
我还应该指出,虽然其他人已经指出如果你使用getIdentifier
(或其他)并且尝试在不提供它的类上进行实例化,你将会遇到编译错误。但是,我觉得有必要警告你,你得到的错误信息可能很长,很复杂,而且很难破译。如果 有getIdentifier
成员可用的其他类型,则特别有可能。在这种情况下,您会收到类似“无法从type A
转换为type B
”的错误消息,其中type A
是您用于实例化容器的任何类型,{{1碰巧有type B
成员的任何(通常是完全不相关的)类型。发生的事情是编译器发现您已使用getIdentifier
,并看到getIdentifier
具有该值,因此它会尝试将您的type B
对象转换为type A
对象,并发现它不能,所以那是它在错误信息中告诉你的内容。
P.S。是的,我知道这不仅仅是一个评论,而是一个答案。我为此道歉,但它不会真正适合评论。
答案 2 :(得分:1)
您无需做任何事情。如果contained[i]
没有getIdentifer()
函数,则会出现编译时错误(就像在Java中使用对接接口一样,就像在使用模板之外一样)。< / p>
详细说明:如果你要写,
int x = 10;
long id = x.getIdentifer();
这将被视为“糟糕的设计”。这只是一个错误,编译器会抓住它。这就是你的榜样。
答案 3 :(得分:0)
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仍然必须定义一个指定的方法