1.3類模板
1.3.1類模板語法
作用:建立一個通用類,類中的成員 數(shù)據(jù)類型可以不具體指定,用一個虛擬的類型來代表;
語法:?
template<class T>
類
解釋:
template :聲明創(chuàng)建模板
class/typename :表明其后面的符號是一種數(shù)據(jù)類型
T? :通用數(shù)據(jù)類型,通常為大寫字母
示例:
template<class NameType,class AgeType>
class Person
{
public:
Person(NameType name, AgeType age)
{
this->m_Name = name;
this->m_Age = age;
}
NameType m_Name;
AgeType m_Age;
};
1.3.2類模板與函數(shù)模板區(qū)別
1.類模板沒有自動類型推導(dǎo)的使用方式;
2.類模板在模板參數(shù)列表中可以有默認參數(shù);
示例:
template<class NameType, class AgeType=int>
class Person
{
public:
Person(NameType name, AgeType age)
{
this->m_Name = name;
this->m_Age = age;
}
NameType m_Name;
AgeType m_Age;
};
void test01()
{
//無法使用自動類型推導(dǎo)
//Person p("Mike", 20);//error
Person<string,int>p("Mike", 20);
}
void test02()
{
Person<string>p("Mike", 20);//ok 因為模板參數(shù)列表設(shè)置了默認參數(shù)
}
1.3.3類模板中成員函數(shù)創(chuàng)建時機
類模板中成員函數(shù)和普通類中成員函數(shù)創(chuàng)建時機是有區(qū)別的:
1.普通類中成員函數(shù)一開始就可以創(chuàng)建;
2.類模板中成員函數(shù)在調(diào)用時才創(chuàng)建;
示例:
class Person1
{
public:
void showPerson1()
{
cout << "showPerson1()" << endl;
}
};
class Person2
{
public:
void showPerson2()
{
cout << "showPerson2()" << endl;
}
};
template <class T>
class MyClass
{
public:
T obj;
//類模板中的成員函數(shù),并不是一開始就創(chuàng)建的,而是在模板調(diào)用時再生成
void func1()
{
obj.showPerson1();
}
void func2()
{
obj.showPerson2();
}
};
void test01()
{
MyClass<Person1> m;
m.func1();
//m.func2();//error
//編譯會出錯,說明函數(shù)調(diào)用才會去創(chuàng)建成員函數(shù)
}
1.3.4類模板對象做函數(shù)參數(shù)
要點:類模板實例化出的對象,向函數(shù)傳參的方式
一共有三種傳入方式:
1.指定傳入的類型? ---直接顯示對象的數(shù)據(jù)類型
2.參數(shù)模板化? ? ---將對象中的參數(shù)變?yōu)槟0暹M行傳遞
3.整個類模板化? ? ---將這個對象類型 模板化進行傳遞、
示例:
template <class T1, class T2>
class Person
{
public:
Person(T1 name, T2 age)
{
this->m_Name = name;
this->m_Age = age;
}
void showPerson()
{
cout << "name: " << this->m_Name << endl
<< "age: " << this->m_Age << endl;
}
T1 m_Name;
T2 m_Age;
};
//1.指定傳入類型
void printPerson1(Person<string, int> &p)
{
p.showPerson();
}
void test01()
{
Person<string, int> p("Mike", 20);
printPerson1(p);
}
//2.參數(shù)模板化
template <class T1, class T2>
void printPerson2(Person<T1, T2> &p)
{
p.showPerson();
cout << "type of T1: " << typeid(T1).name() <<endl
<< "type of T2: " << typeid(T2).name() << endl;
}
void test02()
{
Person<string, int> p("Jack", 22);
printPerson2(p);
}
//3.這個類模板化
template <class T>
void printPerson3(T &p)
{
p.showPerson();
cout << "type of T: " << typeid(T).name() << endl;
}
void test03()
{
Person<string, int> p("Mary", 18);
printPerson3(p);
}
總結(jié):
1.通過類模板創(chuàng)建的對象,可以有三種方式向函數(shù)中進行傳參;
2.第一種指定傳入類型 使用的比較廣泛;
1.3.5類模板與繼承
1.當子類繼承的父類是一個類模板時,子類在聲明時,要指定出父類中T的類型;
2.如果不指定,編譯器無法給子類分配內(nèi)存;
3.如果想要靈活指定出父類中T的類型,子類也需要變?yōu)轭惸0澹?/p>
示例:
template <class T>
class Base
{
public:
T m;
};
class Son//:public Base//error 必須要知道父類中T類型,才能繼承給子類
:public Base<int>{};
//如果想要靈活指定出父類中T的類型,子類也需要變?yōu)轭惸0?/p>
template <class T1,class T2>
class Son2:public Base<T2>
{
public:
T1 obj;
};
void test02()
{
Son2<int,char> s2;
}
總結(jié):如果父類是類模板,子類需要指定出父類中T的數(shù)據(jù)類型
1.3.6類模板成員函數(shù)類外實現(xiàn)
示例:
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 << "name: " << this->m_Name << endl
<< "age: " << this->m_Age << endl;
}
總結(jié):
1.函數(shù)實現(xiàn)體前需要聲明是模板;
2.在類名之后加模板參數(shù)列表;
1.3.7類模板分文件編寫
問題:類模板中成員函數(shù)創(chuàng)建時機是在調(diào)用階段,導(dǎo)致分文件編寫時鏈接不到
解決:
1.直接包含.cpp源文件;
2.將聲明和實現(xiàn)寫到同一個文件中,并更改后綴名為 .hpp (約定名稱,而非強制)
注:主要采用第二種,將類模板成員函數(shù)寫到一起,并更改后綴為.hpp
示例:
1.person.hpp文件
#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;
};
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 << "name: " << this->m_Name << endl
<< "age: " << this->m_Age << endl;
}
2.實現(xiàn)文件
#include "person.hpp"
...
1.3.8類模板與友元
要點:掌握類模板配合友元函數(shù)的類內(nèi)和類外實現(xiàn)
全局函數(shù)類內(nèi)實現(xiàn)-直接在類內(nèi)聲明友元即可;
全局函數(shù)類外實現(xiàn)-需要提前讓編譯器知道全局函數(shù)的存在;
示例:
1.類內(nèi)實現(xiàn)
template<class T1, class T2>
class Person
{
friend void printPerson(Person<T1, T2> p)
{
cout << "name: " << p.m_Name << endl
<< "age: " << p.m_Age << endl;
}
public:
Person(T1 name, T2 age)
{
this->m_Name = name;
this->m_Age = age;
}
private:
T1 m_Name;
T2 m_Age;
};
2.類外實現(xiàn)
//提前讓編譯器知道Person類存在
template<class T1, class T2>
class Person;
//提前讓編譯器知道這個全局函數(shù)的存在
//函數(shù)模板聲明
template<class T1, class T2>
void printPerson2(Person<T1, T2> p)
{
cout << "name: " << p.m_Name << endl
<< "age: " << p.m_Age << endl;
}
template<class T1, class T2>
class Person
{? ?
? ? //error 普通函數(shù)聲明 并非函數(shù)模板聲明
//friend void printPerson2(Person<T1, T2> p);
//如果全局函數(shù)是類外實現(xiàn),需要讓編譯器提前知道這個函數(shù)的存在
friend void printPerson2<>(Person<T1, T2> p);
public:
Person(T1 name, T2 age)
{
this->m_Name = name;
this->m_Age = age;
}
private:
T1 m_Name;
T2 m_Age;
};
總結(jié):建議全局函數(shù)做類內(nèi)實現(xiàn),用法簡單,而且編譯器可以直接識別;