1.模板
模板的意义:可以对类型进行参数化
函数模板
怎么定义模板参数列表
模板类型参数
模板非类型参数
函数模板
模板的实例化
模板函数 ===》 需要编译的
模板的实参推演 compare<char*>(“aaa”, “bbb”)
模板的特例化(特化,专用化)
非模板函数,函数模板的特例化,函数模板的共存关系(重载关系)
template<typename T>
class Link
{
public:
Link(){ mphead = new Node(); }
~Link();
void insertHead(const T &val);
bool query(const T &val)
{
Node *pcur = mphead->mpnext;
while (pcur != NULL)
{
if (pcur->mdata == val)
return true;
pcur = pcur->mpnext;
}
return false;
}
private:
struct Node
{
// 零构造 零初始化
Node(T data=T()) :mdata(data), mpnext(NULL){}
T mdata;
Node *mpnext;
};
// 返回第一个值为val节点的节点地址
Node* getNodeAddr(const T &val);
Node *mphead;
};
template<typename T>
Link<T>::~Link()
{
Node *pcur = mphead;
while (pcur != NULL)
{
mphead = mphead->mpnext;
delete pcur;
pcur = mphead;
}
}
template<typename T>
void Link<T>::insertHead(const T &val)
{
Node *pnode = new Node(val);
pnode->mpnext = mphead->mpnext;
mphead->mpnext = pnode;
}
//Link<T>::Node依赖名称不是类型
template<typename T>
typename Link<T>::Node* Link<T>::getNodeAddr(const T &val)
{
Node *pcur = mphead->mpnext;
while (pcur != NULL)
{
if (pcur->mdata == val)
return true;
pcur = pcur->mpnext;
}
return false;
}
int main()
{
//int a = int();
//cout << a << endl;
//类模板的选择性实例化
Link<char*> strLink1;
strLink1.insertHead("aaa");
strLink1.insertHead("bbb");
strLink1.insertHead("ccc");
cout << strLink1.query("bbb") << endl;
char a[] = "aaa";
char b[] = "bbb";
char c[] = "ccc";
Link<char*> strLink2;
strLink2.insertHead(a);
strLink2.insertHead(b);
strLink2.insertHead(c);
cout << strLink2.query("bbb") << endl;
return 0;
}
两个问题点:
1.typename的另一层含义
2.成员方法的模板
1.1函数模板
模板参数列表 函数模板
template<typename T>
bool compare(T a, T b)
{
cout << "template compare" << endl;
cout << typeid(T).name() << endl;
return a > b;
} // const int a=10; int b=20;
/*
模板函数
bool compare<int>(int a, int b)
{
cout << "template compare" << endl;
cout << typeid(int).name() << endl;
return a > b;
}
1.2模板的特例化版本
template<>
bool compare<char*>(char * a, char *b)
{
cout << "compare<char*>" << endl;
return strcmp(a, b);
}
template<>
bool compare<int>(int a, int b)
{
cout << "compare<int>" << endl;
return a > b;
}
bool compare(char *a, char *b)
{
cout << "compare_char*" << endl;
return strcmp(a, b);
}
bool compare(int a, int b)
{
cout << "compare_in>" << endl;
return a > b;
}
template<typename T> //
void sort(T arr[], int size)
{
T tmp;
for (int i = 0; i < size - 1; ++i)
{
for (int j = 0; j < size - 1 - i; ++j)
{
if (arr[j] > arr[j + 1])
{
tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
template<> //
void sort<char*>(char* arr[], int size)
{
char* tmp;
for (int i = 0; i < size - 1; ++i)
{
for (int j = 0; j < size - 1 - i; ++j)
{
if (strcmp(arr[j], arr[j + 1]) > 0)
{
tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
int main(int argc, char* argv[])
{
int arr[] = { 23, 4, 67, 8, 90, 21, 35, 74 };
sort<int>(arr, sizeof(arr)/sizeof(arr[0]));
for (int val : arr)
{
cout << val << " ";
}
cout << endl;
char *arr1[] = { "aaa", "bbb", "ccc" };
sort<char*>(arr1, sizeof(arr1) / sizeof(arr1[0]));
for (char* ptr : arr1)
{
cout << ptr << " ";
}
cout << endl;
// 函数的调用点 =》 根据指定类型函数模板进行实例化 =》 模板函数
//compare<int>(10, 20);
//compare<double>(10.5, 20.5);
//compare(20, 30);
//char a[] = "aaa";
//char b[] = "bbb";
//compare(a, b);
//compare<char*>(a, b);
return 0;
}
2.问题(多态)
1.你怎么理解C++里面的多态?
静态的多态(编译时期的多态):函数重载, 模板
动态的多态(运行时期的多态):继承中的虚函数
2.能不能把函数模板和模板的调用写在两个不同的源文件当中?
模板本身不编译,实例化以后才编译,模板不编译 模板代码都写在头文件当中, 各个源文件直接include使用就可以
test.cpp
template<typename T>
bool compare(T a, T b)
{
return a>b;
}
main.cpp
template<typename T>
bool compare(T a, T b);
int main()
{
compare(10, 20);
return 0;
}
3.例子
// 在一个数组中,查找一个元素,找到返回元素的下标,找不到返回-1
template<typename T>
int findValue(T arr[], int size, const T &val)
{
for (int i = 0; i < size; ++i)
{
if (arr[i] == val)
return i;
}
return -1;
}
template<>
int findValue(char* arr[], int size, char* const &val)
{
for (int i = 0; i < size; ++i)
{
if (strcmp(arr[i], val) == 0)
return i;
}
return -1;
}
int main()
{
char a[] = "aaa";
char b[] = "bbb";
compare<char*>(a, b);
char *arr[] = {"aaa", "bbb", "ccc"};
int index = findValue<char*>(arr, 3, "bbb");
cout << "index:" << index << endl;
4.成员方法的分类
4.1分类
1.普通的成员方法
。属于类的作用域
。调用必须依赖对象
。可以任意访问自己其它private私有成员
2.static成员方法 => 访问其它的静态成员
。属于类的作用域
。调用必须依赖类的作用域
。可以任意访问自己其它private静态私有成员
3.const常成员方法
。属于类的作用域
。调用必须依赖对象
。可以任意访问自己其它private私有成员,但是只能读,而不能写
4.2用法
常对象 =》 只能调用 =》 常成员方法
// 常识:普通方法只有读操作,都实现成const常方法;如果有写操作,那么
// 实现成普通方法
// 静态成员方法和普通成员方法有什么区别?
static void showBookCount() // 没有this指针
{
cout << “Book Count:” << mCount << endl;
}
onst int BOOK_LEN = 20;
class CBook
{
public:
CBook(char *n, int a, double p)
:mAmount(a), mPrice(p)
{
strcpy(mName, n);
mCount++;
}
/*void showBookBasicInfo() // CBook *this 编译自动添加this指针形参
{
cout << "name:" << this->mName << " amount:" << this->mAmount <<
" price:" << this->mPrice << endl;
}*/
// 常对象 =》 只能调用 =》 常成员方法
// 常识:普通方法只有读操作,都实现成const常方法;如果有写操作,那么
// 实现成普通方法
void showBookBasicInfo() const// const CBook *this
{
cout << "name:" << this->mName << " amount:" << this->mAmount <<
" price:" << this->mPrice << endl;
}
// 静态成员方法和普通成员方法有什么区别?
static void showBookCount() // 没有this指针
{
cout << "Book Count:" << mCount << endl;
}
private:
char mName[BOOK_LEN];
int mAmount;
double mPrice;
static int mCount; // 静态成员变量的声明
};
// 类的静态成员变量必须在类外进行初始化
int CBook::mCount = 0;
int main(int argc, char* argv[])
{
CBook book1("天龙八部", 10, 80.0);
CBook book2("倚天屠龙记", 20, 70.0);
CBook book3("射雕英雄传", 30, 90.0);
CBook book4("雪山飞狐", 30, 90.0);
book1.showBookBasicInfo(); // CBook*
CBook::showBookCount();
const CBook book5("圣经", 30, 90.0);
// CBook::showBookBasicInfo(&book5) const CBook*
book5.showBookBasicInfo(); // 常对象调用普通方法??? 不能!!!
return 0;
}
5.用模板实现栈
template<typename T>
class SeqStack // 模板名称 SeqStack<T> 必须指定实例化模板的类型
{
public:
SeqStack(int size = 10)
{
mTop = 0;
mSize = size;
mpStack = new T[mSize];
}
~SeqStack()
{
delete[]mpStack;
}
SeqStack<T>(const SeqStack<T> &src)
{
mTop = src.top;
mSize = src.mSize;
mpStack = new T[mSize];
for (int i = 0; i < mTop; i++)
{
mpStack[i] = src.mpStack[i];
}
}
SeqStack<T>& operator=(const SeqStack<T> &src)
{
if (this == &src)
{
return *this;
}
delete []mpStack;
mTop = src.top;
mSize = src.mSize;
mpStack = new T [mSize];
for (int i = 0; i < mTop; i++)
{
mpStack[i] = src.mpStack[i];
}
return *this;
}
void push(const T &val)
{
if (full())
{
T *ptmp = new T [mSize *2];
for (int i = 0; i < mTop; i++)
{
ptmp[i] = mpStack[i];
}
delete []mpStack;
mpStack = ptmp;
mSize *= 2;
}
mpStack[mTop++] = val;
}
void pop();
T top()const
{
return mpStack[top - 1];
}
bool full()const
{
return mTop == mSize;
}
bool empty()const
{
return mTop == 0;
}
private:
T *mpStack;
int mTop;
int mSize;
};
template<typename T>
void SeqStack<T>::pop()
{
if (empty())
{
return;
}
--top;
}
int main()
{
SeqStack<int> stack1;
SeqStack<double> stack2;
SeqStack<MazeNode> stack3;
return 0;
}