存在的意义:
当把类的成员的访问权限定义为private或者protected时,在类外只能通过公有函数成员访问,有时候频繁调用函数成员,必然降低程序运行效率。
友元的作用:
友元的作用是提高程序的运行效率,它可以直接访问类的私有和保护成员,但也因此破坏了类的封装性,应谨慎使用。
表现形式:
友元可以是一个函数,也可以是一个类。前者是友元函数,后者是友元类。
2.1 友元函数:
定义:在定义一个类时,若在类中用关键字freend关键字修饰函数,则该函数就成为该类的友元函数,它可以访问该类中的所有成员。
friend <type> FuncName(<args>);
实例:
class Person {
char name[10];
char sex[4];
Date birthday;
public:
Person(const char *name, const char *sex, int y, int m, int d);
friend void print(Person p1);
};
友元函数在类外的定义如下:
void print(Person p1)
{
printf("姓名:%s\n性别:%s\n出生日期:%d年%d月%d日\n", p1.name, p1.sex, p1.birthday.Getyear(), p1.birthday.Getmonth(), p1.birthday.Getday());
std::cout << p1.name << '\n';
}
由此可见,可以直接使用p1.name来访问数据成员,不再需要通过调用公有函数来访问。
关于友元函数使用有如下注意点:
友元函数必须在类的定义中说明
友元函数不是类的成员函数,所以不带this指针,因此必须将对象名或对象的应用作为友元函数的参数,并在函数体内使用’.'来访问对象的成员。
友元函数可以直接访问类中的所有成员
一个类的成员函数也可以作为另一个类的友元函数在声明这个友元函数时需要在函数名前面加上它的类型和作用域运算符“::”。如下:
class A{
...
int f(...);
};
class B{
friend int A::f(...);
};
2.2 友元类
若声明A类为B类的友元类,则A类的所有成员函数都成为B类的友元函数。通过友元类的声明,友元类A的成员函数可以通过对象名直接访问到B类对象隐藏的数据。
如下是类Date的定义
class Date {
int year,month,day;
public:
int Getyear() { return year; }
int Getmonth() { return month; }
int Getday() { return day; }
Date(int year, int month, int day) { this->year = year, this->month = month, this->day = day; std::cout << "定义的Date构造函数\n"; }
Date() { std::cout << "默认的Date构造函数\n"; }
friend class Person;
如下是类Person的函数成员
void Person::print()
{
printf("姓名:%s\n性别:%s\n出生日期:%d年%d月%d日\n", name, sex, birthday.year, birthday.month, birthday.day);
std::cout << name << '\n';
}
可以看到,类Date为类Person的友元类,所以在类Person的成员函数中可以直接访问类Date的数据成员。
注意:
友元关系是不传递的
友元关系不能继承,因为友元函数不是类的成员函数,所以不存在继承关系
谨慎使用友元,因为其破坏封装性
2.3 类的静态成员
静态成员主要用来解决一个类的不同对象之间的数据和函数共享问题。
2.3.1 静态数据成员
类的数据成员在类的每一个对象中都有自己的存储空间,但类的静态数据成员不同,对同类的多个对象,静态数据成员只占有统一个存储空间,定义如下:
class Student{
static int count;
};
由于类是一种数据类型,所以只有在定义类时才会分配存储空间,也就不会为静态数据成员分配存储空间,所以静态数据成员在使用前需要在文件作用域做定义性说明,以分配存储空间和初始化。静态数据成员定义性说明的格式为:(注意需要在函数外定义,若在主函数定义会报错。)
<数据类型> <类名>::<静态数据成员名>=<值>;
eg:
int Student::count=0;
这里,在数据成员名的前面不加关键字static。访问类的静态数据成员的方法是:
<类名>::<静态数据成员名>
eg:
Student::count;
2.3.2 静态成员函数
作用:因为静态成员先于对象存在存储空间,所以如何访问不生成对象的类的静态成员数据呢?
为了在不生成对象的情况下,直接访问静态数据成员,定义了静态成员函数的概念。定义静态成员函数的格式如下:
static 返回值类型 成员函数名(参数表);
eg:
static int AddCount();
**在静态成员函数的实现中,可以直接访问该类的静态数据成员,但不能直接访问非静态数据成员,因为类的静态成员不含this指针。如果要访问非静态数据成员,必须通过参数传递得到对象名,然后再通过对象来访问。**例程如下:
//类Person中有静态数据成员 count和静态成员函数count_f()
class Person {
static int count;
char name[10];
char sex[4];
Date birthday;
public:
Person(const char *name, const char *sex,Date p1);
void print();
Person(const char *name, const char *sex, int y, int m, int d);
static int count_f();
};
静态成员函数的定义如下:
int Person::count_f()
{
return count;
}
在主函数中调用如下:
int Person::count = 0;
int main()
{
std::cout << "人数:" << Person::count_f()<<'\n';
Date d1(1992,2,25);
Person p1("李明", "男",d1);
Person p2("李明", "男", 1992,3,24);
p1.print();
p2.print();
std::cout << "人数:" << Person::count_f() << '\n';
return 0;
可以看出当没有类的对象时,照样可以使用该静态成员函数访问静态数据成员。
当静态成员函数如下:
int Person::count_f()
{
std::cout << this->name << '\n';
return count;
}
编译器会提示,this只能用于非静态成员函数内部,然后报错。