目录
继承的研究实验
三类继承方式中子类继承父类后的属性转换
基础理论
代码实现
结果截图
结论
实现额外内容
多继承
多继承的格式
继承与多继承同名问题
虚继承处理
菱形继承问题
代码简单研讨
有趣的细节问题
友元函数的继承中问题
关于“爸爸 的朋友”可以访问“儿子”那些内容与“爸爸的朋友的儿子”可以访问的内容研究
代码设计
测试结果
结论
多态的研究与实现、
一般多态
结果
地址调用的特殊多态
代码设计
结果展示
关于虚析构函数与纯虚析构函数
测试代码设计
此代码运行结果为
原因
解决方法
简单表述纯虚析构函数
总结
特别强调,本文章全说作者个人实验结论与自己推测结果,如有不正确欢迎在评论区或者私信讨论
继承的研究实验
三类继承方式中子类继承父类后的属性转换
基础理论
基础理论
继承方式有三种 公共继承,保护继承,私有继承。
父类也叫基类,子类也叫派生类。
格式为class 子类:继承方式 父类
代码实现
#include
class baba//爸爸类即父类
{
public:
int a;//公共变量都能访问
protected:
int b;//保护变量派生类(即子类)可访问
private:
int c;//私有变量(子类也不可以访问)
};
class daer :public baba//大儿子,使用公共继承爸爸
{
public:
void dia() {
a = 100;
b = 100;
c = 100;
}
};
class erer :protected baba//二儿子,使用保护继承爸爸
{
public:
void dia() {
a = 100;
b = 100;
c = 100;
}
};
class saner :private baba//三儿子,使用私密继承爸爸
{
void dia() {
a = 100;
b = 100;
c = 100;
}
};
//三类继承都不能访问爸爸的私密变量c说明父类的私密变量子类也不能访问
class ce//调动大儿子以测试大儿子的变量情况
{
void dadia() {
daer da;
da.a = 100;
da.b = 100;
da.c = 100;
}
};
//大儿子的a可以访问,但b,c不行,因为父类的b,c是保护和私有属性,
//可知道公共继承时保护属性继承还是保护,私有继承还是私有
class ceo//调用二儿子变量
{
void erdia() {
erer da;
da.a = 100;
da.b = 100;
da.c = 100;
}
};
//可见三个都不能访问,可见保护继承公共变量也变成了保护变量
class dasun :public daer//大孙子,继承大儿子
{
void dia() {
a = 100;
b = 100;
c = 100;
}
};//发现可访问a,b,可见在孙子
class ersun :public erer//二孙子,继承二儿子
{
void dia() {
a = 100;
b = 100;
c = 100;
}
};//c不可访问,可见孙子也不能访问爷爷私有变量。
class cet//调用二儿子变量
{
void sundia() {
ersun da;
da.a = 100;
da.b = 100;
da.c = 100;
}
};//调用二孙,发现a,b,c皆是不能访问,可见二孙继承的类已经不是公共类。但二二孙可以访问,所以是保护类
class sansun :public saner//三孙子,继承三儿子
{
void dia() {
a = 100;
b = 100;
c = 100;
}
};//三个不能访问,可见三儿的变量都是私有变量了。
结果截图
结论
三类继承共同点:
所有子类继承都不能访问父类的私有变量
可以访问父类的
公共继承
父类中公共为公共,保护为保护
保护继承
父类中所有为保护
私有继承
父类中所有为私有
实现额外内容
关于b private继承a类public时,使用using变为public
class baba
{
public:
int a=10;
int b=100;
int c=1000;
};
class saner :private baba
{
public:
using baba::a;
};
class ce {
void yong() {
saner san;
san.a = 11;//不会报错,可见成功改为了public
//san.b = 11;//会报错,可见成功继承并且为私密
}
};
多继承
多继承的格式
class 子类:继承方式 父类 ,继承方式 父类
继承与多继承同名问题
子类中的同名成员会覆盖父类中所有的同名成员(包括重载)
直接调用会调用子类如果要调用父类要加作用域
如
子类.父类::函数
静态成员同样
但有一点不同,通过类名可以为
子类::父类::静态成员名字或者函数名字
多继承中同名问题同上
虚继承处理
在继承方式前面加上virtual加上后后面的类就叫做虚基类
Vbptr虚基类指针,指向vbtable虚基类表
V —virtual
B —base
Ptr —指针
菱形继承问题
菱形继承问题是典型要用到虚继承的多继承问题,如果爷爷类的一个属性被爸爸继承以后就会出现再多继承给孙子就会造成数据多余浪费
代码简单研讨
class dongwu {
public:
int tui;
};
class mao : virtual public dongwu //猫继承了动物
{
public:
mao() {
tui = 4;
}
};
class ying : virtual public dongwu //鹰继承了动物
{
public:
ying() {
tui = 2;
}
};
class maoying :public mao, public ying {//猫头鹰继承了猫和鹰
public:
void test() {
cout << "tui is" << tui << endl;
}
};
int main() {
maoying my;
my.test();
}
后面的修改覆盖了前面的修改,实现了多继承中多个属性问题。
有趣的细节问题
1.父类中的私有成员只是被编辑器屏蔽了,访问不到,但是确实是被继承下去了。可以通过查子类大小和调用开发人员命令提示工具
2.继承时父类与子类谁先构造,谁先析构
class dongwu {
public:
dongwu() {
cout << "动物构造" << endl;
}
~dongwu() {
cout << "动物析构" << endl;
}
};
class gou : public dongwu //狗继承了动物
{
public:
gou(){
cout << "gou构造" << endl;
}
~gou(){
cout << "gou析构" << endl;
}
};
void test() {
gou g;
};
int main() {
test();
};
可见结果为:
父类构造
子类构造
父类析构
子类析构
友元函数的继承中问题
关于“爸爸 的朋友”可以访问“儿子”那些内容与“爸爸的朋友的儿子”可以访问的内容研究
代码设计
class baba
{
public:
int a;
protected:
int b;
private:
int c;
friend class bapeng;
};
class daer :private baba
{
public:
int d;
protected:
int e;
private:
int f;
friend class erpeng;
};
class bapeng//设计爸爸的朋友
{
public:
void text() {
daer da;
da.a;//无论大儿何种继承都能访问
da.b;//如上
da.c;//如上
da.d;
da.e;//同一般类,不能访问
da.f;//不能访问
};
};
class penger :public bapeng//爸爸朋友的儿子
{
public:
void text() {
daer da;
da.a;//在大儿公共继承时可以访问,其他不能访问
da.b;//不能访问
da.c;//不能访问
da.d;
da.e;//不能
da.f;//不能
};
};
class erpeng //儿子的朋友
{
public:
void text() {
daer da;
da.a;
da.b;//不论大儿哪种种继承都可访问说明只要是朋友就能分享父类的私密以外继承
da.c;//不论何种继承方式都不可访问
da.d;
da.e;//可以访问
da.f;//可以访问,友元函数的基本性质
};
};
测试结果
代码设计
class baba
{
public:
int a;
protected:
int b;
private:
int c;
friend class bapeng;
};
class daer :private baba
{
public:
int d;
protected:
int e;
private:
int f;
friend class erpeng;
};
class bapeng//设计爸爸的朋友
{
public:
void text() {
daer da;
da.a;//无论大儿何种继承都能访问
da.b;//如上
da.c;//如上
da.d;
da.e;//同一般类,不能访问
da.f;//不能访问
};
};
class penger :public bapeng//爸爸朋友的儿子
{
public:
void text() {
daer da;
da.a;//在大儿公共继承时可以访问,其他不能访问
da.b;//不能访问
da.c;//不能访问
da.d;
da.e;//不能
da.f;//不能
};
};
class erpeng //儿子的朋友
{
public:
void text() {
daer da;
da.a;
da.b;//不论大儿哪种种继承都可访问说明只要是朋友就能分享父类的私密以外继承
da.c;//不论何种继承方式都不可访问
da.d;
da.e;//可以访问
da.f;//可以访问,友元函数的基本性质
};
};
测试结果
截图难看,我直接把结果备注在上面代码了,其中代码部分是尝试过各种变换继承的。
结论爸爸的朋友可以访问爸爸继承给儿子的所有属性;
爸爸朋友的儿子已经和一般类没有区别;
儿子的朋友有儿子的朋友属性,对于对儿子继承的爸爸的属性只要不是私密都可访问(这条我不太确定,感觉实验有问题)
多态的研究与实现、
一般多态
class dongwu {
public:
virtual void jiao() //加上了virtual使其变成虚函数。
{
cout << "i'm dongwu" << endl;
}
};
class gou : public dongwu //狗继承了动物
{
public:
void jiao() //狗重写了函数
{
cout << "wangwangwang" << endl;
};
};
class mao : public dongwu //猫继承了动物
{
public:
void jiao()//猫重写了函数
{
cout << "miaomiaomiao" << endl;
};
};
int main()//执行函数
{
dongwu d;
d.jiao();
gou g;
g.jiao();
mao m;
m.jiao();
}
结果
class dongwu {
public:
virtual void jiao() //加上了virtual使其变成虚函数。
{
cout << "i'm dongwu" << endl;
}
};
class gou : public dongwu //狗继承了动物
{
public:
void jiao() //狗重写了函数
{
cout << "wangwangwang" << endl;
};
};
class mao : public dongwu //猫继承了动物
{
public:
void jiao()//猫重写了函数
{
cout << "miaomiaomiao" << endl;
};
};
int main()//执行函数
{
dongwu d;
d.jiao();
gou g;
g.jiao();
mao m;
m.jiao();
}
结果
地址调用的特殊多态
代码设计
class dongwu {
public:
virtual void jiao() //加上了virtual使其变成虚函数。
{
cout << "i'm dongwu" << endl;
}
};
class gou : public dongwu //狗继承了动物
{
public:
void jiao() //狗重写了函数
{
cout << "wangwangwang" << endl;
};
};
class mao : public dongwu //猫继承了动物
{
public:
void jiao()//猫重写了函数
{
cout << "miaomiaomiao" << endl;
};
};
void out1(dongwu& X) {
X.jiao();
};
void out2(dongwu* X) {
X->jiao();
};
int main()//执行函数
{
dongwu d;
out1(d);
out2(&d);
gou g;
out1(g);
out2(&g);
mao m;
out1(m);
out2(&m);
}
结果展示
关于虚析构函数与纯虚析构函数
测试代码设计
#include
#include
using namespace std;
class dongwu {
public:
dongwu() {
cout << "dongwu构造执行" << endl;
}
~dongwu() {
cout << "dongwu析构执行" << endl;
}
virtual void jiao() //加上了virtual使其变成虚函数。
{
cout << "i'm dongwu" << endl;
}
};
class gou : public dongwu //狗继承了动物
{
public:
gou(string name) {
m_name = new string(name);
}
void jiao() //狗重写了函数
{
cout << *m_name<< "wangwangwang" << endl;
};
~gou() {
if (m_name != NULL)
cout << "gou析构函数执行" << endl;
delete m_name;
m_name = NULL;
}
string* m_name;
};
void test() {
dongwu* anm = new gou("xiaohuang shuo:");
anm->jiao();
delete anm;
};
int main() {
test();
};
此代码运行结果为
#include#include using namespace std; class dongwu { public: dongwu() { cout << "dongwu构造执行" << endl; } ~dongwu() { cout << "dongwu析构执行" << endl; } virtual void jiao() //加上了virtual使其变成虚函数。 { cout << "i'm dongwu" << endl; } }; class gou : public dongwu //狗继承了动物 { public: gou(string name) { m_name = new string(name); } void jiao() //狗重写了函数 { cout << *m_name<< "wangwangwang" << endl; }; ~gou() { if (m_name != NULL) cout << "gou析构函数执行" << endl; delete m_name; m_name = NULL; } string* m_name; }; void test() { dongwu* anm = new gou("xiaohuang shuo:"); anm->jiao(); delete anm; }; int main() { test(); };
此代码运行结果为
原因
父类指针在析构时不会调用子类析构函数在析构时不会调用子类析构函数导致子类如果有堆区属性时,会造成信息泄露。
解决方法
解决方法 ~dongwu() 改成virtual ~dongwu()即可(只是更改一行代码故没有复制代码上来)结果如下
简单表述纯虚析构函数
纯虚析构改为dongwu::~dongwu(){ }即可,已经实现可用,观赏性原则并不展示。纯虚析构
总结
这次实验继承部分有趣,探究性强,但未能完成作图,可以说是相当遗憾了。



