模板类可以按以下三种方式编码:
第一种:所有的类模板函数写在类的内部 |
第二种:所有的类模板函数写在类的外部,在一个cpp中 |
第三种:所有的类模板函数写在类的外部,在不同的.h和.cpp中 |
采用不同的方式对应的语法不一样。
第一种编码方式最简单,由于类模板函数在类中,所以函数头不再需要声明为模板函数,同时,类中有友元函数时,友元函数的定义也写在函数体中。
#pragma once #include <iostream> using namespace std; template <typename T> class Example { //当模板类中有友元函数时,而且采用将函数体写在类的内部时,友元函数的函数体也需要写在类内部 friend ostream& operator<<(ostream &out,Example& c) { out << "a:"<<c.a << "b:"<<c.b << endl; return out; } public: //构造函数 Example(T a1,T b1) { this->a = a1; this->b = b1; } //重载+运算符 Example<T> operator+(Example<T> e1) { Example<T> tmp(this->a + e1.a, this->b + e1.b); return tmp; } //普通函数 void exPrint() { cout << this->a <<this->b<< endl; } private: T a; T b; };
//测试代码:
#include <iostream>
using namespace std;
#include "mode1.h";
using namespace std;
#include "mode1.h";
int main()
{
Example<char> a('%', '!');
Example<char> b('"', '#');
Example<char> c = a + b;
cout << c << endl;
}
{
Example<char> a('%', '!');
Example<char> b('"', '#');
Example<char> c = a + b;
cout << c << endl;
}
第二种方式是在同一个源文件中,将函数的声明与定义分开,此时需要注意写在外面的函数时模板函数,而且要指定函数的域。
#include <iostream> using namespace std; template <typename T> class Example {
//此处注意,在<<后需要添加<T>,否则程序运行失败。这是由于模板函数的二次编译机制造成的,如果不加<T>,两次编译生成的函数头不一样,所以程序会报错 friend ostream& operator<<<T> (ostream &out, Example<T>& c); public: //构造函数 Example(T a1, T b1); //重载+运算符 Example<T> operator+(Example<T> e1); //普通函数 void exPrint(); private: T a; T b; };
//将构造函数分离出来,由于是模板函数,因此需要用模板函数标志,同时需指定该函数属于哪个类,以便于C++编译器进行内存空间的分配 template <typename T> Example<T>::Example(T a1, T b1) { this->a = a1; this->b = b1; }
//将重载函数分离出来,由于是模板函数,因此需要用模板函数标志,需要制定返回值类型,以便于C++编译器进行内存空间的分配 template <typename T> Example<T> Example<T>::operator+(Example<T> e1) { Example<T> tmp(this->a + e1.a, this->b + e1.b); return tmp; } template <typename T> void Example<T>::exPrint() { cout << this->a << this->b << endl; }
//友元函数的作用域是全局,并不属于类函数,所以不需要制定作用域,但仍未模板函数 template <typename T> ostream& operator<<(ostream &out, Example<T>& c) { out << "a:" << c.a << "b:" << c.b << endl; return out; } int main() { Example<char> a('%', '!'); Example<char> b('"', '#'); Example<char> c = a + b; cout << c << endl; return 0; }
**************谨记:友元函数在类外部定义时,一定要在声明处添加<T>; 只有对<<,>>进行重载时用友元函数,其他能不用千万别用。
第三种方式是编写类时常用的方法,也是将第二种方法中的类声明和函数定义分别写在了.h和.cpp文件中.
//头文件的编写
#pragma once #include <iostream> using namespace std; template <typename T> class Example { friend ostream& operator<<<T> (ostream &out, Example<T>& c); public: //构造函数 Example(T a1, T b1); //重载+运算符 Example<T> operator+(Example<T> e1); //普通函数 void exPrint(); private: T a; T b; }; template <typename T> Example<T>::Example(T a1, T b1) { this->a = a1; this->b = b1; }
//函数定义
#include "demo3.h" #include <iostream> using namespace std; template <typename T> Example<T> Example<T>::operator+(Example<T> e1) { Example<T> tmp(this->a + e1.a, this->b + e1.b); return tmp; } template <typename T> void Example<T>::exPrint() { cout << this->a << this->b << endl; } template <typename T> ostream& operator<<(ostream &out, Example<T>& c) { out << "a:" << c.a << "b:" << c.b << endl; return out; }
//测试程序
#include <iostream> using namespace std; #include "demo3.h" #include "demo3.cpp"//注意,此时需要将.h和.cpp文件都包含进来,这是因为二次编译机制不会使得按照头文件中编译成的函数头去自动寻找.cpp中的函数体 int main() { Example<char> a('%', '!'); Example<char> b('"', '#'); Example<char> c = a + b; cout << c << endl; return 0; }
在实际应用中,主要以方式一和方式三进行编码。