电子商务网站开发课程教案,shop++的发展历程,自己建个购物网站,wordpress顶部图像使用小工具简介 一种用于实现通用编程的机制。 通过使用模板#xff0c;我们可以编写可复用的代码#xff0c;可以适用于多种数据类型。 C 模板的语法使用角括号 ( ) 来表示泛型类型#xff0c;并使用关键字 template 来定义和声明模板。 示例 #include iostream
//…简介 一种用于实现通用编程的机制。 通过使用模板我们可以编写可复用的代码可以适用于多种数据类型。 C 模板的语法使用角括号 ( ) 来表示泛型类型并使用关键字 template 来定义和声明模板。 示例 #include iostream
// 定义一个模板函数
templatetypename T
T add(T a, T b) {return a b;
}
int main() {int x 5, y 10;float f1 2.5, f2 3.7;
// 调用模板函数std::cout Sum of integers: add(x, y) std::endl;std::cout Sum of floats: add(f1, f2) std::endl;return 0;
} 优点 提高代码的灵活性和复用性 总结 将数据类型可以作为参数进行传递 原理 编译器会对函数模板进行两次编译 在声明的地方对模板代码本身进行编译 在调用的地方对参数替换后的 代码进行编译。 分类
函数模板
类模板
函数模板
步骤 1,声明 2,使用 声明语法
位置在函数上
//class 和 typename 都是一样的用哪个都可以
templateclass 模板名,class 模板名,...
//或
templatetypename 模板名,typename 模板名,...
使用语法 //在该方法任何一处使用数据类型的地方都可以使用模板名替换 注意 1,函数模板可以自动推导参数的类型 , 但是不会进行类型转换 2,函数模板可以自动类型推导 , 也可以显式指定类型 3,只能在声明的所在函数中使用 示例
//定义模板
templateclass T
//在形参中使用模板
void MySwap(T a,T b){
//在局部变量中使用模板T temp a;a b;b temp;
}
void test01(){int a 10;int b 20;cout a: a b: b endl;
//1.函数模板可以自动推导参数的类型MySwap(a,b);cout a: a b: b endl;char c1 a;char c2 b;cout c1: c1 c2: c2 endl;
//2. 函数模板显式指定类型MySwapchar(c1, c2);cout c1: c1 c2: c2 endl;
}
补充 函数模板会编译两次 1,在加载时对函数模板进行第一次编译 2,在调用时推导 T 的类型再次将函数模板编译为模板函数 普通函数和函数模板的区别 1, 函数模板不允许自动类型转化 普通函数能够自动进行类型转。 ( 示例 1) templatetypename T
void func(T a, T b){}
//普通函数
void func02(int a, int b){}
void test02()
{
func(10, 20);
//func(10, a);//err
func02(10, a);
} 2, 函数模板和普通函数同时识别 , 优先使用普通函数 , 加 强制使用函数模板 templatetypename T
void func(T a, T b){
cout函数模板endl;
}
//普通函数
void func(int a, int b){
cout普通函数endl;
}
void test02()
{
//普通函数
func(10, 20);
//显示调用函数模板
func(10, 20);
} 3, 函数模板可以使用 , 普通函数不行 函数模板的局限性 示例 template class Z
void print(Z z)
{cout z endl;
}
class Person{
private:char name[32];int age;
public:
Person()
{
}
Person(char name[],int age)
{strcpy(this - name,name);this - age age;
}
~Person()
{
}
};
int main(int argc, char *argv[])
{Person p(张三,18);
//此时函数模板已经推导出类型为Person,但是因为Person没有对运算符进行重
载所以依据无法使用print(p);return 0;
} 解决方案 1 重载 函数 template class Z
void print(Z z)
{cout z endl;
}
class Person{
friend ostream operator (ostream out,Person p);
private:char name[32];int age;
public:Person(){}Person(char name[],int age){strcpy(this - name,name);this - age age;}~Person(){}
};
ostream operator (ostream out,Person p)
{out p.name p.age endl;return out;
}
int main(int argc, char *argv[])
{Person p(张三,18);print(p);return 0;
} 解决方案 2 函数模板具体化 template class Z
void print(Z z)
{cout z endl;
}
class Person{
friend void printPerson(Person p);
private:char name[32];int age;
public:Person(){}Person(char name[],int age){strcpy(this - name,name);this - age age;}~Person(){}
};
//函数模板具体化
template void printPerson(Person p)
{cout p.name p.age endl;
}
int main(int argc, char *argv[])
{Person p(张三,18);print(p);print(10);return 0;
} 类模板
步骤
定义
使用
定义
语法
template class 模板名1,class 模板名2
位置类的上面
使用
创建对象
语法 类名 实际数据类型 1, 实际数据类型 2,... 对象名 ( 实参列表 ); 注意 类模板示例化对象是不能自动推导类型 , 需指定 示例 #include iostream
#include cstring
using namespace std;
//定义模板
template class T,class Z
class Data{
private:T t1;Z z1;
public:Data(){}Data(T t,Z z){t1 t;z1 z;}void showData(){cout t1 z1 endl;}
};
void test01(){
//创建模板类对象
//Data d01;//类模板示例化对象是不能自动推导类型,错误的
//Data d02(10,a);//类模板示例化对象是不能自动推导类型,错误的Dataint,char d03(10,a);//类模板示例化对象时必须指定模板对应的数据
类型Datastring,float d04(abc,18.8f);d03.showData();d04.showData();
}
int main(int argc, char *argv[])
{test01();return 0;
} 类模板成员函数外部实现 注意 : 外部实现函数时也需定义与类相同的函数模板 示例 #include iostream
#include cstring
using namespace std;
//定义模板
template class T,class Z
class Data{
private:T t1;Z z1;
public:Data(){}Data(T t,Z z);void showData();
};
templateclass T, class Z
DataT,Z::Data(T t, Z z)
{t1 t;z1 z;
}
templateclass T, class Z
void DataT,Z::showData()
{cout t1 z1 endl;
}
void test01(){Datastring,float d01(abc,18.8f);d01.showData();
}
int main(int argc, char *argv[])
{test01();return 0;
} 类模板的分文件使用
注意 在实例化模板之前编译器对模板的定义体是不处理的 在实例化模板时编译器必须在上下文中可以查看到其定义实体 因此模板的实例化与定义体必须放到同一文件中。 但是如果文件名为.h 皆为是头文件 , 在头文件中定义函数不符合头文件的将声明与实例分开的规则 顾将头文件名改为hpp, 并在前内部进行示例化 示例 data.hpp #ifndef DATA_H
#define DATA_H
#includeiostream
using namespace std;
templateclass T1, class T2
class Data
{
private:T1 a;T2 b;
public:Data();Data(T1 a, T2 b);void showData();
};
templateclass T1, class T2
DataT1,T2::Data()
{
}
templateclass T1, class T2
DataT1,T2::Data(T1 a, T2 b)
{this-a a;this-b b;
}
templateclass T1, class T2
void DataT1,T2::showData()
{coutaa, bbendl;
}
#endif // DATA_H main.cpp #include iostream
#include data.hpp
using namespace std;
int main(int argc, char *argv[])
{Dataint,char ob1(100, a);ob1.showData();return 0;
}类模板作为函数参数 注意 : 该函数必须是类模板的友元函数 示例 #include iostream
using namespace std;
template class X
class A{
friend void printA(AX a);
template class T
friend void printB(AT a);
private:X x;
public:A(){}A(X x){this - x x;}void showA(){cout x endl;}
};
//普通函数作为类模板的友缘函数
void printA(Aint a)
{cout a.x endl;
}
void test01()
{Aint a(10);printA(a);
}
//模板函数作为类模板的友缘函数
template class T
void printB(AT a)
{cout a.x endl;
}
void test02()
{Aint a(10);printB(a);
}
int main(int argc, char *argv[])
{test02();return 0;
} 类模板的派生 1, 类模板派生普通子类 示例 #include iostream
using namespace std;
template class T
class Fu{
private:T t;
public:Fu(){}Fu(T t){this - t t;}void showFu(){cout t endl;}
};
//子类实例父类模板数据
class Zi01:public Fuint
{
public:Zi01(){}Zi01(int x):Fu(x){}
};
int main(int argc, char *argv[])
{Zi01 z01(10);z01.showFu();return 0;
} 2, 类模板派生类模板 示例 #include iostream
using namespace std;
template class T
class Fu{
private:T t;
public:Fu(){}Fu(T t){this - t t;}void showFu(){cout t endl;}
};
template class X
class Zi02:public FuX{
public:Zi02(){}Zi02(X x):FuX(x){}
};
int main(int argc, char *argv[])
{Zi02char z02(a);return 0;
} 练习自定义集合 MyArr.hpp #ifndef MYARR_H
#define MYARR_H
#include iostream
using namespace std;
template class T
class MyArr{
private:T* ts;int size;//数据长度int count;//容量
public:MyArr();MyArr(const MyArr myarr);~MyArr();T get(int index);bool add(T t);int getSize();
};
templateclass T
MyArrT::MyArr()
{size 0;count 5;ts new T[count];
}
template class T
MyArrT::MyArr(const MyArrT myarr)
{this-ts new T[myarr.count];this-size myarr.size;this-count myarr.count;/*** C库函数void *memcpy(void *str1, const void *str2, size_t n)* 从存储区 str2 复制 n 个字节到存储区 str1。*/memcpy(ts,myarr.ts,this-size*sizeof(T));
}
template typename T
MyArrT::~MyArr()
{if(ts NULL){return;}delete[] ts;ts NULL;
}
template typename T
T MyArrT::get(int index)
{if(index 0 || index size){return NULL;}return ts[index];
}
template class T
bool MyArrT::add(T t)
{if(size count){T * newTs new T[count * 2];memcpy(newTs,ts,sizeof(T)*size);delete[] ts;ts newTs;count * 2;}ts[size] t;size;return true;
}
templateclass T
int MyArrT::getSize()
{return size;
}
#endif // MYARR_Hmain.cpp #include iostream
#include myarr.hpp
#include cstring
using namespace std;
int main(int argc, char *argv[])
{MyArrint arr01;arr01.add(1);arr01.add(2);arr01.add(3);arr01.add(4);arr01.add(5);arr01.add(6);int s01 arr01.getSize();for(int i 0; i s01; i){cout arr01.get(i) endl;}MyArrint arr02;arr02.add(a);arr02.add(b);arr02.add(c);arr02.add(d);arr02.add(e);arr02.add(f);int s02 arr02.getSize();for(int i 0; i s02; i){cout (char)arr02.get(i) endl;}MyArrstring arr03;arr03.add(abc);arr03.add(123);arr03.add(qaz);arr03.add(hello);arr03.add(hi);int s03 arr03.getSize();for(int i 0; i s03; i){cout arr03.get(i) endl;}return 0;
} 类型转换
上行转换 概念 : 父类指针指向子类空间 注意 安全的 下行转换 子类指针指向父类空间 注意 不安全 类型转换
静态转换
语法 static_castT(要转换的数据)
示例 // 基本类型转换 支持 int num static_cast int ( 3.14f ); // 基本指针类型转换 不支持 float f 0.0f ; //int *p1 static_castint *(f); // 上行转换 支持安全 Base * p2 static_cast Base * ( new Son ); // 下行转换 支持不安全 Son * p3 static_cast Son * ( new Base ); // 不相关类型转换 不支持 //Son *p4 static_castSon *(new Other); 动态转换
语法 dynamic_castT(要转换的数据 ) 示例 // 基本类型转换 不支持 //int num dynamic_castint(3.14f); // 基本指针类型转换 不支持 float f 0.0f ; //int *p1 dynamic_castint *(f); // 上行转换 支持安全 Base * p2 dynamic_cast Base * ( new Son ); // 下行转换 不支持不安全 //Son *p3 dynamic_castSon *(new Base); // 不相关类型转换 不支持 //Son *p4 dynamic_castSon *(new Other); 常量转换 语法 const_castT 注意 只能对指针与引用的变量使用 示例 //将非const 转换成 const
int num 10;
const int *p1 const_castconst int *(num);
//将const 转换成 非const
const int data0;
int *p const_castint *(data); 5, 重新解释转换 垃圾一个不用看