C ++模板和子类?

时间:2010-08-10 19:16:16

标签: c++ oop interface

所以,我正在学习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>

是有效的,但是当我尝试使用用户定义的类时,我收到编译器错误。有什么建议吗?

4 个答案:

答案 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仍然必须定义一个指定的方法