友元函数
友元函数是一种定义在类外部的普通函数,其特点是能够访问类中私有成员和保护成员,即类的访问权限的限制对其不起作用。
友元函数需要在类体内进行说明,在前面加上关键字friend
例:
友元函数特点:
- 1.友元函数不是成员函数,用法也与普通的函数完全一致,只不过它能访问类中所有的数据。
- 2.友元函数破坏了类的封装性和隐蔽性,使得非成员函数可以访问类的私有成员。
- 3.一个类的友元可以自由地用该类中的所有成员。
示例C++代码如下:
#include<iostream>
using namespace std;
class A{
float x, y;
public:
A(float a, float b)
{
x = a;
y = b;
}
float Sum()
{
return x + y;
}
friend float Sum(A &a)
{
return a.x + a.y;
}
};
int main()
{
A t1(4, 5), t2(10, 20);
cout << t1.Sum() << endl;
cout << Sum(t2) << endl;
return 0;
}
运行结果如下:
代码分析:
有关友元函数的使用,说明如下:
- 1.友元函数不是类的成员函数
- 2.友元函数近似于普通的函数,它不带有this指针,因此必须将对象名或对象的引用作为友元函数的参数,这样才能访问到对象的成员。
友元函数与一般函数的不同点在于:
1、友元函数必须在类的定义中声明,其函数体可在类内定义,也可在类外定义;
2、它可以访问该类中的所有成员(公有的、私有的和保护的),而一般函数只能访问类中的公有成员。
示例C++代码如下:
#include<iostream>
using namespace std;
class A{
float x, y;
public:
A(float a, float b)
{
x = a;
y = b;
}
float Getx()
{
return x;
}
float Gety()
{
return y;
}
float Sum()
{
return x + y;
}
friend float Sum(A &);
};
float Sumxy(A &a)
{
return a.Getx() + a.Gety();
}
float Sum(A &a)
{
return a.x + a.y;
}
int main()
{
A t1(1, 2), t2(10, 20), t3(100, 200);
cout << t1.Sum() << endl;
cout << Sum(t2) << endl;
cout << Sumxy(t3) << endl;
return 0;
}
运行结果如下:
代码分析如下:
Attention!!!
1、友元函数不受类中访问权限关键字的限制,可以把它放在类的私有部分,放在类的公有部分或放在类的保护部分,其作用都是一样的。换言之,在类中对友元函数指定访问权限是不起作用的。
2、友元函数的作用域与一般函数的作用域相同。
3、谨慎使用友元函数。通常使用友元函数来取对象中的数据成员值,而不修改对象中的成员值,则肯定是安全的。
大多数情况是友元函数是某个类的成员函数,即A类中的某个成员函数是B类中的友元函数,这个成员函数可以直接访问B类中的私有数据。这就实现了类与类之间的沟通。
注意:一个类的成员函数作为另一个类的友元函数时,应先定义友元函数所在的类。
示例C++代码如下:
#include<iostream>
using namespace std;
class B;
class A{
float x, y;
public:
A(float a, float b)
{
x = a;
y = b;
}
float Sum(B &);
void Show()
{
cout << "x = " << x << '\t' << "y = " << y << endl;
}
};
class B{
float m, n;
public:
B(float a, float b)
{
m = a;
n = b;
}
friend float A::Sum(B &);
};
float A::Sum(B &b)
{
x = b.m + b.n;
y = b.m - b.n;
}
int main()
{
A a1(3, 5);
B b1(10, 20);
a1.Sum(b1);
a1.Show();
return 0;
}
运行结果如下:
友元类
示例C++代码如下:
#include<iostream>
using namespace std;
//class B;
const float PI = 3.1415926;
class A{
float r;
float h;
public:
A(float a, float b)
{
r = a;
h = b;
}
float Getr()
{
return r;
}
float Geth()
{
return h;
}
friend class B;
};
class B
{
int number;
public:
B(int n = 1)
{
number = n;
}
void Show(A &a)
{
cout << PI * a.r * a.h * number << endl;
}
};
int main()
{
A a1(25, 40), a2(10, 40);
B b1(2);
b1.Show(a1);
b1.Show(a2);
return 0;
}
运行结果如下:
对比上面两个代码我们会发现,前者先声明了一个class B,而后者却不需要。这是因为如果为声明类B,则在前一个代码中,class A中成员函数Sum的参数类型是B,而编译器从上往下运行到成员函数Sum这里一直没找到关于类B的声明,所以要提前声明类B,而上面这个代码为何不需要呢?因为friend class B;编译器会接着往下找关于B类的声明定义,所以不需要提前声明B
不管是按哪一种方式派生,基类的私有成员在派生类中都是不可见的。
如果在一个派生类中要访问基类中的私有成员,可以将这个派生类声明为基类的友元。
示例C++代码如下:
#include<iostream>
using namespace std;
class M{
friend class N; //N为M的友元,可直接使用M中的私有成员
int i, j;
void show()
{
cout << "i = " << i << '\t' << "j = " << j << endl;
}
public:
M(int a = 0, int b = 0)
{
i = a;
j = b;
}
};
class N:public M{
public:
N(int a = 0, int b = 0):M(a, b)
{
}
void Print()
{
show();
cout << "i + j = " << i + j<< endl;
}
};
int main()
{
N n1(10, 20);
M m1(100, 200);
n1.Print();
return 0;
}
运行结果如下:
综合题
(1)
定义描述职工档案的类Archives,私有数据成员为职工号(No)、姓名(Name[8])、性别(Sex)、年龄(Age)。成员函数有:构造函数、显示职工信息的函数Show()。再由职工档案类派生出职工工资类Laborage,在职工工资类Laborage中新增数据成员:应发工资(SSalary)、社保金(Security)、实发工资(Fsalary),其成员函数有:构造函数,计算实发工资的函数Count(),计算公式为:实发工资=应发工资-社保金。显示职工档案及工资的函数Display()。在主函数中用Laborage类定义职工对象lab,并赋初始值(1001,”Cheng”,’M’,21,2000,100),然后显示职工档案与工资
详细C++代码如下:
#include<bits/stdc++.h>
using namespace std;
class Archives{
private:
int No;
char Name[8];
char Sex;
int Age;
public:
void Show();
Archives(int no, char *p, char s, int age)
{
No = no;
strcpy(Name, p);
Sex = s;
Age = age;
}
};
void Archives::Show()
{
cout << "No." << No << endl;
cout << "Name:" << Name << endl;
cout << "Sex:" << Sex << endl;
cout << "Age:" << Age << endl;
}
class Laborage:public Archives{
float SSalary;
float Security;
float Fsalary;
public:
Laborage(int no, char *p, char s, int age, float salary, float security):Archives(no, p, s, age)
{
SSalary = salary;
Security = security;
Count();
}
void Count()
{
Fsalary = SSalary - Security;
}
void Display()
{
Show();
cout << "SSalary:" << SSalary << endl;
cout << "Security:" << Security << endl;
cout << "Fsalary:" << Fsalary << endl;
}
};
int main()
{
Laborage lab(1001, "Cheng", 'M', 21, 2000, 100);
lab.Display();
return 0;
}
运行结果如下:
(2)
定义描述矩形的类Rectangle,其数据成员为矩形的中心坐标(X,Y)、长(Length)与宽(Width)。成员函数为计算矩形面积的函数Area()与构造函数。再定义描述圆的类Circle,其数据成员为圆的中心坐标(X,Y)与半径R,其成员函数为构造函数。再由矩形类与圆类多重派生出长方体类Cuboid,其数据成员为长方体的高(High)与体积(Volume)。成员函数为:构造函数,计算体积的函数Vol(),显示矩形坐标(X,Y)、长方体的长、宽、高与体积的函数Show()。主函数中用长方体类定义长方体对象cub,并赋初始值(10,10,10,20,30,30,10,10),最后显示长方体的矩形坐标(X,Y)与长方体的长、宽、高与体积。
详细C++代码如下:
#include<bits/stdc++.h>
using namespace std;
#define PI 3.1415926
class Rectangle{
private:
float X, Y;
float Length, Width;
public:
Rectangle(float x, float y, float length, float width)
{
X = x;
Y = y;
Length = length;
Width = width;
}
float Area()
{
return Length * Width;
}
float Getx()
{
return X;
}
float Gety()
{
return Y;
}
float GetLen()
{
return Length;
}
float GetWidth()
{
return Width;
}
};
class Circle{
private:
float X, Y;
float R;
public:
Circle(int x, int y, int r)
{
X = x;
Y = y;
R = r;
}
double Area()
{
return R * R * PI;
}
};
class Cuboid:public Rectangle, public Circle{
private:
float High, Volume;
public:
Cuboid(float x, float y, float length, float width, int xx, int yy, int r, float high):Rectangle(x, y, length, width), Circle(xx, yy, r){
High = high;
Vol();
}
void Vol()
{
Volume = High * Rectangle::Area();
}
void Show()
{
cout << "(X, Y) = " << Getx() << ", " << Gety() << endl;
cout << "Length:" << GetLen() << " Width:" << GetWidth() << " High:" << High << endl;
cout << "Volume:" << Volume << endl;
}
};
int main()
{
Cuboid cub(10, 10, 10, 20, 30, 30, 10, 10);
cub.Show();
return 0;
}
运行结果如下:
(3)
定义个人信息类Person,其数据成员有姓名、性别、出生年月。并以Person为基类定义一个学生的派生类Student,增加描述学生的信息:班级、学号、专业、英语成绩和数学成绩。再由基类Person定义一个职工的派生类Employee,增加描述职工的信息:部门、职务、工资。编写程序实现学生与职工信息的输入与输出。
详细C++代码如下:
#include<bits/stdc++.h>
using namespace std;
class Person{
private:
char Name[20];
char sex;
char BirthDate[20];
public:
Person(char *p, char s, char *b)
{
strcpy(Name, p);
sex = s;
strcpy(BirthDate, b);
}
char *GetName()
{
return Name;
}
char Getsex()
{
return sex;
}
char * GetBirthDate()
{
return BirthDate;
}
};
class Student:public Person{
int Classn;
int Snum;
char Major[20];
float English;
float Math;
public:
Student(char *p, char s, char *b, int classn, int snum, char *m, float english, float math):Person(p, s, b)
{
Classn = classn;
Snum = snum;
strcpy(Major, m);
English = english;
Math = math;
}
void ShowS()
{
cout << "Name:" << GetName() <<endl;
cout << "sex:" << Getsex() << endl;
cout << "BirthDate:" << GetBirthDate() << endl;
cout << "Classn:" << Classn << endl;
cout << "Snum:" << Snum << endl;
cout << "Major:" << Major << endl;
cout << "English:" << English << endl;
cout << "Math:" << Math << endl;
}
};
class Employee:public Person{
char Deployment[20];
char Task[20];
float Salary;
public:
Employee(char *p, char s, char *b, char *deploy, char *task, float salary):Person(p, s, b)
{
strcpy(Deployment, deploy);
strcpy(Task, task);
Salary = salary;
}
void ShowE()
{
cout << "Name:" << GetName() <<endl;
cout << "sex:" << Getsex() << endl;
cout << "BirthDate:" << GetBirthDate() << endl;
cout << "Deployment:" << Deployment << endl;
cout << "Task:" << Task << endl;
cout << "Salary:" << Salary << endl;
}
};
int main()
{
char name[20], sex, birthdate[20];
int classn, snum;
char major[20];
float English, Math;
cout << "please input student's name(char *), sex(char), birthdate(char), class(int), studentnumber(int), major(char *), English(float) and Math(float):" << endl;
cin >> name >> sex >> birthdate >> classn >> snum >> major >> English >> Math;
Student stud(name, sex, birthdate, classn, snum, major, English, Math);
char deployment[20], task[20];
float salary;
cout << "please input Employee's name(char *), sex(char), birthdate(char), deployment(char *), task(char *) and salary(float):" << endl;
cin >> name >> sex >> birthdate >> deployment >> task >> salary;
Employee employee(name, sex, birthdate, deployment, task, salary);
stud.ShowS();
employee.ShowE();
return 0;
}
运行结果如下:
(4)
定义一个复数类Complex,复数的实部Real与虚部Image定义为私有数据成员。用复数类定义复数对象c1、c2、c3,用默认构造函数将c1初始化为c1=20+40i ,将c2初始化为c2=0+0i,用拷贝构造函数将c3初始化为c3=20+40i。用公有成员函数Dispaly()显示复数c1、c2与c3 的内容。
#include<iostream>
using namespace std;
class Complex{
private:
int Real;
int Image;
public:
Complex()
{
Real = 0;
Image = 0;
}
Complex(int real, int image)
{
Real = real;
Image = image;
}
void Display()
{
cout << Real << "+" << Image << "i" << endl;
}
Complex(Complex &a)
{
Real = a.Real;
Image = a.Image;
}
};
int main()
{
Complex c1(20, 40), c2, c3;
c3 = Complex(c1);
c1.Display();
c2.Display();
c3.Display();
return 0;
}
运行结果如下:
(5)
定义一个学生成绩类Score,描述学生成绩的私有数据成员为学号(No)、姓名(Name[8])、数学(Math)、物理(Phi)、数据结构(Data)、平均分(ave)。定义能输入学生成绩的公有成员函数Write(),能计算学生平均分的公有成员函数Average(),能显示学生成绩的公有成员函数Display()。在主函数中用Score类定义学生成绩对象数组s[3]。用Write()输入学生成绩,用Average()计算每个学生的平均分,最后用Display()显示每个学生的成绩。
实验数据:
No Name Math Phi Data Ave
1001 Zhou 80 70 60
1002 Chen 90 80 85
1003 Wang 70 75 89
#include<iostream>
using namespace std;
class Score{
private:
long long No;
char Name[8];
float Math;
float Phi;
float Data;
float Ave;
public:
void Write()
{
cout << "Please input No. Name Math Phi Data:" << endl;
cin >> No >> Name >> Math >> Phi >> Data;
Average();
}
void Average()
{
Ave = (Math + Phi + Data) / 3.0;
}
void Display()
{
cout << No << " " << Name << " " << Math << " "<< Phi << " "<< Data << " "<< Ave << endl;
}
};
int main()
{
Score s[3];
for(int i = 0; i < 3; i++)
{
s[i].Write();
}
cout << "No. Name Math Phi Data Ave" << endl;
for(int i = 0; i < 3; i++)
{
s[i].Display();
}
return 0;
}
运行结果如下:
(6)
定义一个矩形类Rectangle,矩形的左上角(Left,Top)与右下角坐标(Right,Bottom)定义为保护数据成员。用公有成员函数Diagonal()计算出矩形对角线的长度,公有成员函数Show()显示矩形左上角与右下角坐标及对角线长度。在主函数中用new运算符动态建立矩形对象r1,初值为(10,10,20,20)。然后调用Show()显示矩形左上角与右下角坐标及对角线长度。最后用delete运算符回收为矩形动态分配的存储空间。
#include<bits/stdc++.h>
using namespace std;
class Rectangle{
protected:
int Left, Top;
int Right, Bottom;
public:
Rectangle(int left, int top, int right, int bottom)
{
Left = left;
Top = top;
Right = right;
Bottom = bottom;
}
float Diagonal()
{
int Line1 = (Left - Right) * (Left - Right);
int Line2 = (Top - Bottom) * (Top - Bottom);
return sqrt(Line1 + Line2);
}
void Show()
{
cout << "(" << Left << " ," << Top << ")" << endl;
cout << "(" << Right << " ," << Bottom << ")" << endl;
cout << Diagonal() << endl;
}
};
int main()
{
Rectangle *r1 = new Rectangle(10, 10, 20, 20);
r1->Show();
delete r1;
return 0;
}
运行结果如下:
(7)
建立一个存放素数的类Prime,具体要求如下
①私有数据成员。
int a[25]:存放指定范围内的所有素数。
int n1,n2:存放指定范围的下限和上限
int num:存放素数的个数。
②公有成员函数
Prime(int m1,int m2):构造函数,用参数m1、m2初始化n1、n2,同时初始化num。
void primef():求指定范围内的所有素数,把它们依次存放在数组a中。并将求出的素数个数赋给num。
void show():显示求出的素数的个数及所有的素数,每行输出5个素数。
③在主函数中定义一个Prime类的对象p(100,200),通过p调用成员函数完成求素数及输出素数的工作。
#include<bits/stdc++.h>
using namespace std;
class Prime{
private:
int a[25];
int n1, n2; //下限和上限
int num; //存放素数个数
public:
Prime(int m1, int m2)
{
n1 = m1;
n2 = m2;
num = 0;
}
void primef()
{
for(int i = n1; i <= n2; i++)
{
int flag = 1;
for(int j = 2; j < sqrt(i); j++)
{
if(i % j == 0)
{
flag = 0;
break;
}
else
continue;
}
if(flag)
{
a[num++] = i;
}
}
}
void show()
{
cout << "Total:" << num << endl;
for(int i = 0; i < num; i++)
{
cout << a[i] << " ";
if((i + 1) % 5 == 0)
cout << endl;
}
if(num >= 25)
cout << "数组已存满!余下的素数不存放了."<<endl;
}
};
int main()
{
Prime p(100, 200);
p.primef();
p.show();
return 0;
}
运行结果如下: