目录
一、继承访问权限测试
第一步:设计类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! } };
从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 };若只想给类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; };
运行结果:
这次我们得到了期望的结果,基类中被重写的成员函数被设置为虚函数,指针指向对象所属类的虚表,在程序运行时,将根据指针指向对象的类型来确定想要调用的函数,从而在调用虚函数时,就能够找到正确的函数。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)