ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

C++实验二——继承与多态

2021-11-10 23:03:11  阅读:109  来源: 互联网

标签:继承 成员 基类 多态 C++ class 访问 派生类 public


一、继承访问权限测试

源代码:

#include <iostream>
using namespace std;

class A_animal{
	public:
		void eat(){
			cout << "need eat" << endl;
		}
	protected:
		void sleep(){
			cout << "need sleep" << endl;
		}
	private:
		void stand(){
			cout << "can stand up" << endl;
		}
};

//这里子类B_dog可以通过公有继承、保护继承、私有继承来继承父类A_animal
class pub_B_dog : public A_animal{
	public:
		void pub_test(){
			eat();//可以访问
			sleep();//只有在派生类中利用派生类对象访问基类中protected对象
			//stand();//不能访问
		}
		void pub_bark(){
			cout << "wangwang(pub)" << endl;
		}
	protected:
		void pub_tail(){
			cout << "short tail(pub)" << endl;
		}
	private:
		void pub_hair(){
			cout << "yellow(pub)" << endl;
		}
};
class pro_B_dog : protected A_animal{
	public:
		void pro_test(){
			eat();//可以访问
			sleep();//只有在派生类中利用派生类对象访问基类中protected对象
			//stand();//不能访问
		}
		void pro_bark(){
			cout << "wangwang(pro)" << endl;
		}
	protected:
		void pro_tail(){
			cout << "short tail(pro)" << endl;
		}
	private:
		void pro_hair(){
			cout << "yellow(pro)" << endl;
		}
};
class pri_B_dog : private A_animal{
	public:
		void pri_test(){
			eat();//可以访问
			sleep();//只有在派生类中利用派生类对象访问基类中protected对象
			//stand();//不能访问
		}
		void pri_bark(){
			cout << "wangwang(pri)" << endl;
		}
	protected:
		void pri_tail(){
			cout << "short tail(pri)" << endl;
		}
	private:
		void pri_hair(){
			cout << "yellow(pri)" << endl;
		}
};
int main()
{
	pub_B_dog A;

	A.pub_bark();//派生类能访问基类中public成员
	A.eat();
	//A.sleep();//派生类不能访问基类中protected成员
	//A.stand();//派生类不能访问基类中private成员
	//A.pub_tail();
	//A.pub_hair();
	
	pro_B_dog B;
	B.pro_bark();
	//B.eat();
	//B.sleep();
	//B.stand();
	//B.pro_tail();
	//B.pro_hair();
	
	pri_B_dog C;
	C.pri_bark();
	//C.eat();
	//C.sleep();
	//C.stand();
	//C.pri_tail();
	//C.pri_hair();
	return 0;
}

1.public、protected、private三种继承的派生类可以访问基类中的public、protected 成员;

2.基类中的private 成员不可以在派生类中被直接访问;

3.派生类对象仅当 public 派生时,对基类中的 public 成员有可访问/可修改的权限,其他都为不可访问/不可修改。

4.继承方式会改变从基类继承的成员在派生类的访问权限:

     (1).public 继承不改变基类成员的访问权限

     (2).protected 继承将基类中 public 成员变为子类的 protected 成员,其它成员的访问权限不变

     (3).private 继承使得基类所有成员在子类中的访问权限变为 private

5.B以private方式继承A,用{using A::_a; }把A中的部分public成员提升为public

6.如果想让这些继承而来的数据成员作为public或者protected成员,可以用using重新声明。using声明语句中名字的访问权限由该using声明语句之前的访问说明符决定。

二、友元类继承测试

源代码:

#include<istream>
using namespace std;
class A {
private:
	int a;
	friend class C;//友元类给类C; 
};
class B: public A {
private:
	int b;
};
class C {
public:
	void Test() {
		B b1;
		b1.a;
		//b1._b;不可访问 ;
	}
};
class D :public C {
public:
	void Test() {
		A a1;
		//a1.a;//不可访问; 
		B b2;
		//b2.a;//不可访问 ; 
		//b2.b;//不可访问 ; 
	}
};

1.友元关系不能继承。基类的友元对派生类的成员没有特殊访问权限。

2.如果基类被授予友元关系,则只有基类具有特殊访问权限,该基类的派生类不能访问授予友元关系的类。当类Y被说明为类X的友元时,类Y的所有成员函数都成为类X的友元函数,这就意味着作为友元类Y中的所有成员函数都可以访问类X中的所有成员(包括私有成员)。

3.友元关系是单向的,不具有交换性。友元关系也不具有传递性。友元关系不能被继承,基类的友元类未必是子类的友元,某类型的友元的子类未必是该类型的友元。

三、多态性的综合应用

1.一般多态性:

新建CAnimal类,Move()是其内部虚函数,新建CCat类、CEagle类、COwl类继承CAnimal类,并重写其内部的虚函数Move()的实现方法以实现多态的效果。

#include <iostream>
using namespace std;

class CAnimal
{
public:
    //无参构造函数
    CAnimal() {
        m_nLegs = 2;
    }
    CAnimal(int nLeg) {
        m_nLegs = nLeg;
    }
    //虚函数
    virtual void Move() {
        cout << "I can crawl or fly!" << endl;
    }
protected:
    int m_nLegs;
};
class CCat : virtual  public CAnimal
{
public:
    //无参构造函数
    CCat() {
        m_nLegs = 4;
    }
    CCat(int nLegs) {
        m_nLegs = nLegs;
    }
    virtual void Move() {
        cout << "I am a cat,I can crawl!" << endl;
    }
};
class CEagle : virtual public CAnimal
{
public:
    //无参构造函数
    CEagle() {
        m_nLegs = 2;
    }
    CEagle(int nLegs) {
        m_nLegs = nLegs;
    }
    virtual void Move() {
        cout << "I am an eagle,I can fly!" << endl;
    }
};
class COwl : public CCat, public CEagle
{
public:
    //无参构造函数
    COwl() {
        m_nLegs = 2;
    }
    COwl(int nLegs) {
        m_nLegs = nLegs;
    }
    virtual void Move() {
        cout << "I am an owl,I can also fly!" << endl;
    }
};

void TestAnimal()
{
    CAnimal* pAnimal[4];
    pAnimal[0] = new  CAnimal(2);
    pAnimal[1] = new CCat(4);
    pAnimal[2] = new CEagle(2);
    pAnimal[3] = new COwl(2);
    for (int i = 0; i < 4; i++)
    {
        pAnimal[i]->Move();
    }
}

int main() {
    TestAnimal();
    return 0;
}

 2.特殊多态性

输入或输出参数在子类中是父类的指针或基类的引用,在子类中对于的是子类的指针或子类的引用

此处的特殊多态性含义为函数的参数是父类的指针(引用)或者子类的指针(引用)(即在运行过程中实现虚函数的绑定(运行时多态))。

#include <iostream>
using namespace std;

class CAnimal
{
public:
    //无参构造函数
    CAnimal() {
        m_nLegs = 2;
    }
    CAnimal(int nLeg) {
        m_nLegs = nLeg;
    }
    //虚函数
    virtual void Move() {
        cout << "I can crawl or fly!" << endl;
    }
protected:
    int m_nLegs;
};
class CCat : virtual  public CAnimal
{
public:
    //无参构造函数
    CCat() {
        m_nLegs = 4;
    }
    CCat(int nLegs) {
        m_nLegs = nLegs;
    }
    virtual void Move() {
        cout << "I am a cat,I can crawl!" << endl;
    }
};
class CEagle : virtual public CAnimal
{
public:
    //无参构造函数
    CEagle() {
        m_nLegs = 2;
    }
    CEagle(int nLegs) {
        m_nLegs = nLegs;
    }
    virtual void Move() {
        cout << "I am an eagle,I can fly!" << endl;
    }
};
class COwl : public CCat, public CEagle
{
public:
    //无参构造函数
    COwl() {
        m_nLegs = 2;
    }
    COwl(int nLegs) {
        m_nLegs = nLegs;
    }
    virtual void Move() {
        cout << "I am an owl,I can also fly!" << endl;
    }
};

void callMove(CAnimal* pAn) {
    pAn->Move();
}

void TestAnimal()
{
    CAnimal animal;
    CEagle eagle;
    COwl owl;
    CCat cat;
    callMove(&animal);
    callMove(&eagle);
    callMove(&owl);
    callMove(&cat);
}

int main() {
    TestAnimal();
    return 0;
}

 3.析构多态性

在应用C++的多态性时,当指向基类的指针被释放时,派生类的析构函数其实没有被调用,导致在派生类中申请的空间没有被释放,导致内存泄漏。

#include <iostream>
using namespace std;
 
class Base {
public:
    Base() {cout << "Base constructor... \n";}
    ~Base() {cout << "Base destructor... \n";}
    virtual void fun() const {cout << "Base functoin...\n";}
};
 
class Derived :public Base {
public:
    Derived() {
        p = new int(0);
        cout << "Derived Constructor...\n";
    }
    ~Derived() {
        cout << "Derived destructor...\n";
        delete p;
    }
    void fun() const {cout << "Derived function...\n";}
private:
    int *p;
};
 
int main() {
    Base* pd = new Derived;
    pd->fun();
    delete pd;
    return 0;
}

运行结果:

 

上面运行结果显示,派生类的析构函数没有调用,派生类的构造函数申请的空间泄露了,所以可将代码改成以下代码:

class Base {
public:
    Base() {cout << "Base constructor... \n";}
    virtual ~Base() {cout << "Mammal destructor... \n";}
    virtual void fun() const {cout << "Base functoin...\n";}
};

 运行结果:

 通过将基类的析构函数声明为虚析构函数,成功的通过基类指针调用了派生类的析构函数,完成了内存的释放。

4.多继承

多继承概念:如果一个派生类从多个基类继承,则成为多继承。

多继承的声明:

class派生类名:访问控制 基类名1,访问控制 基类名2,....{

        成员列表

}

需要注意以下几个点:

1.多个基类的派生类的构造函数执行的顺序与单继承的情况类似,执行顺序取决于定义派生类时指定的继承基类的顺序。
2.一个派生类对象拥有多个基类的成员。 不同名成员访问不会出现二义性; 如果不同的基类拥有同名成员, 派生类对象访问时应该加以识别。
3.如果派生类声明了一个和基类成员同名的新成员, 派生的新成员就覆盖了基类同名成员, 直接使用成员名只能访问到派生类的成员。

class A
{
public:
    int a;
};
class B : public A
{
public:
    int b;
};
class C : public A
{
public:
    int c;
};
class D :public B, public C
{
public:
    int d;

    void fun() 
    {
        d = a;
    }
};

标签:继承,成员,基类,多态,C++,class,访问,派生类,public
来源: https://blog.csdn.net/lasd12415/article/details/121141618

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有