[C++实验2 ]继承和多态

实验内容:

一、继承访问权限测试

设计类A具有public, protected, private等不同属性的成员函数或变量;
类B通过public, protected, private等不同方式继承A,在类B的成员函数中测试访问A的成员函数或变量;
在类B中添加public, protected, private等不同属性的成员函数或变量,在外部测试访问B的各个成员函数或变量;
B以private方式继承A,尝试把A中的部分public成员提升为public。

二、友元类继承测试

设计类A含有私有变量a,在类A中友元给类C;
设计类B继承A,添加私有变量b;在类C中测试访问类B的成员变量a, b;
设计类D继承C,在D的成员函数中测试访问类A的成员变量a,类B的成员变量a, b。

三、多态性综合运用

一般多态性函数:输入输出参数完全一样,在父类中添加virtual;
特殊多态性函数:输入或输出参数在子类中是父类的指针或基类的引用,在子类中对于的是子类的指针或子类的引用;
析构函数的多态性;
多继承,注意什么情况需要虚继承;
设计矢量图,运用多继承设计组合图形,要求具备创建不同类型矢量图、选择图形、移动图形、用不同颜色显示图形(表示选中与否),用vector或数组管理图形。

函数实现:

一、继承访问权限测试

设计类A具有public, protected, private等不同属性的成员函数或变量;
类B通过public, protected, private等不同方式继承A,在类B的成员函数中测试访问A的成员函数或变量;

1.cpp:

#include<iostream>
using namespace std;
 
class A		//基类
{
public:			//基类公有成员
	void A_1()
	{
		cout << "执行A_1函数" << endl;
	}
protected:		//基类保护成员
	void A_2()
	{
		cout << "执行A_2函数" << endl;
	}
private:		//基类私有成员
	int m_A;
};
class B :public A			//定义B类,继承A类,public继承方式
{
public:					//派生类公有成员
	void B_1()
	{
		A_2();		//在派生类中可以访问基类的保护成员
		cout << "执行B_1函数" << endl;
	}
protected:				//派生类保护成员
	void B_2()
	{
		cout << "执行A_2函数" << endl;
	}
private:                //派生类私有成员
	int m_B;
};
 
 int  main()//主函数
{
    B a;//创建一个派生类对象a
    a.A_1();//在派生类中调用基类的公有成员
    a.B_1();//在派生类中调用派生类的公有成员
    A base;//创建一个基类对象base
    base.A_1();//在基类中调用基类的公有成员
}

代码运行截图:

可以看到,类B以public方式继承了基类A,那么类A的所有成员依然保持原有权限,同时在派生类中的访问权限也保持不变,所以类B的对象可以在类体外访问类A的公有成员(a.A_1());,同时类A的对象也可以在类体外访问自己的公有成员(base.A_1())。


2.cpp

#include<iostream>
using namespace std;
 
class A		//基类
{
public:			//基类公有成员
	void A_1()
	{
		cout << "执行A_1函数" << endl;
	}
protected:		//基类保护成员
	void A_2()
	{
		cout << "执行A_2函数" << endl;
	}
private:		//基类私有成员
	int m_BASE;
};
class B :private A	//定义B类,继承A类,private继承方式
{
public:					//派生类公有成员
	void B_1()
	{
		A_1();		//在派生类中可以访问基类的公有成员
		A_2();		//在派生类中可以访问基类的访问成员
		cout << "执行B_1函数" << endl;
	}
protected:				//派生类保护成员
	void B_2()
	{
		cout << "执行B_2函数" << endl;
	}
private:                		//派生类私有成员
	int m_B;
};
 
int main()//主函数
{
	B b;//创建一个派生类对象b
	b.B_1();//在派生类中调用派生类的公有成员
	A base;//创建一个基类对象base
	base.A_1();//在基类中调用基类的公有成员
}

运行截图:

   可与看到,类B以private方式继承了基类A,那么类A的所有成员在派生类中的访问权限都将变成私有权限,所以类B的对象不可以在类体外访问类A的公有成员,只能在类体外方位类B自己的公有对象(b.B_1())。

3.cpp

#include<iostream>
using namespace std;
 
