一、类模板(续day18)
1.1 类模板的成员函数在类外实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| template<class T1,class T2> class Person{ public: T1 name; T2 age; public: Person(T1 name,T2 age); void showPerson(void); };
template<class T1, class T2> Person<T1,T2>::Person(T1 name, T2 age) { this->name = name; this->age = age; cout<<"有参构造"<<endl; } template<class T1, class T2> void Person<T1,T2>::showPerson() { cout<<"name:"<<this->name<<",age:"<<this->age<<endl; } void test01(){ Person<string,int> ob1("小花",18); ob1.showPerson(); }
|
运行结果:
1.2 类模板源文件与头文件分离
1.2.1 源文件与头文件分离产生的问题
perosn.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #ifndef PERSON_H #define PERSON_H
template<class T1,class T2> class Person { public: T1 name; T2 age; public: Person(); Person(T1 name,T2 age); void showPerson(); };
#endif
|
person.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| #include "person.h" #include <iostream> using namespace std;
template<class T1,class T2> Person<T1,T2>::Person() { cout<<"无参构造函数"<<endl; }
template<class T1,class T2> Person<T1,T2>::Person(T1 name,T2 age) { this->name = name; this->age = age; cout<<"有参构造函数"<<endl; }
template<class T1,class T2> void Person<T1,T2>::showPerson() { cout<<"name:"<<this->name<<",age:"<<this->age<<endl; }
|
main.cpp
1 2 3 4 5 6 7 8 9 10
| #include <iostream> #include "person.h" using namespace std;
int main(int argc, char *argv[]) { Person<string,int> ob1("小花",18); ob1.showPerson(); return 0; }
|
运行结果:
结果分析:因为类模板会进行两次编译,第一次是类模板本身编译,第二次是在类模板的成员调用的时候类型确定了,会以确定的类型再一次进行编译。由于C++/C 是独立文件编译的。如果类模板的.cpp和.h分文件,会造成第二次编译出错,找不到在.cpp中对类的定义。解决办法如下。
1.2.2 解决办法
- 1、将main.cpp中的include<person.h>替换为include<person.cpp>,因为 .cpp中也包含的.h,相当于都有了,没有分离。但是include标准是包含头文件,基本不会包含.cpp
person.hpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| #ifndef PERSON_H #define PERSON_H
template<class T1,class T2> class Person { public: T1 name; T2 age; public: Person(); Person(T1 name,T2 age); void showPerson(); };
#include <iostream> using namespace std;
template<class T1,class T2> Person<T1,T2>::Person() { cout<<"无参构造函数"<<endl; }
template<class T1,class T2> Person<T1,T2>::Person(T1 name,T2 age) { this->name = name; this->age = age; cout<<"有参构造函数"<<endl; }
template<class T1,class T2> void Person<T1,T2>::showPerson() { cout<<"name:"<<this->name<<",age:"<<this->age<<endl; }
#endif
|
main.cpp
1 2 3 4 5 6 7 8 9 10 11 12
| #include <iostream>
#include "person.hpp" using namespace std;
int main(int argc, char *argv[]) { Person<string,int> ob1("小花",18); ob1.showPerson(); return 0; }
|
运行结果:
1.3 类模板的强化训练
设计一个数组模板类MyArray,完成对不同类型元素的管理。
myarray.hpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
| #ifndef MYARRAY_HPP #define MYARRAY_HPP #include <iostream> using namespace std;
template<class T> class MyArray{ private: T *addr; int capacity; int size; public: MyArray(); MyArray(int capacity); ~MyArray(); MyArray(const MyArray &ob);
void push_back(const T &val); void showMyArray(); };
template<class T> MyArray<T>::MyArray() { this->addr = nullptr; this->capacity = 0; this->size = 0; cout<<"无参构造函数"<<endl; }
template<class T> MyArray<T>::MyArray(int capacity) { this->addr = new T[capacity]; this->capacity = capacity; this->size = 0; cout<<"有参构造函数"<<endl; }
template<class T> MyArray<T>::~MyArray() { if(this->addr != nullptr){ delete [] this->addr; this->addr = nullptr; } cout<<"析构函数"<<endl; }
template<class T> MyArray<T>::MyArray(const MyArray &ob) { this->addr = new T[ob.capacity]; int i = 0; while (i<ob.size) { this->addr[i] = ob.addr[i]; i++; } this->capacity = ob.capacity; this->size = ob.size; cout<<"拷贝构造函数"<<endl; }
template<class T> void MyArray<T>::push_back(const T &val) { if(this->size >= this->capacity){ cout<<"数组已满"<<endl; return; } this->addr[this->size] = val; this->size++; }
template<class T> void MyArray<T>::showMyArray() { int i = 0; for(i = 0; i < this->size; i++){ cout<<this->addr[i]<<" "; } cout<<endl; }
#endif
|
main.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| #include <iostream> #include "myarray.hpp" #include <string> using namespace std; class Person{ private: string name; int age; public: friend ostream& operator <<(ostream& out,Person &ob); Person(){ cout<<"Person默认构造函数"<<endl; } Person(string name,int age){ this->name = name; this->age = age; cout<<"Person有参构造函数"<<endl; } };
ostream& operator <<(ostream& out,Person &ob){ out<<"name="<<ob.name<<",age="<<ob.age; return out; } void test01(){ MyArray<int> ob1(10); ob1.push_back(1); ob1.push_back(2); ob1.push_back(3); ob1.push_back(4); ob1.showMyArray();
MyArray<string> ob2(10); ob2.push_back("1"); ob2.push_back("b"); ob2.push_back("c"); ob2.push_back("hello world"); ob2.showMyArray();
MyArray<Person> ob3(10); ob3.push_back(Person("小花",19)); ob3.push_back(Person("小明",15)); ob3.push_back(Person("小王",16)); ob3.showMyArray(); }
int main(int argc, char *argv[]) { test01(); return 0; }
|
运行结果:
1.4 类模板与友元
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| #include <iostream>
using namespace std; template<class T1,class T2> class Person; template<class T1,class T2> void printPerson2(Person<T1,T2> &ob);
template<class T1,class T2> class Person{ private: T1 name; T2 age; public: Person(T1 name,T2 age); friend void printPerson1(Person<T1,T2> &ob){ cout<<"name="<<ob.name<<",age="<<ob.age<<endl; } friend void printPerson2<>(Person<T1,T2> &ob); };
template<class T1,class T2>
void printPerson2(Person<T1,T2> &ob){ cout<<"name="<<ob.name<<",age="<<ob.age<<endl; } template<class T1,class T2> Person<T1,T2>::Person(T1 name,T2 age){ this->name = name; this->age = age; cout<<"Person有参构造"<<endl; }
int main(int argc, char *argv[]) { Person<string,int> ob("小花",18); printPerson1(ob); printPerson2(ob); return 0; }
|
运行结果:
==注意:==
当友元函数在类外定义时,是有讲究的 有了templete printPerson2是一个模板函数 在类中声明的时候需要告诉编译器(加<>) 该友元函数是一个模板函数;而且需要将void printPerson2(Person<T1,T2> &ob)在类中声明之前,在类外在声明一次,不然编译器编译到类中声明时编译器找不到模板函数会报错;然后这时候编译器又找不到Person类,所以还要在前面声明一下Person类。看上面代码就懂了。