20170305STL01_泛型编程/模版

来源:互联网 发布:js获取当天日期时间 编辑:程序博客网 时间:2024/09/21 11:17

泛型编程:

1:STL目前在国内的资料比较少,国外相对较多。STL用得好的话,一个人的效率相当于十个人。
    1:编程就是生产一个工具,这个工具他能够帮人们做很多重复的事情!
    2:编程过程中,我们需要进行设计,分析,更新,维护。我们需要考虑的是这个软件的架构,代码量等。
    3:编码量将决定我们需要多少人来工作,所以当时Java很流行,生产力大。C++也推出了模版编程。
    4:模版它是一个能够产生代码的代码。这也是模版的意义。他改变了很多设计方式。
    5:他从设计角度帮我们解决很多问题。
2:牲口圈舍的设计:

        按C语言的思维(这个图是C++,但思想是C思想),如果再加一只羊,我们就得加两个模块(羊和羊圈),他们都是强聚合关系,最后将非常难以管理。

        按方案二:将所有动物抽象成一个父类,这样接口很简单,谁进去,就变成什么棚,适合哪种动物。这就是多态的机制实现的自动匹配。但是,这样和现实是脱节的,不可能有这样一个东西,虽然代码量小,但是难以让人理解。

        根据方案三:泛型编程(自动推导式编程),他抽象出来的是实际有的。相当于一个产生器,会产生实实在在存在的代码。

编程的思想:

1:泛型编程,面相对对象,使用对象,他和我们语言的本身是没有关系的,他们都是一种思想、是一种哲学。
2:上面的例子就是三种思想:过程、对象、泛型。三种思想最终的目的都是写出好的程序,他们本身是没有好坏之分的。

类模版基础使用:

1:之前我们自己写的Array类只能保存一种类型的数据,但是STL里面的却可以保存任何类型的。我们可以使用模版的方式来实现。
2:template<typename T>;。typename后面跟的是一个“类型变量”,之后传什么类型,这个T就代表什么类型。
3:template<class T>;。template后面只可能跟这两个关键字,他们的作用都是一样的。但是class使用得比较少,已被废弃,但编译器还可以使用。
4:测试代码:
#ifndef ARRAY_H_#define ARRAY_H_template<typename T>//已经开始在做泛型了。class Array{public:explicit Array(const size_t size = 10);~Array();explicit Array(const Array& other);Array& operator=(Array&other);const T& operator[](const size_t index) const;T& operator[](const size_t index);void Append(const T value);private:T *data_;size_t size_;unsigned int pos_;};//--------------------------------------函数实现-----template<typename T>void Array<T>::Append(const T value){data_[pos_++] = value;}template<typename T>T& Array<T>::operator[](const size_t index){return data_[index];}template<typename T>const T& Array<T>::operator[](const size_t index) const{return data_[index];}template<typename T>Array<T>& Array<T>::operator=(Array<T>&other){if (&other == this)return *this;delete[]data_;size_ = other.size_;data_ = new int[size_];memcpy(data_, other.data_, size_*sizeof(T));return *this;}template<typename T>Array<T>::Array(const Array<T>& other){data_ = new T[other.size_];size_ = other.size_;memcpy(data_, other.data_, size_*sizeof(T));}template<typename T>Array<T>::~Array(){delete[]data_;}template<typename T>Array<T>::Array(const size_t size /*= 10*/){data_ = new T[size_];}#endif//!ARRAY_H_//main.c类容:#include <iostream>#include "Array.h"int main(){//int ar[10] = { 0 };Array<int> a(10);//Array只是一个int型的Array。如果要保存double类型的数据,就又得做一个保存double的类。//这时候就可以用泛型的方式来解决。a.Append(1);a.Append(2);a.Append(3);a.Append(4);a.Append(5);//宏是编译时替换,而模版是编译时生成。编译器在编译的时候会copy生成多个类,它对应你是用过的类型。Array<char> c;c.Append('a');c.Append('b');c.Append('c');c.Append('d');c.Append('e');std::cout << a[3] << std::endl;std::cout << c[3] << std::endl;return 0;}

类外部模版类的类名:

使用模版后,class的类型已经发生了改变的,应该在类名后面加上<T>.

函数模版:

在类里面使用的模版成为类模版,这个类称为模版类。
#include <iostream>template<typename T, typename T2>class Demo{public:Demo(T2 in){}private:T tdemo;T2 t2Demo;};template<typename T, int size>//模版参数,可以直接拿来使用,但必须是常量。class Demo3{public:Demo3(T in){size_ = size;}private:int size_;T tdemo;};int main(){Demo <int, float> demo(float(1.003));return 0;}

1:模版还可以和函数相结合使用,最著名的就是Swap交换函数。它可以推导参数的类型,产生相应的代码。
2:你使用了多少类型,他就会生成多少个函数,而且每个函数的地址是不一样的。
3:如果我们使用的方式出错,他就会推到不出来,导致出错,这时候,我们可以强制指定类型。

4:模版函数是可以重载的。也可以特化(把将会生成的函数自己写一遍,实现特殊的效果)。

5:但凡使用了模版,就很可能存在重载,所以可能存在二义性的问题。而且在模版里面的重载是不可以进行提升转换的。

#include <iostream>template<typename T, typename T2>class Demo{public:Demo(T2 in){}private:T tdemo;T2 t2Demo;};template<typename T, int size>//模版参数,可以直接拿来使用,但必须是常量。class Demo3{public:Demo3(T in){size_ = size;}private:int size_;T tdemo;};template<typename T>void Swap(T&lhs, T&rhs){T temp = lhs;lhs = rhs;rhs = temp;}void Swap(int&lhs, double&rhs)//重载的{}void Swap(int&lhs, int&rhs)//特化的(相当于一个特例,模版不再自己生成这个){}template<typename T1, typename T2>void Swap(T1 lhs, T2 rhs){Swap<double>(lhs, rhs);}int main(){Demo <int, float> demo(float(1.003));int a = 10, b = 20;Swap(a, b);std::cout << a << "  " << b << std::endl;int aa = 10;double bb = 20;//Swap(aa, bb);//这行代码会出错。//Swap<double>(aa, bb);//会强制生成double的版本。//error C2664: “void Swap<double>(T &,T &)”: 无法将参数 1 从“int”转换为“double &”Swap(aa, bb);//将会调用重载的函数。return 0;}



1 0
原创粉丝点击