class A		//基类
{
public:			//基类公有成员
	void A_1()
	{
		cout << "执行A_1函数" << endl;
	}
protected:		//基类保护成员
	void A_2()
	{
		cout << "执行A_2函数" << endl;
	}
private:		//基类私有成员
	int m_BASE;
};
class B :protected A	//定义B类,继承A类,protected继承方式
{
public:					//派生类公有成员
	void B_1()
	{
		A_1();		//在派生类中可以访问基类的公有成员
		A_2();		//在派生类中可以访问基类的访问成员
		cout << "执行B_1函数" << endl;
	}
protected:				//派生类保护成员
	void B_2()
	{
		cout << "执行B_2函数" << endl;
	}
private:                		//派生类私有成员
	int m_C;
};
 
int main()//主函数
{
	B c;//创建一个派生类对象c
	c.B_1();//在派生类中调用派生类的公有成员
	A base;//创建一个基类对象base
	base.A_1();//在基类中调用基类的公有成员
}

代码运行截图:

   从结果上看,protected继承方式和private方式是相同的,不过和private继承方式不同的一点是,当采用protected继承方式时,在派生类中,基类的公有成员和保护成员的使 用权限将是protected,不再是private,也就是说,当再有一个类D继承C类时,D类可以继续在类内调用C类的公有成员和保护成员,但是在private继承方式下,这将是错误的。

4.cpp
 

#include<iostream>
using namespace std;

 
class A		//A类
{
public:			//A类公有成员
	void A_1()
	{
		cout << "执行A_1函数" << endl;
	}
protected:		//A类保护成员
	void A_2()
	{
		cout << "执行A_2函数" << endl;
	}
private:		//A类私有成员
	int m_BASE;
};
class B 	//定义B类
{
public:					
                		//私有成员
	int m_C;
};
 
int main()//主函数
{
	B b;//创建一个B类对象b
	A a;//创建一个A类对象a 
	a.A_1();//在外部调用A类的公有成员
   
}

代码运行截图:

从代码运行结果看,可以从外部访问A类的共有成员

5.cpp

 

#include<iostream>
using namespace std;

 
class A		//A类
{
public:			//A类公有成员
	void A_1()
	{
		cout << "执行A_1函数" << endl;
	}
protected:		//A类保护成员
	void A_2()
	{
		cout << "执行A_2函数" << endl;
	}
private:		//A类私有成员
	int m_BASE;
};
class B 	//定义B类
{
public:					
                		//私有成员
	int m_C;
};
 
int main()//主函数
{
	B b;//创建一个B类对象b
	A a;//创建一个A类对象a 
	a.A_2();//在外部调用A类的保护成员
    a.m_BASE=1//在外部调用A类的私有成员
   cout << a.m_BASE<< endl;
}

代码无码运行,原因:无法从外部调用A类的保护乘员和私有成员

6.cpp

  • 下面的B私有B私有继承于A,所以getNum在B中是private的,我们不能在外界调用
  • 我们在B中使用using将A的getNum声明在public下,此时B的对象就可以在外界调用getNum了
#include<iostream>
using namespace std;

class A {
public:
    std::size_t getNum() { return n; };
protected:
    std::size_t n=1;
};
 
class B :private A{
public:
    using A::getNum;
protected:
    using A::n;
};
 
int main()
{
    B b;
    b.getNum(); //正确:在B中已经声明A的getNum为public了
    cout<<b.getNum()<<endl;
    return 0;
}

代码运行截图:

 

二、友元类继承测试

1.cpp

设计类A含有私有变量a,在类A中友元给类C

#include <iostream>
using namespace std;


 
class A
{
private:
	int a ;
	friend class C;
};

2.cpp

设计类B继承A,添加私有变量b


class B : public A
{
private:
	int b ;
};

3.cpp

测试访问类B的成员变量a,b


class C
{
public:
	void Test()
	{
		B b;
		cout << b._a << endl;
		
		return;
	}
};

4.cpp

设计类D继承C
测试访问类A的成员变量a,类B的成员变量a, b


class D : public C
{
public:
	void Test()
	{
		A a;
		//cout << a.a << endl;	成员"A::a"不可访问
		B b;
		//cout << b.a << endl;	成员"A::a"不可访问
		//cout << b.b << endl;	成员"B::b"不可访问
	}
};

友元类是单向的,不可继承,不可传递,如果基类被授予友元关系,则只有基类具有特殊访问权限,该基类的派生类不能访问授予友元关系的类.

三、多态性综合运用

虚函数:

