【C++】泛型编程 ⑨ ( 类模板的运算符重载 - 函数声明 和 函数实现 写在同一个类中 | 类模板 的 外部友元函数问题 )

2023-11-22 12:45:53 浏览数 (1)

一、类模板 - 函数声明与函数实现分离


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 . . .

0 人点赞