C++继承详细介绍

作者:是星星鸭 时间:2022-08-18 10:05:42 

前言

可能会涉及到汇编的知识,不过这没有关系,肯定能看懂,看不懂留言,我再做解释。

使用到的工具是vs2010。

本节只讲继承的特点,公有私有多态等内容暂且不讲,以后会细说。

一、什么是继承

继承就是数据的复制

概念模糊、直接上代码:

#include <stdio.h>
#include <Windows.h>
struct Master            // 父类(基类)
{
int a;
int b;
};
struct Slave:Master      // 子类(派生类)
{
int c;
int d;
};
int main()
{
Slave slave;
slave.a = 1;
slave.b = 2;
slave.c = 3;
slave.d = 4;
int x = sizeof(slave);
system("pause");      // 此处下断点查看x的大小(子类的大小)
return 0;
}

运行,查看x的值:

C++继承详细介绍

16,这足以说明slave是拷贝了一份a和b给slave子类的。

查看汇编:

C++继承详细介绍

可以看出继承就是数据的复制

二、派生类和基类的成员重复问题

1、派生类和基类的成员可以重复吗?

2、重复的话是使用的哪一个类的成员呢?

解答如下:

1、派生类和基类的成员可以重复吗?

可以。

证明:

#include <stdio.h>
#include <Windows.h>
struct Master
{
int a;
int b;
};
struct Slave:Master
{
int a;
int d;
};
int main()
{
Slave slave;
   printf("%d \n",sizeof(slave));
system("pause");          
return 0;
}

运行:

C++继承详细介绍

不仅可以,而且slave类的大小依旧是16字节;

这说明了子类的a和父类的a是分开的,父类的a依旧被拷贝到了子类,尽管子类已经有成员a;

2、重复的话是使用的哪一个类的成员呢?

这样就不要使用变量来测试了,因为变量无法输出内容,很难分辨出是父类还是子类的,所以我们使用函数。

如下:

#include <stdio.h>
#include <Windows.h>
struct Master
{
void test()
{
printf("这是父类的测试。\n");
}
};
struct Slave:Master
{
void test()
{
printf("这是子类的测试。\n");
}
};
int main()
{
Slave slave;
slave.test();
system("pause");
return 0;
}

定义一父一子,类中都定义了test函数,那么子类的对象会调用谁的呢?

运行如下:

C++继承详细介绍

子类调用了子类的。

父类的对象会调用谁的呢?

测试如下:

C++继承详细介绍

运行:

C++继承详细介绍

父类调用父类。

可以看到,对象的默认调用都是本类自己定义的函数。

父类调用子类方法

父类可以调用子类方法吗?如何调用?子类又如何调用父类呢?

父类可以调用子类方法,步过需要一些手段;子类可以直接调用父类

先看一张图:

C++继承详细介绍

从这张图我们可以得知,子类包含了父类中允许继承的所有内容;但父类不包含任何子类的东西。

所以,子类可以直接调用父类是应该的,如下:

#include <stdio.h>
#include <Windows.h>
struct Master
{
void test()
{
printf("这是父类的测试。\n");
}
};
struct Slave:Master
{
void test()
{
printf("这是子类的测试。\n");
}
};
int main()
{
Slave slave;
slave.test();
slave.Master::test();        // 声明调用父类的内容即可
system("pause");
return 0;
}

运行如下:

C++继承详细介绍

可以看到,子类正常的调用了父类的方法;

如果父类直接调用子类的呢?

如下:

C++继承详细介绍

直接调用的话是不被允许的。

不过可以通过其他方法进行调用;

父类调用子类

我们知道,纯虚函数是必须要子类进行实现的,如果父类定义了纯虚函数,子类不进行实现,就会报错;我们可以通过这一点,让父类定义纯虚函数,子类来实现这个纯虚函数;然后父类定义指针(纯虚类就是接口类,无法定义对象,可以定义指针)来指向子类,调用子类的函数。

如下:

#include <stdio.h>
#include <Windows.h>
struct Master
{
virtual void test() = 0; // 父类定义纯虚函数
};
struct Slave:Master
{
void test() // 子类实现纯虚函数
{
printf("这是子类的测试。\n");
}
};
int main()
{
Slave slave;
slave.test(); // 子类正常调用
// Master master; // 不可以定义对象,会出错。
Master *master = &slave; // 可以定义指针指向子类
master->test();
system("pause");
return 0;
}

运行:

C++继承详细介绍

成功调用。