虚函数的定义是在基类中进行的,它是在基类中需要定义为虚函数的成员函数的声明中冠以关键字virtual,从而提供一种接口界面。定义虚函数的方法如下:

virtual 返回类型 函数名(形参表)
{
   函数体
}

在基类中的某个成员函数被声明为虚函数后,此虚函数就可以在一个或多个派生类中被重新定义。虚函数在派生类中重新定义是,其函数原型,包括返回类型,函数名,参数个数,参数类型的顺序,都必须与基类中的原型完全相同。

#include<iostream>
#include<string>
using namespace std;
class Student
{
public:
    Student(string name="科目"):subjects(name){}
    string getname()
    {
        return subjects;
    }
    virtual void like()
    {
        cout<<"每个人都有喜欢的"<<getname()<<endl;
    }
private:
    string subjects;
};
class Xiaoming:public Student
{
public:
    Xiaoming(string name="英语"):Student(name){}
    void like()
    {
        cout<<"小明喜欢"<<getname()<<endl;
    }
};
class Xiaoliang:public Xiaoming
{
public:
    Xiaoliang(string name="数学"):Xiaoming(name){}
    void like()
    {
        cout<<"小亮喜欢"<<getname()<<endl;
    }
};
class Xiaohui:public Xiaoliang
{
public:
    Xiaohui(string name="语文"):Xiaoliang(name){}
    void like()
    {
        cout<<"小辉喜欢"<<getname()<<endl;
    }
};

int main()
{
    Student *ptr;
    Student st;
    Xiaoming xm;
    Xiaoliang xl;
    Xiaohui xh;
    ptr=&st;
    ptr->like();
    ptr=&xm;
    ptr->like();
    ptr=&xl;
    ptr->like();
    ptr=&xh;
    ptr->like();
    return 0;
}

代码截图:

析构函数的多态性:

 当用delete运算符撤销无名对象时,系统只执行基类的析构函数,而不执行派生类的析构函数。
原因是当撤销指针p所指的派生类的无名对象,而调用析构函数时,采用了静态连编方式,只调用了基类Base的析构函数。如果希望程序执行动态连编方式,在用delete运算符撤销派生类的无名对象时,先调用派生类的析构函数,再调用基类的析构函数,可以将基类的析构函数声明为虚析构函数,由该基类所派生的所有派生类的析构函数也都自动成为虚函数。

#include<iostream>
#include<string>
using namespace std;
class Base
{
public:
    virtual ~Base()
    {
        cout<<"调用基类Base的析构函数"<<endl;
    };
};

class Derived:public Base
{
public:
    ~Derived()
    {
        cout<<"调用派生类Derived的析构函数"<<endl;
    };
};

int main()
{
    Base *p;
    p=new Derived;

    delete p;
    return 0;
}

多继承与虚函数

多继承可以视为多个单继承的组合。因此,多继承情况下的虚函数调用与单继承情况下的虚函数调用有相似之处。

 

#include<iostream>
using namespace std;
class A1
{
public:
    virtual void fun()
    {
        cout<<"-----A1-----"<<endl;
    }
};
class A2
{
public:

    void fun()
    {
        cout<<"-----A2-----"<<endl;
    }
};
class B:public A1, public A2
{
public:
    void fun()
    {
        cout<<"------B-----"<<endl;
    }
};
int main()
{
    A1 obj1,*ptr1;
    A2 obj2,*ptr2;
    B obj3;
    ptr1=&obj1;
    ptr1->fun();
    ptr1=&obj3;
    ptr1->fun();
    ptr2=&obj2;
    ptr2->fun();
    ptr2=&obj3;
    ptr2->fun();
    return 0;
}

 

从程序运行结果可以看出,由于派生类B中的函数fun()有不同的继承路径,所以呈不同的性质。相对于类A1的派生路径,由于类A1中的fun()是虚函数,当声明为指向类A1的指针指向派生类B的对象obj3时,函数fun()呈现出虚特性。因此,此时的"ptr->fun();"调用的是B::fun()函数,相对于A2的派生路径,由于类A2中的fun()是一般成员的函数,所以此时它只能是一个普通的重载函数。当声明为指向类A2的指针指向类B的对象obj3时,函数fun()只呈现普通函数的重载特性。因此,此时的"ptr->fun();"调用的是A2::fun()函数。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值