2009-08-31 95 views
3

现在我正在学习C++,现在我知道模板的基本概念, ,它的作用就像一个泛型类型, ,我发现几乎所有的C++程序使用模板, 所以我真的很想知道我们什么时候该假设使用模板? 有人可以为我结束关于C++模板的经验吗? 您何时会考虑使用模板?什么时候最好用C++模板?

补充: 如果我们定义这样的功能

template <class myType> 
myType GetMax (myType a, myType b) { 
return (a>b?a:b); 
} 

,但我们想传递一个对象(自定义类)进行比较,我们怎样才能实现?

Supplement2:在下面的答案 ,有人已经写了这个示例代码

template <class myType> 
const myType& GetMax (const myType& a, const myType& b) { 
    return (a<b?b:a); 
} 

template <class myType, class Compare> 
const myType& GetMax (const myType& a, const myType& b, Compare compare) { 
    return (compare(a,b)?b:a); 
} 

这是正确的?我们可以传递一个函数名作为类myType的参数吗?如果你想添加2 INT,你想获得一个

+0

模板并不总是泛型类型。模板也可以是通用函数,就像你给出的例子。 – pyon 2009-08-31 15:14:37

+0

Re:supplement 2.你可以传递一个指向函数的指针(“函数名称”)或一个函子(重载operator()的类)作为第二个重载的第三个参数。 – UncleBens 2009-08-31 18:36:53

+0

@UncleBens:当然,这就是实际乐趣开始的地方。想象一下那些(尤其是后者)的所有用途(和滥用!)! – pyon 2009-09-02 00:16:12

回答

1

回复:补充。如果你想传递一个比较函数,你可以提供另一种过载:

template <class myType> 
const myType& GetMax (const myType& a, const myType& b) { 
    return (a<b?b:a); 
} 

template <class myType, class Compare> 
const myType& GetMax (const myType& a, const myType& b, Compare compare) { 
    return (compare(a,b)?b:a); 
} 

Samle用法:比较C风格字符串:

bool c_strings_less(const char* a, const char* b) 
{ 
    return std::strcmp(a, b) < 0; //is a less than b 
} 

const char* greater = GetMax("hello", "world", c_strings_less); 

这是怎么的std ::最大算法的工作。 (我也做了一些修改,例如在C++中习惯用谓语定义“小于”的比较。)

或者如果您询问GetMax如何为任意用户定义类型工作,那么必须重载运算符>或者你的函数会导致编译错误。

+0

比较(a,b)?b:a 是这样吗?可以在这里只传递一个函数作为参数吗? – MemoryLeak 2009-08-31 15:14:54

+0

编辑提供使用示例。 – UncleBens 2009-08-31 15:21:51

0

如果你不知道你的变量的类型或你想要做同样的事情,对很多类型的变量,你可以使用模板...

如果你想添加2双int对于回报 ,你想获得一个双退货

所以你使用模板,这个..

3

基本上当你想创建一个通用类,它可以处理解决方案对于多种类型而言,无需为所有想要支持的类提供父类。

你可以只给类一起与您要使用(最好的例子是一个容器,它可以存储你创建转嫁给任何类型)

//----- the container 
template <class T> 
class Stack 
{ 
public: 
    T* stackPtr; 
} 

//----- example 
void main() 
{ 
    typedef Stack<float> FloatStack; 
    typedef Stack<int> IntStack; 
} 

您现在可以存储浮动和同一类的整数,而不必为每种类型编写特定的类。

+0

模板也比类层次更倾向于类型安全。在给定的例子中,FloatStack只处理浮点数,并且不能用它来颠覆类型系统。基类Stack和FloatStack和IntStack的子类的类似实现将更难以实现类型安全,特别是如果基类具有实现细节,那么它们不必在每个子类中重复。 – 2009-08-31 14:59:58

2

简答:如果没有用的话:不要。 如果它似乎解决了一个问题(在不同类型的代码重用,...),首先实现和调试没有模板,然后添加模板参数。

在STL/boost之前,他们很高兴制作容器。

+0

在STL/boost之前,他们很高兴制作容器。 这是什么? – MemoryLeak 2009-08-31 14:57:56

+1

现在已经有容器了,当然。实例化调试良好的模板比编写自己的模板更好。 – MSalters 2009-08-31 15:01:46

+0

我认为这对于初学者来说是一个很好的建议,尽管一个更有经验的C++开发人员可能会立即开始使用这些模板。 – 2009-08-31 15:03:24

