了解c ++模板示例

时间:2014-09-11 21:17:49

标签: c++ templates

假设我有一个计数秒的类SecondTimer并通知侦听器,假设侦听器有一个接受来自计时器的事件的特殊方法onTimer()

template <class TName>
class SecondTimer
{
public:
    SecondTimer() : listener(nullptr), stime(0), time(1000), isStarted(false) {}

    void init(TName * _listener, int _stime)
    {
        GASSERT(_listener && "The listener can not be NULL");
        listener = _listener;
        stime = _stime;
        time = 1000;
        isStarted = false;
        listener->onTimer(stime);
    }
    inline void start() { isStarted = true; }
    inline void stop() { isStarted = false; }
    void Process(int dtime)
    {
        if (!isStarted)
            return;

        time -= dtime;
        if (time <= 0)
        {
            int ds = 1 - time / 1000;
            time = time % 1000 + 1000;
            stime -= ds;
            listener->onTimer(stime);
            //
            if (stime <= 0)
            {
                isStarted = false;
            }
        }
    }

private:
    TName * listener;
    int stime, time;
    bool isStarted;
};

我想将它用作实现onTimer(int)成员函数的1000个不同类的模板。

构建程序时会发生什么?编译器是否会复制所有1000个不同类的Init()Process()函数?

2 个答案:

答案 0 :(得分:3)

是。对于您使用它的每个类,编译器将实例化整个类。

这有时被称为模板膨胀。有一些技术可以部分避免它,现代编译器有时会做一些聪明的技巧。但是在一天结束时会有很多重复的代码。

有一些编译器(我不记得哪些编译器,如果他们碰巧编译两个相同的函数,字节到字节,他们会将它们合并为只有一个。这在技术上是非法的C ++,因为指针这些函数在不应该的时候会比较相等。但是模板类中的很多函数都会被合并。不幸的是,在你的例子中只有构造函数start()stop()符合条件,其他的使用模板类很可能会产生不同的代码。

对于这类问题,您必须考虑使用模板或使用虚函数(接口)编写基类是否值得。在运行时(较慢和较小)或在编译期间(更快和更大)解决概念性虚拟调用onTimer之间存在权衡。

例如:

struct TName
{
    virtual void onTimer() =0;
};

class SecondTimer //no template bloat!
{
   /*...*/
};

PS:我打算在这里添加一些关于哪些编译器进行合并的信息,但后来我发现this answer可以很好地解释它。

答案 1 :(得分:1)

  

编译器是否会为所有1000复制Init()和Process()函数   不同的班级?

是。这正是将要发生的事情。编译器将为类实例化整个代码,就像您手动编写了所有这些代码一样。然而,一些优化是可能的。