C++提高编程
模版
特点:
- 只是一个框架,不可以直接使用
- 通用并不是万能的
泛型主要利用模版
函数模版
语法:
template<typename T>
函数
# include<iostream>
using namespace std;
template<typename T>
void MySwap(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
void test01() {
int a = 10;
int b = 20;
MySwap(a, b);
cout << a << " " << b << endl;
char c = 'a';
char d = 'b';
MySwap<char>(c, d);
cout << c << " " << d << endl;
}
int main() {
test01();
system("pause");
return 0;
}
注意事项:
- 自动类型推导,必须推导出一致的数据类型T,才可以使用
- 模版必须确定出T的数据类型才可以使用
# include<iostream>
using namespace std;
template<typename T>
void MySwap(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
template<class T>
void func() {
cout << "func" << endl;
}
void test01() {
int a = 10;
int b = 20;
MySwap(a, b);
char c = 'a';
//MySwap(c, a);
//func();
func<int>();
}
int main() {
test01();
system("pause");
return 0;
}
普通函数与函数模版的区别:
- 普通函数可以发生自动类型转换
- 函数模版调用时,如果利用自动类型推导,不会发生自动类型转换
- 如果利用显示指定类型的方式,可以发生自动类型转换
# include<iostream>
using namespace std;
template<typename T>
T MyAdd1(T a, T b) {
return a + b;
}
int MyAdd2(int a, int b) {
return a + b;
}
void test01() {
int a = 10;
int b = 20;
char c = 'a'; // 97
int ans = 0;
ans = MyAdd2(a, c);
cout << ans << endl;
//ans = MyAdd1(a, c);
ans = MyAdd1<int>(a, c);
cout << ans << endl;
}
int main() {
test01();
system("pause");
return 0;
}
普通函数与函数模版的调用规则:
- 都可实现,优先调用普通函数
- 可以通过空模版参数列表来强制调用函数模版
- 函数模版也可以重载
- 如果函数模版可以更好的匹配,优先调用函数模版
# include<iostream>
using namespace std;
void MySwap(int &a, int &b) {
cout << "普通函数" << endl;
}
template<typename T>
void MySwap(T &a, T &b) {
cout << "函数模版" << endl;
}
template<typename T>
void MySwap(T& a, T& b, int x) {
cout << "重载函数模版" << endl;
}
void test01() {
int a = 10;
int b = 2;
MySwap(a, b);
MySwap<>(a, b);
MySwap(a, b, 100);
char c = 'a';
char d = 'b';
MySwap(c, d);
}
int main() {
test01();
system("pause");
return 0;
}
局限性:
- 传入class类时,需要进行函数模版的重载
# include<iostream>
# include<string>
using namespace std;
class Person {
public:
Person(string name, int age) {
this->m_name = name;
this->m_age = age;
}
string m_name;
int m_age;
};
template<typename T>
bool MyCompare(T &a, T &b) {
if (a == b) {
return true;
}
return false;
}
template<> bool MyCompare(Person & a, Person & b) {
if (a.m_age == b.m_age && a.m_name == b.m_name) {
return true;
}
return false;
}
void test01() {
Person p1("张三", 19);
Person p2("罗向", 55);
Person p3("张三", 19);
if (MyCompare(p1, p2)) {
cout << "p1 p2 一样" << endl;
}
else {
cout << "p1 p2 不一样" << endl;
}
if (MyCompare(p1, p3)) {
cout << "p1 p3 一样" << endl;
}
else {
cout << "p1 p3 不一样" << endl;
}
}
int main() {
test01();
system("pause");
return 0;
}
类模版
语法:
template<typename T>
类
# include<iostream>
# include<string>
using namespace std;
template <class NameType, class AgeType>
class Person {
public:
Person(NameType name, AgeType age) {
this->m_name = name;
this->m_age = age;
}
void show() {
cout << m_name << " " << m_age << endl;
}
NameType m_name;
AgeType m_age;
};
void test01() {
Person<string, int> p("孙悟空", 999);
p.show();
}
int main() {
test01();
system("pause");
return 0;
}
类模版与函数模版区别:
类模版与函数模版区别主要有两点:
- 类模版没有自动类型推导的使用方式
- 类模版在模版参数列表中可以有默认参数
# include<iostream>
# include<string>
using namespace std;
template <class NameType, class AgeType = int>
class Person {
public:
Person(NameType name, AgeType age) {
this->m_name = name;
this->m_age = age;
}
void show() {
cout << m_name << " " << m_age << endl;
}
NameType m_name;
AgeType m_age;
};
void test01() {
//Person p("孙悟空", 999);
Person<string> p("财务科", 98);
p.show();
}
int main() {
test01();
system("pause");
return 0;
}
类模版中成员函数创建时机:
- 普通类中成员函数一开始就可以创建
- 类模版中成员函数在调用时才创建
# include<iostream>
# include<string>
using namespace std;
class Person1 {
public:
void show1() {
cout << 1 << endl;
}
};
class Person2 {
public:
void show2() {
cout << 2 << endl;
}
};
template<class T>
class MyClass {
public:
T obj;
void func1() {
obj.show1();
}
void func2() {
obj.show2();
}
};
void test01() {
MyClass<Person1> c;
c.func1();
//c.func2();
}
int main() {
test01();
system("pause");
return 0;
}
类模版对象做函数参数:
三种传入方式:
- 指定传入的类型(直接显示对象的数据类型)
- 参数模版化(将对象中的参数变为模版进行传递)
- 整个类模版化(将这个对象类型 模版化进行传递)
# include<iostream>
# include<string>
using namespace std;
template<class T1, class T2>
class Person {
public:
Person(T1 name, T2 age) {
this->m_name = name;
this->m_age = age;
}
void showPerson() {
cout << m_name << " " << m_age << endl;
}
T1 m_name;
T2 m_age;
};
void show1(Person<string, int> &p) {
p.showPerson();
}
template<class T1, class T2>
void show2(Person<T1, T2> &p) {
p.showPerson();
}
template<class T>
void show3(T& p) {
p.showPerson();
}
void test01() {
Person<string, int> p("孙悟空", 999);
show1(p);
show2(p);
show3(p);
}
int main() {
test01();
system("pause");
return 0;
}
类模版与继承:
注意事项:
- 当子类继承的父类是一个类模版时,子类在声明的时候,要指定出父类中的T类型
- 如果不指定,编译器无法给子类分配内存
- 如果想灵活指定出父类中T的类型,子类也虚变为类模版
# include<iostream>
# include<string>
using namespace std;
template<class T>
class Base {
public:
T m;
};
class Son1 : public Base<int> {
};
template<class T1, class T2>
class Son2 : public Base<T2> {
T1 obj;
};
void test01() {
Son2<int, char> s2;
}
int main() {
test01();
system("pause");
return 0;
}
类模版成员函数类外实现:
# include<iostream>
# include<string>
using namespace std;
template<class T1, class T2>
class Person {
public:
Person(T1 name, T2 age);
void showPerson();
T1 m_name;
T2 m_age;
};
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age) {
this->m_name = name;
this->m_age = age;
}
template<class T1, class T2>
void Person<T1, T2>::showPerson() {
cout << m_name << " " << m_age << endl;
}
void test01() {
Person<string, int> p("猪八戒", 888);
p.showPerson();
}
int main() {
test01();
system("pause");
return 0;
}
类模版分文件编写:
问题:类模版中成员函数创建时机是在调用阶段,导致分文件编写时链接不到
解决:
- 直接包含
.cpp
源文件 - 将声明和实现写到同一个文件中,更改后缀名为
.hpp
person.h
#pragma once
# include<iostream>
# include<string>
using namespace std;
template<class T1, class T2>
class Person {
public:
Person(T1 name, T2 age);
void showPerson();
T1 m_name;
T2 m_age;
};
person.cpp
#include "person.h"
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age) {
this->m_name = name;
this->m_age = age;
}
template<class T1, class T2>
void Person<T1, T2>::showPerson() {
cout << m_name << " " << m_age << endl;
}
main.cpp
# include<iostream>
# include<string>
# include "person.cpp"
using namespace std;
void test01() {
Person<string, int> p("猪八戒", 888);
p.showPerson();
}
int main() {
test01();
system("pause");
return 0;
}
person.hpp
#pragma once
# include<iostream>
# include<string>
using