1

当您需要参数化类表示的概念时。

举例来说,如果你有一个类,代表了一种方法来管理一类对象

class MyThingManager 
{ 
    void add(MyThing& mything); 
    //... 
}; 

的...也许你需要在后面的新型使用完全相同的行为,但管理不同类型。然后,你必须使用复制/粘贴选择/替换在你的脚下immediately--凹口 - 会导致地狱打开或让你的类有一个类型,以管理为parametter:

template< class ThingType > 
class ThingManager 
    { 
     void add(ThingType& thing); 
     //... 
    }; 

你不这样重复的代码。

另一个值得关注的是,当你想要一些函数调用与具有所需语义的任何参数兼容:

template< class MyType > 
void addPi(MyType& value) 
{ 
    value += PI; 
} 

这样,你(再次)没有重复代码的每个类型可能在parametters。

它没有被称为“泛型编程”。

这些都是简单的情况,但当您想要进行元编程时,会出现更复杂的情况。如果你想去那里,请在编写地狱代码之前阅读至少一本书。我推荐使用“C++模板元编程”以及出色的“现代C++设计”书籍,以获得更高级的模板用法,比如Policy pattern ans等众所周知的。

8

天儿真好,

答案很简单,当你想要的行为仍然使用相同的独立类型的实例化的类。

所以一堆整数的行为方式与一堆浮点的行为将像一堆MyClass对象一样。

当您想允许行为的专业化时,使用继承和基类。

所以说你有一个名为Animal的基类,它有一个名为makeSound()的成员函数。你不知道每个动物会产生哪种声音,所以你使makeSound成员函数成为虚拟函数。实际上,因为对于所有动物没有默认声音,所以您不知道应该将哪些作为默认行为,因此您会将此成员函数声明为纯虚函数。

然后这告诉任何人制作一个派生类的实例,例如一个Lion类,他们必须提供一个实现makeSound成员函数,它将以某种方式提供一个咆哮。

编辑:我忘了补充一点,这是我强烈推荐的Scott Meyers出色的书“Effective C++”(sanitised Amazon link)中的一篇。

HTH

欢呼声,

1

回答第二个问题( 但我们想通过比较的对象(自定义类),我们怎样才能实现?)

如果你想使用 运算符>在模板函数中使用您自己的类。 你的课只需要定义这个操作符或函数。

重要的部分是您的课程需要定义与模板使用的操作员或功能相同的 。

/Tobias

0

模板提供参数化已知编译时间数量的方法。请注意,也可以是一个类型(标准::矢量将仅包含整数),但它们也可以是值:

template <int N, typename T > class MyType 

被模板化的两者上的整数和类型,和的MyType < 2,int>的将是与MyType不同的类型< 3,int>。

此外,模板允许模板元编程:即编译器在编译时执行程序。 Erwin Unruh在编译时计算素数有一个非常吸引人的例子。

看一下http://ubiety.uwaterloo.ca/~tveldhui/papers/priority.html的一小段历史。

2

在您提供的示例中,只要为您正在比较的实例的数据类型定义了operator >,就一切正常。

例如,如果你定义了以下类:

class fraction 
{ 
private: 
    int _num, _den; 

public: 
    fraction(int num, int den) 
    { 
     if (den >= 0) 
     { 
      _num = num; 
      _den = den; 
     } 
     else 
     { 
      _num = -num; 
      _den = -den; 
     } 
    } 

    fraction(const fraction &f) 
    { 
     _num = f._num; 
     _den = f._den; 
    } 

    bool operator > (const fraction &f) const 
    { 
     return (_num * f._den) > (f._num * _den); 
    } 

    bool operator == (const fraction &f) const 
    { 
     return (_num * f._den) == (f._num * _den); 
    } 
}; 

然后你可以使用你的模板函数与该类的实例。

int main(int argc, char* argv[]) 
{ 
    fraction a(1,2); // 0.5 
    fraction b(3,4); // 0.75 
    assert(GetMax/*<fraction>*/(a,b) == a); 
    return 0; 
} 
0

重要的是要注意,不写自己的模板是完全没问题的。如果你不确定你为什么需要它们,那么你可能不需要它们。模板是一个非常强大的工具,但它们并不总是最好的解决方案。

在任何常见的开发平台上,标准库都提供了许多旧式传统模板使用的高质量实现。使用标准库类和函数不需要编写新的模板。例如,它提供了std :: max(),这与你的例子相同。

相关问题