C/C++教程

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

本文主要是介绍C++实验二——继承与多态,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

一、继承访问权限测试

源代码:

#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++实验二——继承与多态的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!