目录
一、继承访问权限测试
第一步:设计类A
第二步:设计类B、类C、类D(继承于类A)
类B通过public的方式继承类A:
类C通过protected的方式继承类A:
类D通过private的方式继承类A:
把原本A中的部分public成员重新提升为public:
二、友元类继承测试
设计类A含有私有变量a_pri_pro,在类A中友元给类B:
若只想给类TestA中“某个函数”基类A中的私有变量a_pri_pro的访问权限:
利用友元可以赋予某个类或某个函数访问基类的私有变量的权限,有三种模式:
测试友元类是否能访问继承类的私有变量:
测试友元类TestA的继承类Pro_TestA是否能访问基类A以及基类的继承类B的私有变量:
三、多态性综合运用
一、继承访问权限测试
第一步:设计类A
设计类A具有public, protected, private等不同属性的成员函数或变量
外部只能访问A类的public成员,如下图:
第二步:设计类B、类C、类D(继承于类A)
类B通过public的方式继承类A:
class B :public A
{
void setPuPro(string a_pro_pro = "")
{
a_pu_pro = "";//ok!
a_pro_pro = a_pro_pro;//ok!
//a_pri_pro = 0;//no!
}
};
class B :public A
{
void setPuPro(string a_pro_pro = "")
{
a_pu_pro = "";//ok!
a_pro_pro = a_pro_pro;//ok!
//a_pri_pro = 0;//no!
}
};
从A类继承的成员变量或函数权限不变,类B不能访问A的private成员函数或变量,只能访问proteced以上的成员函数或变量,如下图:
在外部同样只能访问A类的public成员:
类C通过protected的方式继承类A:
class C :protected A
{
public:
void SetProPro(string a_pro_pro = "")
{
a_pu_pro = "";//ok!
a_pro_pro = a_pro_pro;//ok!
//a_pri_pro = 0;//no!
}
};
从A类继承的成员变量或函数父类中public权限降级为protected,类C不能访问A的private成员函数或变量,只能访问proteced以上的成员函数或变量
在外部不能访问A类的public及以下成员:
类D通过private的方式继承类A:
class D :private A
{
public:
void SetProPro(string pro_pro = "")
{
a_pu_pro = "";//ok!
a_pro_pro = pro_pro;//ok!
//a_pri_pro = 0;//no!
}
};
从A类继承的成员变量或函数父类中所有权限降级为private,类D不能访问A的private成员函数或变量,只能访问proteced以上的成员函数或变量
在外部同样不能访问A类的public及以下成员:
把原本A中的部分public成员重新提升为public:
方法一:在外部用get函数的方式访问protected及以下成员
class D :private A
{
public:
void SetProPro(string pro_pro = "")
{
a_pu_pro = "";//ok!
a_pro_pro = pro_pro;//ok!
//a_pri_pro = 0;//no!
}
string & GetPuPro()//这个函数保证了在外部可以访问A类的public成员
{
return a_pu_pro;
}
};
方法二:用using的方式访问protected及以下成员
class D :private A
{
public:
using A::a_pu_pro;
using A::a_pro_pro;//用using的方式访问protected及以下成员
void SetProPro(string pro_pro = "")
{
a_pu_pro = "";//ok!
a_pro_pro = pro_pro;//ok!
//a_pri_pro = 0;//no!
}
string & GetPuPro()//这个函数保证了在外部可以访问A类的public成员
{
return a_pu_pro;
}
};
main.cpp里的TestA()函数
void TestA()
{
A aObj;
aObj.a_pu_pro = "A PuPro is ok!";
//aObj.a_pro_pro = "A ProPro isn't ok!";//外部只能访问A的public成员
B bObj;
string proPro = bObj.GetProPro();//在外部用get函数的方式访问protected成员
bObj.a_pu_pro = "B PuPro is ok!";
//bObj.a_pro_pro = "B ProPro isn't ok!";//从A类以public继承下来可以访问public成员
C cObj;
//cObj.a_pu_pro = "C PuPro isn't ok!";//从A类以protected继承下来不可以访问public成员
cObj.SetProPro("");
//A aCObj = cObj; //按理论基类可以转为派生类,而派生类不能转为基类
D dObj;
//dObj.a_pu_pro = "D PuPro isn't ok!";//从A类以private继承下来不可以访问public成员
dObj.SetProPro("");
dObj.GetPuPro();
dObj.a_pu_pro = "";
dObj.a_pro_pro = "";
}
二、友元类继承测试
设计类A含有私有变量a_pri_pro,在类A中友元给类B:
class A {
public:
A();
string a_pu_pro;
void SetProPro(string pro_pro)
{
a_pro_pro = pro_pro;
}
protected:
string a_pro_pro;
private:
int a_pri_pro;
friend class B;//友元函数使得继承于classA的B可以访问A的私有变量a_pri_pro
};
class A {
public:
A();
string a_pu_pro;
void SetProPro(string pro_pro)
{
a_pro_pro = pro_pro;
}
protected:
string a_pro_pro;
private:
int a_pri_pro;
friend class B;//友元函数使得继承于classA的B可以访问A的私有变量a_pri_pro
};
若只想给类TestA中“某个函数”基类A中的私有变量a_pri_pro的访问权限:
class A;
class TestA {
public:
void TestFriend(A &a);//可以访问私有变量
void TestFriendA(A& a);//不能访问私有变量
};
class A {
public:
A();
string a_pu_pro;
void SetProPro(string pro_pro)
{
a_pro_pro = pro_pro;
}
protected:
string a_pro_pro;
private:
int a_pri_pro;
friend class B;//友元函数使得继承于classA的B可以访问A的私有变量a_pri_pro
//利用友元函数允许函数TestFriend(A& a)访问A的私有变量a_pri_pro
friend void TestA::TestFriend(A &a);
};
利用友元可以赋予某个类或某个函数访问基类的私有变量的权限,有三种模式:
private:
int a_pri_pro;
//友元使得继承于classA的B可以访问A的私有变量a_pri_pro
friend class B;//友元类
friend void TestFriendFun(A& a)//全集函数
{
a.a_pri_pro = 5;
}
//利用友元函数允许函数TestFriend(A& a)访问A的私有变量a_pri_pro
friend void TestA::TestFriend(A &a);//友元函数
类B是基类A的友元类,但B的继承类LittleB不是A的友元类,所以不能访问A的私有变量,类似于朋友的儿子不是我的朋友:
测试友元类是否能访问继承类的私有变量:
class A;
class B;
class TestA {
public:
void TestFriend(A &a);
//void TestFriendA(A& a);
void TestFriend(B& a);
};
class A {
public:
A();
string a_pu_pro;
void SetProPro(string pro_pro)
{
a_pro_pro = pro_pro;
}
protected:
string a_pro_pro;
private:
int a_pri_pro;
friend void TestFriendFun(A& a)//全集函数
{
a.a_pri_pro = 5;
}
//利用友元函数允许函数TestFriend(A& a)访问A的私有变量a_pri_pro
//friend void TestA::TestFriend(A &a);//友元函数
//友元使得继承于classA的B可以访问A的私有变量a_pri_pro
friend class B;//友元类
friend class TestA;//友元类可以访问基类继承类B继承于A的私有变量a_pri_pro
};
class B : public A
{
public:
void SetProPro(string pro_pro = "")
{
a_pu_pro = "";//ok!
a_pro_pro = pro_pro;//ok!
//a_pri_pro = 0;//no!
a_pri_pro = 0;//now ok!利用友元函数访问基类的私有变量
}
string GetProPro()
{
return a_pro_pro;
}
int GetPriPro()
{
return 0;
a_pri_pro = 10;
}
private:
int b_pri_pro;
};
class LettleB : public B
{
public:
//int GetPriPro()
//{
// a_pri_pro = 10;
//}
};
友元类可以访问基类继承类B继承于A的私有变量a_pri_pro:
但不能访问基类继承类B新定义的私有变量b_pri_pro:
类似于他是我的朋友不是我儿子的朋友,所以不能访问儿子独有的隐私
测试友元类TestA的继承类Pro_TestA是否能访问基类A以及基类的继承类B的私有变量:
class Pro_TestA {
public:
void TestFriend(A& a);
void TestFriend(B& a);
};
都没有权限访问,原因类似于朋友的儿子不是我和我儿子的朋友 。
三、多态性综合运用
梳理:
多态性的便利:比如有十只猫,十只狗,十只鸡,我想要他们动起来,原本是需要分别对猫狗鸡进行for遍历,但如果利用了多态的性质,只需要制作一个动物列表,把猫狗鸡放入动物列表,再对动物类进行for循环,后续如果有新的动物需要同样操作,只需将其加入动物列表。
#ifndef CANIMAL_H #define CANIMAL_H #includeusing namespace std; class CAnimal { public: CAnimal(int nLegs); CAnimal(); ~CAnimal(); void Move(); protected: int m_nLeg; }; class CCat : public CAnimal { public: CCat(); CCat(int nLegs); ~CCat(); void Move(); }; class CEagle : public CAnimal { public: CEagle(); CEagle(int nLegs); ~CEagle(); void Move(); }; class COwl : public CCat,public CEagle { public: COwl(); COwl(int nLegs); ~COwl(); ~COwl(); void Move(); }; #endif // !CANIMAL_H
遇到的问题:不存在默认构造函数
解决:类里面需要有无参构造器,添加一个无参构造器即可。
多态性可以简单的概括为“1个接口,多种方法”,在程序运行的过程中才决定调用的机制
程序实现上是这样,通过父类指针调用子类的函数,可以让父类指针有多种形态。
为了实现通过父类指针调用子类的函数,我们需要在基类中声明函数时使用virtual关键字,这样的函数我们称为虚函数。一旦某个函数在基类中声明为virtual,那么在所有的派生类中该函数都是virtual,而不需要再显式地声明为virtual,下面来看一下有无virtual声明的效果对比:
CAnimal.h
class CAnimal
{
public:
CAnimal(int nLegs);
CAnimal();
~CAnimal();
void Move();
void Sleep();
void Breathe();
protected:
int m_nLeg;
};
class CFish :public CAnimal
{
public:
CFish();
void Breathe();
};
CAnimal.cpp
void CAnimal::Sleep()
{
cout << "animal sleep" << endl;
}
void CAnimal::Breathe()
{
cout << "animal breathe" << endl;
}
void CFish::Breathe()
{
cout << "fish bubble" << endl;
}
mian.cpp
int main()
{
CFish fh;
CAnimal* pAn = &fh;
pAn->Breathe();
return 0;
}
输出结果:
我们可以发现输出的结果还是沿用了基类的Breathe函数,从指针角度来看,函数调用的地址是固定的,因而始终调用一个函数;从内存模型的角度来看,这是因为我们在构造CFish类的对象时是先去调用CAnimal类的构造函数,再去调用CFish类的构造函数,再将两者拼成该对象,对于CAnimal中已存在的部分默认保存不做更改,所以当我们利用类型转换后的对象指针去调用它的方法时,输出的时animal breathe。
所以我们在基类CAnimal里对Breathe函数进行virtual声明:
class CAnimal
{
public:
CAnimal(int nLegs);
CAnimal();
~CAnimal();
void Move();
void Sleep();
virtual void Breathe();
protected:
int m_nLeg;
};
运行结果:
这次我们得到了期望的结果,基类中被重写的成员函数被设置为虚函数,指针指向对象所属类的虚表,在程序运行时,将根据指针指向对象的类型来确定想要调用的函数,从而在调用虚函数时,就能够找到正确的函数。



