new char(10);申请一个char类型的空间初始化为10
new char[10];申请10各char类型空间
泛型编程:
模板:分为函数模板和类模板
c++提供了函数模板,所谓的函数模板就是一个通用的函数
类型太多了,但是逻辑又非常相似,于是就让类型参数化
//1.自动类型推演,让编译器自己进行类型推演,如果有产生二义性直接报错
#include<iostream>
using namespace std;
template <class T> //告诉编译器下面如果出现T不要报错,T是一个通用类型
void myswap(T &a, T &b)
{
T temp = a;
a = b;
b = temp;
}
int main()
{
int a = 10;
int b = 20;
double c = 3.14;
double d = 4.23;
myswap(a, b);
myswap(c, d);
cout << a << endl << b << endl;
cout << c << endl << d << endl;
return 0;
}
//2.显示指定类型
#include<iostream>
using namespace std;
template <class T> //告诉编译器下面如果出现T不要报错,T是一个通用类型
void myswap(T &a, T &b)
{
T temp = a;
a = b;
b = temp;
}
int main()
{
int a = 10;
int b = 20;
double c = 3.14;
double d = 4.23;
myswap<int>(a, b);
myswap<double>(c, d);
cout << a << endl << b << endl;
cout << c << endl << d << endl;
return 0;
}
模板必须要指定出T才可以使用,不要让编译器去猜,去推倒,一般显示指定就好了,否则容易出错
通过类模板实现一个选择排序
#include<iostream>
using namespace std;
template<class T>
void myswap(T &a, T &b)
{
T temp = a;
a = b;
b = temp;
}
template<class T>
void mysort(T array[], int len)
{
for (int i = 0; i < len; ++i)
{
int max = i;
int j = i + 1;
for(j; j < len; ++j)
{
if (array[max] < array[j])
max = j;
}
if (max != i)
myswap(array[i], array[max]);
}
}
template<class T>
void printfs(T array[],int len)
{
for (int i = 0; i < len; ++i)
{
cout << array[i]<<" ";
}
cout << endl;
}
void test()
{
char a[] = "helloworld";
int b[] = { 5, 8, 7, 4, 6, 3, 1, 9, 2, 0 };
int num = sizeof (a) / sizeof (a[0]);
mysort(a, num);
printfs(a, num);
int num1 = sizeof (b) / sizeof (b[0]);
mysort(b, num1);
printfs(b, num1);
}
int main()
{
test();
return 0;
}
template<calss T>只能保证紧跟真的那个函数里面的T不报错意思就是,函数要想使用模板就必须每个函数前面都要有一个模板template<calss T>
函数模板与普通函数的区别以及调用规则
区别:模板无法进行隐式类型转换
#include<iostream>
using namespace std;
template<class T>
void plus1(T &a,T &b)
{
cout << a + b << endl;
}
void plus2(int a, int b)
{
cout << a + b << endl;
}
int main()
{
int a = 10;
int b = 20;
char c = 'c';
plus1(a, b);
//plus(a, c);函数模板不能进行隐士类型转换
plus2(a, c);
return 0;
}
函数模板调用规则:
#include<iostream>
using namespace std;
template<class T>
void func(T a, T b)
{
cout << "函数模板调用\n";
}
void func(int a, int b)
{
cout << "普通函数调用\n";
}
int main()
{
int a = 10;
int b = 20;
func(a, b);
//结论
//1.如果出现函数重载,那么优先调用普通函数,就算普通函数只有声明没有定义,报错也优先调用普通函数
//2.如果想要强制调用函数模板,那么就要用空的参数列表。例如:func<>(a, b);强制调用函数模板
//3.函数模板也可以发生重载(示例在下面)
return 0;
}
//3.函数模板也可以发生重载(示例在下面)
#include<iostream>
using namespace std;
template<class T>
void func(T a, T b)
{
cout << "函数模板调用\n";
}
template<class T>
void func(T a,T b,T c)
{
cout <<"三参数函数模板调用\n";
}
int main()
{
int a = 10;
int b = 20;
int c = 30;
func(a, b, c);
return 0;
}
//4.如果函数模板可以产生更好的匹配那么优先使用函数模板
#include<iostream>
using namespace std;
template<class T>
void func(T a, T b)
{
cout << "函数模板调用\n";
}
void func(int a, int b)
{
cout << "普通函数调用\n";
}
int main()
{
char a = 'a';
char b = 'b';
func(a, b);
return 0;
}
//此时将调用函数模板,因为不会产生隐式类型转换
模板机制:
1.模板不是万能的,并不是可以通用所有数据类型
2.通过模板生成的函数叫模板函数
一个模板在被调用的时候就会通过这个模板产生一个函数(参数类型已经赋好好的函数),这个函数就叫做模板函数。
3.操作系统会对模板进行二次编译,第一次是对函数模板进行编译,推演出所有类型之后,再对模板函数进行编译。
类模板的基本使用:
#include<iostream>
#include<string>
using namespace std;
template<class T1,class T2>
class person
{
public:
person(T1 a,T2 b)
{
this->name = a;
this->ages = b;
}
void printfs()
{
cout << this->ages << endl << this->name << endl;
}
T1 name;
T2 ages;
};
void test()
{
//person p("孙悟空",10);这个是错误的写法因为类模板不支持自动的推演,只支持显示化调用
person<string, int>p("孙悟空",10);
p.printfs();
}
int main()
{
test();
return 0;
}
还有一点就是类模板可以有默认的参数,函数模板不可以
template<class T1 = int ,class T2 = string>
class person
{
};
成员函数的创建时机:一开始并不会去创建 ,只有在运行的时候才会根据模板创建函数
类模板做函数参数:
1.显示传入指定参数
2.参数模板化
3.类整体模板化
#include<iostream>
#include<string>
using namespace std;
template <class T1, class T2>
class person
{
public:
person(T1 a, T2 b)
{
this->name = a;
this->ages = b;
}
void func()
{
cout << this->name << endl << this->ages << endl;
}
T1 name;
T2 ages;
};
//1.指定传入参数
void funcs(person<string, int> &a)
{
a.func();
}
//2.参数模板化
template<class T1,class T2>
void funcs2(person<T1,T2>&a)
{
a.func();
}
void test()
{
person<string, int>p1("猪八戒", 10);
funcs(p1);
person<string, int>p2("呆贼", 18);
funcs2(p2);
}
int main()
{
test();
return 0;
}
#include<iostream>
#include<string>
using namespace std;
template <class T1, class T2>
class person
{
public:
person(T1 a, T2 b)
{
this->name = a;
this->ages = b;
}
void func()
{
cout << this->name << endl << this->ages << endl;
}
T1 name;
T2 ages;
};
template<class T>
//3.整体模板化,直接让操作系统对person这个类进行推演
void funcs(T &a)
{
a.func();
}
void test()
{
person<string, int>p1("猪八戒", 10);
funcs(p1);
}
int main()
{
test();
return 0;
}
如何查看推导出来的函数类型:(string类型原名很长)
void funcs(T &a)
{
cout << typeid(T).name() << endl;
a.func();
}
//结果就是
class person<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,int>
猪八戒
10
请按任意键继续. . .
类模板碰到继承的问题以及解决:
#include<iostream>
using namespace std;
template<class T>
class person
{
public:
T myname;
};
class dog : public person<int> //1.写死的类型
{
};
template<class T1,class T2>
class dog2 : public person<T2> //2.用户自定义的类型T2直接就是基类的T类型
{
public:
T1 myname;
};
类模板的类外实现成员函数:
#include<iostream>
#include<string>
using namespace std;
template<class T1,class T2>
class person
{
public:
person(T1 name, T2 ages);
void func();
T1 name;
T2 ages;
};
//与普通调用相比在开头多了模板声明
template<class T1,class T2>
person<T1,T2>::person(T1 name, T2 ages)//在指定作用域的时候多了<T1, T2>
{
this->name = name;
this->ages = ages;
}
template<class T1,class T2>
void person<T1,T2>::func()
{
cout << this->name << endl << this->ages << endl;
}
void test()
{
person<string, int>p1("狗贼", 18);
p1.func();
}
int main()
{
test();
return 0;
}
要是报无法解析的外部命令一般都是在链接的时候找不到代码
建议模板不建议做分文件编写,如果要进行的话就要把声明和实现写到一个文件中
友元函数模板:
#include<iostream>
#include<string>
using namespace std;
template<class T1,class T2>
class person
{
friend void func(person<T1, T2>&p)//全局函数做友元
{
cout << p.name << endl << p.ages << endl;
}
public:
person(T1 name, T2 ages)
{
this->name = name;
this->ages = ages;
}
private:
T1 name;
T2 ages;
};
void test()
{
person<string, int>p("唐僧",88);
func(p);//虽然没在全局声明但是默认func是全局函数做友元
}
int main()
{
test();
return 0;
}
普通函数,模板函数,模板函数就是函数前面紧跟着的有template<class T... >,普通函数没有,想强制调用模板函数就要使用空参数列表<>
类模板应用:
#include<iostream>
using namespace std;
template<class T>
class array
{
public:
array(int capacity)//有参构造函数 实现array<int>p(10);
{
this->capacity = capacity;
this->size = 0;
this->myarray = new T[this->capacity];
}
array(const array &p) //拷贝构造函数
{
this->capacity = p.capacity;
this->size = p.size;
this->myarray = new T[p.capacity];
for (int i = 0; i < this->size; ++i)
{
this->myarray[i] = p[i]; //这里不必写p.myarray[i],因为我们写了[]运算符的重载,目的就是为了让代码更简明
}
}
array& operator=(const array &p) //=号运算符的重载
{
if (this->capacity != NULL)
{
delete[] this->myarray;
this->myarray = NULL;
this->size = NULL;
this->capacity = NULL;
}
this->capacity = p.capacity;
this->size = p.size;
this->myarray = new T[p.capacity];
for (int i = 0; i < this->size; ++i)
{
this->myarray[i] = p[i]; //这里不必写p.myarray[i],因为我们写了[]运算符的重载,目的就是为了让代码更简明
}
return *this
}
T operator[](int num)
{
return this->myarray[num];
}
void push(int val) //尾插
{
this->myarray[this->size] = val;
size++;
}
int getsize() //获取有效长度
{
return this->size;
}
int getcapacity() //获取容量
{
return this->capacity;
}
~array() //析构函数
{
if (this->capacity != NULL)
{
delete[] this->myarray;
this->size = NULL;
this->myarray = NULL;
this->capacity = NULL;
}
}
private:
T *myarray;
int capacity;
int size;
};
void printfs(array<int>& p) //打印数组的函数
{
for (int i = 0; i < p.getsize(); ++i)
{
cout << p[i] << " ";
}
cout << endl;
}
void test()
{
array<int>p1(10);
int j = 10;
for (int i = 0; i < p1.getcapacity(); ++i) //进行插入数据
{
p1.push(j);
}
printfs(p1);
}
int main()
{
test();
return 0;
}