C++(二)

C++(二),第1张

C++(二)

目录

一、继承访问权限测试

第一步:设计类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
#include 
using 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;
};

运行结果:

这次我们得到了期望的结果,基类中被重写的成员函数被设置为虚函数,指针指向对象所属类的虚表,在程序运行时,将根据指针指向对象的类型来确定想要调用的函数,从而在调用虚函数时,就能够找到正确的函数。 

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5116413.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-17
下一篇 2022-11-17

发表评论

登录后才能评论

评论列表(0条)

保存