Cherno C++学习笔记 P53 模板

这篇文章我们会讲一下C++模板,这个是一个非常有意思的且有用的东西,我们平时使用的STL其实就是基于模板编写的。它几乎就像一个宏,可以去做我们想做的任何事情。模板也可以称其为泛型,但是它比泛型要强大得多。

模板是一个非常非常大的话题,所以这里我们只会讲解它简单的应用。它的本质是可以根据我们自己的用途,为其定义一个模板,然后编译器会根据我们给出的规则来帮助我们编写代码,可以让我们省去很多麻烦。所以使用模板类似于我们为编辑器创建了一个blueprint。我们举一个例子来说明为什么模板对于我们很方便。

比如我们来写一个非常简单的print函数,就是输出一个值:

void Print(const std::string& str) {
    std::cout << str << std::endl;
}

但是如果在比如我们的日志类当中,我们要打印的东西不仅仅有string类型,可能还会有其他类型,比如int/float/double等等,那么我们就得把这个简单的函数换一个类型,一遍一遍的写一遍,这个听起来就很费劲了,而更离谱的是,如果我们想要修改一下这个Print函数,那么我们每一个类型对应的函数都得修改一下,想一想这个工作量就很让人难受。

正因为如此,对于这种需要我们可以无视变量类型而专心实现功能的函数,我们的模板就非常有用了,具体的使用方法如下所示:

template
void Print(const T& value) {
    std::cout << value << std::endl;
}

这样我们输入的类型就直接用T来代替了,它会根据我们具体输入的类型来生成对应的函数,这样一下子就方便了很多。

需要注意的是,模板并不是真实的代码,也就是说,在我们编译的时候,模板这部分代码是不参与编译的。它的影响方式是,在我们预处理之后,实际编译之前,模板类会根据我们定义和使用它的方式,帮我们给这个函数写出来,然后我们再调用编译器帮我们写出来的这个函数。所以模板类函数是根据我们的输入情况自动创建我们要调用的函数的,而模板类函数本身这段代码是不会被使用的。甚至我们可以认为,如果我们不使用某个模板,我们都可以当成它是不存在的。

当然,我们其实是可以指定生成的类型的,比如说我们可以这样使用上面的Print函数:

Print(5);

这样使用也是完全没有问题的。但是平时没必要这样用,因为编译器可以自己推断应该使用的类型。
当然我们也可以在构建类的时候使用模板,而且模板也不仅仅是提供通用类型。比如我们想要写一个自己的array类,但是我们不想使用new来动态分配内存,我们希望能够在栈上分配内存,但是我们又知道在栈上是不能接受变量作为分配内存的长度的,那么就需要我们使用模板类:

template
class MyArray {
private:
    int MyArray[N];
public:
    int Length() const {
        return N;
    }
};

这样我们就可以用下面的方式来确定这个array的长度了:

MyArray<4> array;
std::cout << array.Length() << std::endl;

同时我们也可以看到输出就是4。这是说明我们在按照模板复制我们的代码的时候,我们就已经自动地把内容填充好了,所以就不会出现编译的时候塞进来一个变量的问题了。

如果说我们想要把这个array存储数据的类型也作为模板的一部分,那么我们就有了如下的代码:

template
class MyArray {
private:
    T MyArray[N];
public:
    int Length() const {
        return N;
    }
};

同样,我们使用的时候就变成了这个样子:

MyArray array;

这两项都是在编译的时候确定,然后编译器帮我们把空填好。这种使用方式已经与STL非常接近了。

这个其实就是所谓的元编程。我们为编译器设置规则,然后让编译器自动帮我们填充,非常强大。但是我们知道,有很多公司和组织,会严格禁止使用模板类,这个是因为模板能做到的事情太多,导致有些程序员会非常疯狂地使用模板,在模板过于复杂的情况下,我们就没有什么办法辨别清楚我们需要编译的内容了。尤其是如果十多个template变量,每一个一个一个对过去,真的非常糟心。所以不宜对于模板过于痴迷,但是合理的在比如logging类当中使用它,其实是非常nice的。

好了以上就是关于模板的全部内容了,希望大家喜欢!

你可能感兴趣的:(Cherno,C++学习,学习,笔记,c++)