小言_互联网的博客

C++模板类详解及注意事项

468人阅读  评论(0)

C++模板类

C++中有一个重要特性,那就是模板类型。类似于Objective-C中的泛型,C++通过类模板来实现泛型支持。它使用参数化的类型创建相应的函数和类,分别称之为函数模板和类模板。

模板是一种对类型进行参数化的工具,通常有两种形式:函数模板和类模板。函数模板针对仅参数类型不同的函数;类模板针对仅数据成员和成员函数类型不同的类,可以显著减小源代码的大小并提高代码的灵活性,而不会降低类型安全。

模板适用情景

模板(有时称为参模板(有时称为参数化类型)是用于生成基于类型参数的函数和类的机制。通过使用模板,可以设计操作多种类型的数据的单个类或函数,而不必为每种类型创建单独的函数或类。

模板的优势和劣势

使用模板有很多原因,最主要的为了得到通用编程的优点。国际标准化组织(ISO)为C++建立了C++标准库,该标准库功能强大,这证明了模板的重要性。库中涉及算法和容器的部分组成了标准模板库(简称STL)。由于模板的可重用性和可扩展性,你可以利用STL来实现效率很高的代码。

但是模板也有一些不太为人知的缺点。首先,由于C++没有二进制实时扩展性,所以模板不能像库那样被广泛使用。模板的数据类型只能在编译时才能被确定。因此,所有用基于模板算法的实现必须包含在整个设计的头文件中。通过分析标准模板库(STL)的头文件,你可以很清楚的认识到这一点。

另外,由于模板只是最近加入C++标准中,所以有些C++编译器还不支持模板,当使用这些编译器时编译含有模板的代码时就会发生不兼容问题。例如,Mozilla浏览器开发组之所以没有使用模板就是因为交叉平台会导致模板的不兼容。同样的,如果当开发者需要跨越好几个平台而有的平台可能只有老的C++编译器的时候,使用模板也是不明智的。

即使到现在,模板的一些高级特性,例如局部特殊化和特殊化顺序在不同的C++标准实现中也还是不统一的。

尽管如此,结合STL使用模板还是可以大大减少开发时间。模板可以把用同一个算法去适用于不同类型数据,在编译时确定具体的数据类型。

函数模板概念

函数模板可以用来创建一个通用功能的函数,以支持多种不同形参,进一步简化重载函数的函数体
意义:对于功能完全一样,只是参数类型不同的函数,能写一段通用代码是用于多种不同的数据类型,使代码的可重用性大大提高,从而提高软件的开发效率。
请参考:C++函数模板详解

模板类概念

一个类模板(类生成类)允许用户为类定义个一种模式,使得类中的某些数据成员、默认成员函数的参数,某些成员函数的返回值,能够取任意类型(包括系统预定义的和用户自定义的)。

如果一个类中的数据成员的数据类型不能确定,或者是某个成员函数的参数或返回值的类型不能确定,就可以将此类声明为模板,它的存在不是代表一个具体的、实际的类,而是代表一类 类。

类模板以下面的这样的代码开头

template <class T>

关键字template或class告诉编译器。将要定义一个模板,尖括号的内容相当于函数的参数列表。可以把关键字template或class看做是变量的类型名该变量接受类型作为其值,把T看做变量的名称。

如下,声明一个普通的类模板:

#include<iostream>
using namespace std;
template <typename T>
class Complex
{
public:
    //构造函数
    Complex(T a, T b)
    {
        this->a = a;
        this->b = b;
    }

    //运算符重载
    Complex<T> operator+(Complex& c)
    {
        Complex<T> tmp(this->a + c.a, this->b + c.b);
        return tmp;
    }

private:
    T a;
    T b;
};

int main()
{
    //对象的定义,必须声明模板类型,因为要分配内容
    Complex<int> a(10, 20);
    Complex<int> b(20, 30);
    Complex<int> c = a + b;

    return 0;
}



模板除了定义类型参数,还可以在模板定义非类型参数
什么是非类型形参?顾名思义,就是表示一个固定类型的常量而不是一个类型。通常来说,模板都是用作类型的泛化,而非类型参数则不同于以往的用处。

//示例代码:
template<class T, int MAXSIZE>
class List
{
private:
    T Num[MAXSIZE];
public:
    List()                   //构造函数
    {
        for (int i = 0; i < MAXSIZE; i++)
        {
            Num[i] = i;
        }
    }
    void Print()
    {
        cout << "储存的值分别为:" << endl;
        for (int i = 0; i < MAXSIZE << i++)
        {
            cout << "  " << Num[MAXSIZE];
        }
    }
};

对应的非类型实参也有限制:

实参必须是编译时常量表达式,不能使用非const的局部变量,局部对象地址及动态对象

非Const的全局指针,全局对象,全局变量(下面可能有个特例)都不是常量表达式。

由于形参的已经做了限定,字符串,浮点型即使是常量表达式也不可以作为非类型实参。

非类型形参是有条件限制的:

浮点数不可以作为非类型形参,包括float,double。具体原因可能是历史因素,也许未来C++会支持浮点数。

类不可以作为非类型形参。

字符串不可以作为非类型形参。

整形,可转化为整形的类型都可以作为形参,比如int,char,long,unsigned,bool,short(enum声明的内部数据可以作为实参传递给int,但是一般不能当形参)

指向对象或函数的指针与引用(左值引用)可以作为形参。

非类型模版参数作用:

模板定义内,非类型模板参数是一个常量值,所以,在需要常量表达式的地方,可以使用这个特性,例如,指定数组大小(例如上面示例代码中指定最大size)

可以作为一个参数传入的方式,只是这个参数有上述的一些性质。

注意事项

模版类的定义和实现不能分开写在不同文件中,否则会导致编译错误

原因:在C++中,在编译阶段才确定对象所占用的空间。模板类只有被真正使用的时候,编译器才知道,模板套用的是什么类型,应该分配多少空间。然后根据套用的类型进行编译。套用不同类型的模板类实际上就是两个不同的类型,因此这两个类型的共同成员函数实质上也不是同一个函数,仅仅是具有相似的功能。因此,模板类在套用不同类型以后,会被编译出不同的代码。

结论:

1.模板类本身未指定所使用的数据类型,不能单独编译模板类的实现。 只用在使用模板类的阶段,指定了模板中的数据类型,编译器才能正常编译。因此,在实际开发中,必须把实现全部写在头文件里面,把声明和实现分开的做法不可取。

2.模版不支持在局部函数中声明定义或使用

3…使用模板时,template<typename|class T> 声明行同使用T的函数之间不允许出现其它代码。

4.自动类型推导,必须推导出一致的数据类型T,才可以使用模板必须要确定出T的数据类型,才可以使用。

群内有各种学习资料,欢迎大家一起来学习~
如果大家遇到什么问题也欢迎大家进群讨论~
qq群:759252814
期待你的关注~
感谢大家的支持,谢谢!


转载:https://blog.csdn.net/LYXlyxll/article/details/108028024
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场