链接:https://pan.baidu.com/s/1YRXI0WiABUlYaQXQDNfbyA?pwd=1688
提取码:1688
上午:类和对象高级应用(续)
下午:派生和继承
教学内容:
1、友元
类的私有成员只能在类定义的范围内使用,也就是说私有成员只能通过它的成员函数来访问但是,有时候需要在类的外部访问类的私有成员。为此,就需要寻找一种途径,在不放弃私有数据安全性的情况下,使得类外部的函数或类能够访问类中的私有成员,此方法就是友元。
友元可分为:友元函数,友元成员,友元类
友元函数不是当前类的成员函数,而是独立于当前类的外部函数,但它可以访问该类的所有对象的成员,包括私有成员和公有成员。
例如:(友元函数)
友元函数虽然可以访问类对象的私有成员,但它毕竟不是成员函数。因此,在类的外部定义友元函数时,不必像成员函数那样,在函数名前加上“类名::”
友元函数一般带有一个该类的入口参数。因为友元函数不是类的成员,所以它不能直接引用对象成员的名称,也不能通过this指针引用对象的成员,它必须通过作为入口参数传递进来的对象名或对象指针来引用该对象的成员
//***********************************************
class Girl{
private:
char *name;
int age;
public:
Girl(char *n,int d){
name = new char[strlen(n)+1];
strcpy(name,n);
age = d;
}
friend void disp(Girl &x); //声明为友元函数,可以内部定义也可以外部定义
// {
// cout<<"girl\'s name is:"<
// }
~Girl(){
delete name;
}
};
void disp(Girl &x) //定义友元函数,格式不是void Girl:disp(Girl &x),所以是外部函数
{
cout<<"girl\'s name is:"<
}
int main()
{
Girl e("Chen Xingwei",18);
disp(e); //调用友元函数,函数是直接调用,是外部函数标志
return 0;
}
//********************************************
友元函数可以访问多个类的私有成员
例如:
//********************************************
class Boy; //向前引用,必须声明,不声明下面的友元函数出错
class Girl{
private:
char name[25];
int age;
public:
void init(char N[],int A);
friend void prdata(const Girl plg,const Boy plb); //声明函数为girl类的友元函数
};
void Girl::init(char N[],int A)
{
....
}
class Boy{
private:
char name[25];
int age;
public:
void init(char N[],int A);
friend void prdata(const Girl plg,const Boy plb); //声明函数为boy类的友元函数
};
void Boy::init(char N[],int A)
{
....
}
void prdata(const Girl plg,const Boy plb)
//必须在2个类定义之后使用,因为函数中使用了类中成员
{
cout<<"女孩"<
cout<<"男孩"<
}
int main()
{
Girl G1;
Boy B1;
G1.init("Stacy",12);
B1.init("Jim",11);
prdata(G1,B1);
return 0;
}
//*************************************************
例如:(友元成员)
//**************************************************
class Girl; //向前引用
//class Boy;
class Boy{
private:
char *name;
int age;
public:
Boy(char *N,int A){...}
void disp(Girl &); //声明disp()为类boy的成员函数
~Boy(){delete name;}
};
class Girl{
private:
char *name;
int age;
public:
Girl(char *N,int A){...}
friend void Boy::disp(Girl &); //声明类boy的成员函数disp()为类girl的友元函数
~Girl(){delete name;}
};
//*********************************
当一个类被声明为另一个类的友元时,它的所有的成员函数都成为另一个类的友元函数,这就意味着为友元的类中的所有成员函数都可以访问另一个类的私有成员
例如:(友元类)
//*******************************************
class Girl;
class Boy{
private:
char *name;
int age;
public:
Boy(char *n,int d){...}
void disp(Girl &); //声明disp()为类boy的成员函数,为友元类做准备
void test(Girl & g); //声明test()为类的boy成员函数,为友元类做准备
~Boy(){delete name;}
};
class Girl{
private:
char *name;
int age;
friend class Boy; //声明类boy是类girl的友元,即boy可以访问girl的所有成员
public:
Girl(char *n,int d){...}
~Girl(){delete name;}
};
void Boy::disp(Girl &x) //定义函数disp()为类boy的成员函数,也是类girl的友元函数
{
cout<<"boy\'s name is:"<
cout<<"girl\'s name is:"<
}
void Boy::test(Girl & g)
{
cout<<"in boy test "<
}
int main()
{
Boy b("chen hao",25);
Girl g("zhang wei",18);
b.disp(g);
b.test(g);
return 0;
}
//*****************************************
2、运算符重载函数(即规定运算符的作用,以函数来定义)
格式:返回类型 operator 运算符符号 (参数说明)
使用运算符重载函数,能使得复杂函数更简单,有几点要求:
• 返回类型 operator 运算符符号 (参数说明){ //函数体的内部实现 }
• 至少有一个参数是自定义类型(数组,类)
• 如果是单目运算符,只传一个参数
• 如果是双目运算符,传两个参数
•规定了一些运算符不能够自定义重载,例如.、::、.*、.->、?:
一种是作为类的友元函数进行使用,例如:
//***********************************************
class Test{
public:
Test(int a = 0){ this->a = a; }
friend void add(Test& ,Test& );
friend void operator + (Test& ,Test& );//+运算符的重载函数
private:
int a;
};
void add(Test& temp1,Test& temp2)
{
cout<<"in add result="<
}
void operator + (Test& temp1,Test& temp2)
{
cout<<"in operator+ ="<
}
int main()
{
Test a(100);
Test b(50);
add(a,b); //和下面a+b作用一样
a+b; //和上面等效
return 1;
}
//*********************************************
一种则是作为类的成员函数进行使用
//*********************************************
class Internet{
public:
Internet(char *name,char *url) //构造函数
{
this->name = new char[strlen(name)+1];
this->url = new char[strlen(url)+1];
if(name){
strcpy(this->name,name);
}
if(url){
strcpy(this->url,url);
}
}
Internet(Internet &temp) //拷贝构造函数
{
Internet::name = new char[strlen(temp.name)+1];
Internet::url = new char[strlen(temp.url)+1];
if(name){
strcpy(this->name,temp.name);
}
if(url){
strcpy(this->url,temp.url);
}
}
~Internet(){ delete[] name; delete[] url; } //析构函数
Internet & operator = (const Internet &temp) //赋值运算符重载函数,返回对象
{
cout<<"this->name="<
delete[] this->name;
delete[] this->url;
this->name = new char[strlen(temp.name)+1];
this->url = new char[strlen(temp.url)+1];
if(this->name){
strcpy(this->name,temp.name);
}
if(this->url){
strcpy(this->url,temp.url);
}
return *this;
}
public:
char *name;
char *url;
};
int main()
{
Internet a("凌阳教育","www.sunplusedu.com");
Internet b = a; //b对象还不存在,所以调用拷贝构造函数,进行构造处理。
cout<<"b "<
Internet c("大学计划","www.unsp.com");
b = c; //b对象已经存在,所以系统选择赋值运算符重载函数处理。
cout<<"b "<
return 0;
}
//**************************************************
在b=c使用运算符重载函数中,因为b已经存在,在重新的构造的过程中,必须把原先的对象b申请的空间delete掉,然后申请新的空间,在这个过程中,如果没有delete会造成原先的空间没有释放造成内存泄露,不申请新的空间会造成2个对象指向同一个空间,会造成重复delete,从而产生段错误。
3、继承和派生
最高层(基类):是最普遍、最一般的
• 低层(派生类):比它的上一层更具体,并且含有高层的特性(继承),同时也与高层有细微的不同
• 继承性是程序设计中一个非常有用的、有力的特性,它可以让程序员在既有类的基础上,通过增加少量代码或修改少量代码
派生类格式:class 派生类名:派生方式 基类名{//派生类新增的数据成员和成员函数};
派生方式:有public 和 private二种方式
public:以共有性质继承base类,只能继承base类的保护成员(继承后还是保护)和共有成员(继承后还是共有)
private:以私有性质继承base类,只能继承保护成员和共有成员(继承后全部变为私有)
//********************
class 类名{
[private:]
私有成员
protected:
保护成员
public:
公有成员};
//******************
protected成员在类中使用相当于private成员,只有在继承中才有区别;在继承中private成员不能被直接访问,即不能继承;而protected成员可以。
4、派生的构造函数和析构函数
当基类的构造函数没有参数(或全部默认值),或没有显示定义构造函数时,那么派生类可以不向基类传递参数,可以不定义构造函数。
当基类含有带参数的构造函数时,派生类必须定义构造函数,以提供把参数传递给基类构造函数的途径。
一般格式:
派生类构造函数名(参数表0):基类构造函数名(参数表1)
和有类成员类似,例如:
//*********************************************
class Base{
private:
int x;
public:
Base(int i){ //构造函数
x = i;
cout<<"构造base类, x="<
}
~Base(){ //析构函数
cout<<"析构base类, x="<
}
void show(){
cout<<"x="<
}
};
class Derive:public Base{
private:
int y;
Base d;
public:
Derive(int i,int j,int k):Base(i),d(j) //Base(i)传递构造函数参数,d(j)类成员
{
y = k;
cout<<"构造derived类, y="<
}
~Derive(){
cout<<"析构derived类, y="<
}
};
int main()
{
Derive obj(1,2,3);
obj.show();
return 0;
}
//**********************************************