zl程序教程

您现在的位置是:首页 >  后端

当前栏目

C++面向对象程序设计(谭浩强)第三章第10~11节学习笔记

C++笔记学习 10 11 面向对象 程序设计 第三章
2023-06-13 09:18:38 时间

3.10 友元

3.10.1友元函数

如果在本类以外的其他地方定义了一个函数(这个函数可以说是不属于任何类的非成员函数,也可以是其他类的成员函数),在类体中用friend对其进行声明,此函数就称为本类的友元函数。

1.将普通函数声明为友元函数

#include<iostream>
using namespace std;
class Time
{
public:
	Time(int, int, int);
	friend void display(Time&);//声明display函数是为Time类的友元函数
private:
	int hour;
	int minute;
	int sec;
};
Time::Time(int h, int m, int s)
{
	hour = h;
	minute = m;
	sec = s;
}
void display(Time &t)
{
	cout << t.hour << ":" << t.minute << ":" << t.sec << endl;//必须加上对象名
//因为display函数不是Time类的成员函数,没有this指针,不能默认引用Time类的数据成员,必须指定要访问的对象
}
int main()
{
	Time t1(12, 13, 14);
	display(t1);
	return 0;
}

2.友元成员函数

friend函数不仅可以是一般函数(非成员函数),而且可以是另一个类中的成员函数。

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class Date;//声明Date类!!!“提前引用”
class Time
{
public:
	Time(int, int, int);
	void display(Date&);//声明display函数是为Time类的友元函数
private:
	int hour;
	int minute;
	int sec;
};
class Date
{
public:
	Date(int, int, int);
	friend void Time::display(Date&);//允许display函数使用私有成员数据
private:
	int month;
	int day;
	int year;
};
Time::Time(int h, int m, int s)
{
	hour = h;
	minute = m;
	sec = s;
}
void Time::display(Date& d)
{
	cout << d.month << "/" << d.day << "/" << d.year << endl;
	cout << hour << ":" << minute << ":" << sec << endl;
}
Date::Date(int m, int d, int y)
{
	month = m;
	day = d;
	year = y;
}
int main()
{
	Time t1(10, 13, 56);
	Date d1(12, 25, 2004);
	t1.display(d1);
	return 0;
}

类的提前声明的适用范围是有限的,只有在正式声明一个类以后才能用它去定义对象。

一个函数可以被多个类声明为“朋友”,这样就可以引用多个类中的私有数据。

3.10.2 友元类

可以将一个类B声明为另一个类A的“朋友”,此时B就是A的友元类。

声明友元类的一般形式: friend 类名;

 如上例中:

 说明:

(1)友元的关系是单向的而不是双向的。

(2)友元的关系不能传递。

关于友元利弊分析:面向对象程序设计的一个基本原则是封装性和信息隐蔽,而友元却可以访问其他类中的私有成员,不能不说这是对封装原则的一个小的破坏。但是它能有助于数据共享,能提高程序的效率,在使用友元时,要注意到它的副作用,不要过多地使用友元,只有在使用它能使程序精练,较大地提高程序效率时才用友元。也就是说,要在数据共享与信息隐蔽之间选择一个恰当的平衡点。

3.11 类模板

用一个模板实现一类多用

 template

由于类模板包含类型参数,因此又称为参数化的类。

类模板是类的抽象,类是类模板的实例。

一般形式为: 类模板名 <实际类型名>对象名(参数表); Compare <int> cmp(4,7);

#include<iostream>
using namespace std;
template <class numtype>
class Compare
{
public:
	Compare(numtype a, numtype b)
	{
		x = a; y = b;
	}
	numtype max()
	{
		return (x > y )? x : y;
	}
	numtype min()
	{
		return (x < y) ? x : y;
	}
private:
	numtype x;
	numtype y;
};
int main()
{
	Compare<int>cmp1(3, 7);
	cout << cmp1.max() << "是最大值。" << endl;
	cout << cmp1.min() << "是最小值。" << endl;
	Compare<float>cmp2(3.6, 7.9);
	cout << cmp2.max() << "是最大值。" << endl;
	cout << cmp2.min() << "是最小值。" << endl;
	Compare <char>cmp3('a', 'A');
	cout << cmp3.max() << "是最大值。" << endl;
	cout << cmp3.min() << "是最小值。" << endl;
}

 在类模板外点过成员函数时,不能用一般定义类成员函数的形式。 应当写成类模板的形式: template <class numtype> template Conpare <numtype>::max() {return (x>y)?x:y;}

 归纳 1)先写出一个实际的类(如本节开头的 Compare_int )。由于其语义明确,含义清楚,一般不会出错。

(2)将此类中准备改变的类型名(如 int 要改变为 float 或 char )改用一个自己指定的虚拟类型名(如上例中的 numtype )。

(3)在类声明前面加入一行,格式为  template < class 虚拟类型参数>//注意本行末尾无分号  template < class numtype >  class Compare {...};//类体

 (4)用类模板定义对象时用以下形式: 类模板名<实际类型名>对象名; 类模板名<实际类型名>对象名(实参表);

 compare < int > cmp ;  compare < int > cmp (3,7);

 (5)如果在类模板外定义成员函数,应写成类模板形式:

 template < class 虚拟类型参数> 函数类型  类模板名<虚拟类型参数>::成员函数名(函数形参表){…}

 说明:

(1)类模板的类型参数可以有一个或多个,毎个类型前面都必须加 class 

 template < class T1, class T2>  class someclass  {…};

(2)和使用类一样,使用类模板时要注意其作用域(在同一个文件中使用) 

(3)模板可以有层次,一个类模板可以作为基类,派生出派生模板类。