当然还有其他方法可以让父类调用子类,不过本文章只讲继承,不深入其他内容;大家感兴趣的话可以自己百度看看。

三、继承不仅仅局限于父类

怎么理解这个标题呢?就是说,不单单是父类可以有派生类,子类也可以有派生类。

如果子类有派生类,那么子类的派生类仅仅有父类的成员,还是既有父类的成员也有父类的父类成员?

观点:子类的派生类,即会拥有父类的公有成员也会拥有父类的父类的公有成员。

文字模糊,看图:

C++继承详细介绍

通过这张图我们可以知道:Son调用Slave的函数或者Master的函数可以直接调用;

Son包含Master和Slave所有公有成员、Slave只包含Master的公有成员、Master只包含自己的成员。

论证如下:

直接测试类所占用字节数就行了,如下:

#include <stdio.h>
#include <Windows.h>
struct Master
{
int a;
int b;
};
struct Slave:Master
{
int c;
int d;
};
struct Son:Slave
{
int e;
int f;
};
int main()
{
int MasterSize = sizeof(struct Master);
int SlaveSize = sizeof(struct Slave);
int SonSize = sizeof(struct Son);
printf("Master成员个数:\t%d\nSlave成员个数:\t\t%d\nSon成员个数:\t\t%d\n",MasterSize/4,SlaveSize/4,SonSize/4);
system("pause");
return 0;
}

Slave继承Master,Son继承Slave

三个类的成员都是int类型,所以通过类的字节数/4就可以知道这个类有几个成员

运行如下:

C++继承详细介绍

论证成功。

四、多重继承

就是说子类不单单可以继承一个父类,可以继承多个。

如下:

#include <stdio.h>
#include <Windows.h>
struct Master                 // 第一个父类
{
int a;
int b;
};
struct Slave                  // 第二个父类
{
int c;
int d;
};
struct Son:Slave,Master       // 两个父类
{
int e;
int f;
};
int main()
{
int MasterSize = sizeof(struct Master);
int SlaveSize = sizeof(struct Slave);
int SonSize = sizeof(struct Son);
printf("Master成员个数:\t%d\nSlave成员个数:\t\t%d\nSon成员个数:\t\t%d\n",MasterSize/4,SlaveSize/4,SonSize/4);
system("pause");
return 0;
}

运行如下:

C++继承详细介绍

所以,如图:

C++继承详细介绍

这就是多重继承,但是多重继承增加了程序的复杂度,不建议使用 。

来源:https://blog.csdn.net/qq_52572621/article/details/127234843

标签:C++,继承
0
投稿

猜你喜欢

  • springboot+spring data jpa实现新增及批量新增方式

    2023-01-27 03:45:53
  • C# 嵌入dll 的方法

    2022-11-06 08:39:10
  • List转换成DataSet实现代码

    2023-03-02 04:46:01
  • Java发送邮箱验证码、session校验功能

    2023-09-11 02:44:21
  • 浅谈为什么要使用mybatis的@param

    2023-07-01 20:12:39
  • Spring Boot之AOP配自定义注解的最佳实践过程

    2023-01-27 17:41:02
  • C#调用海康工业相机SDK采集图像并在Halcon窗口中显示方式

    2022-06-26 00:48:02
  • java反射拼接方法名动态执行方法实例

    2022-12-07 00:44:28
  • SpringBoot过滤器与拦截器使用方法深入分析

    2023-08-18 10:20:03
  • Springboot深入讲解nocos的整合与使用

    2022-06-05 05:11:27
  • Unity UGUI实现卡片椭圆方向滚动

    2022-06-03 06:02:53
  • Android实现列表元素动态效果

    2021-07-18 07:05:22
  • Spring Boot和Vue前后端分离项目架构的全过程

    2023-09-20 17:49:13
  • Unity利用材质自发光实现物体闪烁

    2021-07-03 20:42:26
  • 自定义mybatis插件如何实现sql日志打印

    2023-11-29 11:22:37
  • 一篇文章教你如何用多种迭代写法实现二叉树遍历

    2023-12-23 04:03:29
  • java nio基础使用示例

    2022-02-12 01:46:22
  • Java读写Windows共享文件夹的方法实例

    2022-10-02 02:25:45
  • 使用java实现各种数据统计图(柱形图,饼图,折线图)

    2022-03-09 22:12:50
  • gradle中的增量构建浅析

    2022-09-23 06:43:13
  • asp之家 软件编程 m.aspxhome.com