文章目录
- 前言
- 一、typename
- 二、非类型模板参数
- 三、模板参数的特化
- 1. 函数模板参数的特化
- 2. 类模板的特化
- 四、模板类成员函数声明和定义分离
- 1. 显示实例化(不建议使用)
- 2. 将生命和定义写在同一个.h文件中
- 五、 继承
- 总结
前言
typename、非类型模板参数、模板参数的特化、模板类成员函数声明和定义分离、继承等的介绍
一、typename
void Print(vector<int>& v)
{
vector<int>::iterator it = v.begin();
while (it != v.end())
{
cout << *it << " ";
++it;
}
cout << endl;
}
对上述Print函数进行模板化,如果不加typename会出现如下情况:
#include <iostream>
#include <vector>
#include <list>
using namespace std;
template <class Container>
void Print(Container& v)
{
typename Container::iterator it = v.begin(); // 此处要加typename修饰
while (it != v.end())
{
cout << *it << " ";
++it;
}
cout << endl;
}
int main()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
Print(v);
vector<double> v1;
v1.push_back(1.1);
v1.push_back(2.2);
v1.push_back(3.3);
v1.push_back(4.4);
v1.push_back(5.5);
Print(v1);
list<double> lt;
lt.push_back(1.14);
lt.push_back(2.14);
lt.push_back(3.14);
lt.push_back(4.14);
lt.push_back(5.14);
Print(lt);
return 0;
}
二、非类型模板参数
- 比如一个静态栈,不仅需要接收类型参数, 还需要接收每个数组的长度
#include <iostream>
#include <vector>
#include <list>
using namespace std;
// 静态栈
template <class T, size_t N>
class Stack
{
public:
Stack()
{}
private:
T _a[N];
int _top;
};
int main()
{
Stack<int, 10> st1; // 10
Stack<double, 100> st2; // 100
return 0;
}
三、模板参数的特化
特化指的就是 特殊化处理
1. 函数模板参数的特化
- 函数模板个格式,虽然需要加template<>,但是大多数情况下,我们可以直接去掉,与原来的函数构成函数重载,达到特化的效果
#include <iostream>
using namespace std;
// 函数模板的特化
template <class T>
bool Less(T left, T right)
{
return left < right;
}
// 函数模板的特化格式
template<>
bool Less<int*>(int* left, int* right)
{
return *left < *right;
}
int main()
{
cout << Less(1, 2) << endl;
int a = 2, b = 1;
cout << Less(&a, &b) << endl;
return 0;
}
2. 类模板的特化
类模板的特化包括 全特化,偏特化(半特化), 限制类型为指针, 限制类型为引用
#include <iostream>
using namespace std;
// 类模板特化
template <class T1, class T2>
class A
{
public:
A() { cout << "A<T1, T2>" << endl; }
private:
};
// 全特化
template<>
class A<int, double>
{
public:
A() { cout << "A<int, double>" << endl; }
private:
};
// 偏特化
template <class T1>
class A<T1, double>
{
public:
A() { cout << "A<T1, double>" << endl; }
private:
};
// 对类型进行限制---指针
template <class T1, class T2>
class A<T1*, T2*>
{
public:
A() { cout << "A<T1*, T2*>" << endl; }
private:
};
// 对类型限制---引用
template <class T1, class T2>
class A<T1&, T2&>
{
public:
A() { cout << "A<T1&, T2&>" << endl; }
private:
};
int main()
{
A<int, int> a1;
A<int, double> a2;
A<double, double> a3;
A<char, double> a4;
A<int*, double> a5;
A<int*, double*> a6;
A<void*, void*> a7;
A<int&, double&> a8;
return 0;
}
四、模板类成员函数声明和定义分离
模板类成员函数声明和定义分离 有两种方式:
一种是: 在函数的定义处显示实例化
另一种是: 将生命和定义写在同一个.h文件中,(有些还将这种文件以.hpp作为后缀)
模板类成员函数声明和定义直接分离,因为模板类型T没有进行实例化,编译器在链接阶段无法找到正确的地址,所以会出现编译报错。
1. 显示实例化(不建议使用)
// Stack.h
#pragma once
#include <vector>
namespace hhb
{
template<class T, class Container = std::vector<T>>
class stack
{
public:
void push(const T& x);
void pop();
bool empty()
{
return _con.empty();
}
const T& top()
{
return _con.front();
}
private:
Container _con;
};
}
// Stack.cpp
#include "Stack.h"
namespace hhb
{
template<class T, class Container>
void stack<T, Container>::push(const T& x)
{
_con.push_back(x);
}
template <class T, class Container>
void stack<T, Container>::pop()
{
_con.pop_back();
}
template
class stack<int>;
template
class stack<double>;
}
// test.cpp
#include "Stack.h"
int main()
{
hhb::stack<int> st;
st.push(1);
st.pop();
hhb::stack<double> st1;
st1.push(1.1);
st1.pop();
return 0;
}
- 不会有编译错误
2. 将生命和定义写在同一个.h文件中
// Stack.h
#pragma once
#include <vector>
namespace hhb
{
template<class T, class Container = std::vector<T>>
class stack
{
public:
void push(const T& x);
void pop();
bool empty()
{
return _con.empty();
}
const T& top()
{
return _con.front();
}
private:
Container _con;
};
template<class T, class Container>
void stack<T, Container>::push(const T& x)
{
_con.push_back(x);
}
template <class T, class Container>
void stack<T, Container>::pop()
{
_con.pop_back();
}
}
// test.cpp
#include "Stack.h"
int main()
{
hhb::stack<int> st;
st.push(1);
st.pop();
hhb::stack<double> st1;
st1.push(1.1);
st1.pop();
return 0;
}
- 不会有编译错误
五、 继承
访问限定符的权限 : public > protected > privated;
继承是有基类以继承方式继承给派生类
继承方式: 有三种 以 public 、 protected、 private 三种方式进行继承。
派生类对基类成员变量/成员函数的访问方式取决于: 基类的成员变量和成员函数的访问限定符以及派生类的继承方式:
- 基类的成员若为private, 则在派生类中无法看见(访问)基类private的成员
- 基类的protected和public成员, 与派生类的继承方式权限进行比较,权限小的即为在派生类中访问基类成员的访问方式。
#include <iostream>
using namespace std;
class Person
{
public:
Person()
{}
void print()
{
cout << "_name: " << _name << endl;
cout << "_age: " << _age << endl;
}
protected:
string _name = "perter";
int _age = 10;
};
class student : public Person
{
public:
private:
int _sid;
};
class teacher : public Person
{
public:
private:
int _tid;
};
int main()
{
student s;
s.print();
teacher t;
t.print();
return 0;
}
总结
typename、非类型模板参数、模板参数的特化、模板类成员函数声明和定义分离、继承等的介绍