繁体   English   中英

C ++模板和子类?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM