一、类模板 - 函数声明与函数实现分离
1、函数声明与函数实现分离
项目开发中 , 需要 将 函数声明 与 函数实现 分开进行编码 ;
将 函数声明 与 函数实现 分开进行编码 , 有 三种 方式 :
- 类模板 的 函数声明 与 函数实现 都写在同一个类中 ;
- 类模板 的 函数实现 在 类外部进行 , 写在相同的 .h 和 .cpp 源码文件中 ;
- 类模板 的 函数实现 在 类外部进行 , 写在不同的 .h 和 .cpp 源码文件中 ;
2、代码示例 - 函数声明与函数实现分离
对于下面的 Father 类中的 printValue 函数 ,
代码语言:javascript复制// 声明 类模板 父类
template <typename T>
class Father {
public:
T value;
Father(T val) : value(val) {}
void printValue() {
std::cout << value << std::endl;
}
};
如果要在外部 实现 printValue 的话 , 写法如下 :
代码语言:javascript复制// 声明 类模板 父类
template <typename T>
class Father {
public:
T value;
Father(T val) : value(val) {}
void printValue();
};
// 在 类模板 外部实现函数
template <typename T>
void Father<T>::printValue()
{
std::cout << value << std::endl;
}
每个函数前面都要加上 template <typename T>
类型参数列表声明 ,
使用域作用符 Father<T>::
访问函数 ;
3、函数声明与函数实现分离 友元函数引入
如果要在 类模板 中进行运算符重载 , 就需要用到友元函数 ;
如果将 类模板 的 函数实现 , 定义在函数外部 , 结合 友元函数 使用 , 就变得很复杂 , 下面针对该问题进行讨论 ;
二、普通类的运算符重载 - 函数声明 和 函数实现 写在同一个类中
下面的类是一个 普通类 , 其中定义了 成员变量 和 成员方法 ;
并为其重载了 左移运算符 和 加法运算符 ;
其中 加法运算符 重载 是在 类内部实现的 ,
左移运算符 重载 是在类外部 通过友元函数实现的 , 因为左移运算符的 左操作数是 ostream& 类型的 , 如果定义在了 类内部 , 左操作数就默认为当前类 ;
代码示例 :
代码语言:javascript复制#include "iostream"
using namespace std;
class Student
{
// 左移运算符重载
friend ostream& operator<<(ostream& out, Student& s)
public:
Student(int x = 0, int y = 0)
{
this->a = x;
this->b = y;
}
// 重载 运算符
Student operator (Student& s)
{
Student student(this->a s.a, this->b s.b);
return student;
}
// 打印类成员变量
void printStudent()
{
cout << "a = " << a << " , b = " << b << endl;
}
public:
int a, b;
};
// 重载左移运算符
ostream& operator<<(ostream& out, Student& s)
{
out << "a:" << s.a << " b: " << s.b << endl;
return out;
}
int main() {
Student s(666, 888);
s.printStudent();
// 控制台暂停 , 按任意键继续向后执行
system("pause");
return 0;
}
执行结果 :
代码语言:javascript复制10
666
88
66
Press any key to continue . . .
三、类模板的运算符重载 - 函数声明 和 函数实现 写在同一个类中
1、类模板 的 外部友元函数问题
将上述 " 普通类的运算符重载 - 函数声明 和 函数实现 写在同一个类中 " 示例改造成 类模板 示例 ;
问题就出现在 定义在外部的 友元函数 中 ,
友元函数 , 不能 读取 和 访问 到 泛型类型 T , 也就是 类模板 中 的 template <typename T>
泛型类型 T ;
在外部重新定义 template <typename T>
就是重新定义了一个新的泛型 , 与 类模板 中的 T 不是同一个泛型类型 ;
解决上述问题 , 就需要将 友元函数 定义在 类模板 的内部 ;
代码语言:javascript复制template <typename T>
class Student
{
// 左移运算符重载
friend ostream& operator<<(ostream& out, Student& s2)
{
out << "a:" << s.a << " b: " << s.b << endl;
return out;
}
}
2、代码示例 - 类模板 函数声明 和 函数实现 写在同一个类中 ( 包括友元函数 )
代码示例 :
代码语言:javascript复制#include "iostream"
using namespace std;
template <typename T>
class Student
{
// 左移运算符重载
friend ostream& operator<<(ostream& out, Student& s)
{
out << "a:" << s.a << " b: " << s.b << endl;
return out;
}
public:
Student(T x, T y)
{
this->a = x;
this->b = y;
}
// 重载 运算符
Student operator (Student& s)
{
Student student(this->a s.a, this->b s.b);
return student;
}
// 打印类成员变量
void printStudent()
{
cout << "a = " << a << " , b = " << b << endl;
}
public:
T a, b;
};
// 重载左移运算符
//ostream& operator<<(ostream& out, Student& s)
//{
// out << "a:" << s.a << " b: " << s.b << endl;
// return out;
//}
int main() {
// 模板类不能直接定义变量
// 需要将 模板类 具体化之后才能定义变量
Student<int> s(666, 888);
s.printStudent();
Student<int> s2(222, 111);
s2.printStudent();
// 验证 加法运算符 重载
Student<int> s3 = s s2;
s3.printStudent();
// 验证 左移运算符 << 重载
cout << s3 << endl;
// 控制台暂停 , 按任意键继续向后执行
system("pause");
return 0;
}
执行结果 :
代码语言:javascript复制a = 666 , b = 888
a = 222 , b = 111
a = 888 , b = 999
a:888 b: 999
Press any key to continue . . .