使用继承与派生的6大要点
概述
面向对象编程技术非常看重软件的可重用性,在C++中,可重用性是通过继承机制来实现的。继承机制允许程序员在保持原有类的数据和功能的基础上进行扩展,增加新的数据和功能,从而构成一个新的类,也称为派生类。原有类,一般称之为基类。派生类不仅拥有基类的成员,还拥有自身新增加的成员。继承与派生是C++的重要组成部分,也是C++的基础知识。掌握好了继承与派生,就对面向对象编程技术有了更深刻的理解。关于继承与派生的入门知识,这里就不赘述了,下面将介绍继承与派生相关的一些知识要点。
访问权限
派生类从基类派生时,有三种继承方式,分别是:公有继承、保护继承、私有继承,分别对应关键字public、protected、private。
公有继承时,基类中public成员和protected成员在派生类中的访问权限不变,private成员在派生类中不可访问。
保护继承时,基类中public成员和protected成员在派生类中的访问权限变为protected,private成员在派生类中不可访问。
私有继承时,基类中public成员和protected成员在派生类中的访问权限都变为private,private成员在派生类中不可访问。
可通过下表更清晰地看到不同继承方式下,基类成员在派生类中的访问权限。
基类public成员 | 基类protected成员 | 基类private成员 | |
公有继承 | public | protected | 不可访问 |
保护继承 | protected | protected | 不可访问 |
私有继承 | private | private | 不可访问 |
派生类能否改变基类成员在自身的访问权限呢?答案是肯定的,通过using关键字即可。参看下面的示例代码。
class CBase
{
public:CBase();int m_nData1;protected:int m_nData2;private:int m_nData3;
};CBase::CBase() : m_nData1(6), m_nData2(88), m_nData3(999)
{NULL;
}class CDerived : public CBase
{
public:using CBase::m_nData2;protected:using CBase::m_nData1;using CBase::m_nData3; // 编译错误
};CDerived derived;
printf("data1 is %d\n", derived.m_nData1); // 编译错误
printf("data2 is %d\n", derived.m_nData2); // 编译正常
可以看到,通过using 基类::基类成员的方式,可以修改基类成员在派生类中的访问权限。m_nData1原来为public,修改后变为protected。m_nData2原来为protected,修改后变为public。由于m_nData3在基类CBase中为private,故在派生类中无法访问,因此无法通过using CBase::m_nData3修改private成员的访问权限。
构造顺序
构造派生类的对象时,会按照顺序依次调用以下函数。
1、所有基类的构造函数。注意是根据继承基类的顺序,而不是派生类中初始化列表的顺序来调用的。
2、派生类所有成员变量的构造函数。注意是根据声明成员变量的顺序,而不是初始化列表的顺序来调用的。
3、派生类的构造函数。
在派生类的初始化列表中,如果没有显式调用基类和成员变量的构造函数,则自动调用基类和成员变量默认的构造函数。另外,销毁派生类对象时,调用析构函数的顺序与上面的顺序正好相反。
可以通过下面的示例代码更好地理解构造顺序和析构顺序。
class CTemp1
{
public:CTemp1(){printf("CTemp1 constructor\n");}~CTemp1(){printf("CTemp1 destructor\n");}
};class CTemp2
{
public:CTemp2(int nNumber){printf("CTemp2 constructor: %d\n", nNumber);}~CTemp2(){printf("CTemp2 destructor\n");}
};class CTemp3
{
public:CTemp3(){printf("CTemp3 constructor\n");}~CTemp3(){printf("CTemp3 destructor\n");}
};class CBase1
{
public:CBase1(){printf("CBase1 constructor\n");}~CBase1(){printf("CBase1 destructor\n");}
};class CBase2
{
public:CBase2(int nNumber){printf("CBase2 constructor: %d\n", nNumber);}~CBase2(){printf("CBase2 destructor\n");}
};class CBase3
{
public:CBase3(){printf("CBase3 constructor\n");}~CBase3(){printf("CBase3 destructor\n");}
};class CDerived : public CBase1, public CBase2, public CBase3
{
public:CDerived() : m_tmp2(66), m_tmp1(), CBase2(88), CBase1() {printf("CDerived constructor\n");}~CDerived(){printf("CDerived destructor\n");}private:CTemp1 m_tmp1;CTemp2 m_tmp2;CTemp3 m_tmp3;
};CDerived derived;
上述示例的输出如下:
CBase1 constructor
CBase2 constructor: 88
CBase3 constructor
CTemp1 constructor
CTemp2 constructor: 66
CTemp3 constructor
CDerived constructor
CDerived destructor
CTemp3 destructor
CTemp2 destructor
CTemp1 destructor
CBase3 destructor
CBase2 destructor
CBase1 destructor
从输出可以得出以下几点。
1、在CDerived的初始化列表中,先初始化了m_tmp2和m_tmp1,但依然先调用了三个基类的构造函数。
2、在CDerived的初始化列表中,先初始化了CBase2,然后才初始化了CBase1,但依然按照继承基类的顺序先调用了CBase1的构造函数。
3、在CDerived的初始化列表中,没有初始化CBase3,但依然调用了CBase3的默认构造函数。如果CBase3没有默认构造函数,则编译出错。
4、在CDerived的初始化列表中,先初始化了m_tmp2,然后才初始化了m_tmp1,但依然按照声明成员变量的顺序先调用了m_tmp1的构造函数。
5、在CDerived的初始化列表中,没有初始化m_tmp3,但依然调用了m_tmp3的默认构造函数。如果m_tmp3没有默认构造函数,则编译出错。
6、析构的顺序与构造的顺序正好相反。
同名覆盖
派生类和基类可以拥有同名的成员,此时,派生类会把基类中所有同名的成员(包括多个重载版本的函数)都覆盖掉。要想调用基类的成员,必须加作用域。
class CBase
{
public:CBase() : m_nData(66){NULL;}void ShowData(){printf("CBase data is %d\n", m_nData);}void ShowData(const std::string &strData){printf("CBase data is %s\n", strData.c_str());}int m_nData;
};class CDerived : public CBase
{
public:CDerived() : CBase(), m_nData(88){NULL;}void ShowData(){printf("CDerived data is %d, %d\n", m_nData, CBase::m_nData);}int m_nData;
};CDerived derived;
derived.ShowData();
derived.ShowData("CSDN"); // 编译出错
printf("data is %d\n", derived.m_nData);derived.CBase::ShowData();
derived.CBase::ShowData("CSDN");
printf("data is %d\n", derived.CBase::m_nData);CBase *pBase = &derived;
pBase->ShowData();
上述示例的输出如下:
CDerived data is 88, 66
data is 88
CBase data is 66
CBase data is CSDN
data is 66
CBase data is 66
可以看到,调用派生类对象derived的成员函数ShowData()和成员变量m_nData时,都是使用的派生类中的成员。调用派生类对象derived的ShowData("CSDN")时,因为同名会覆盖基类中多个重载版本的函数,导致基类中重载字符串参数的函数在派生类中被隐藏了,不可见,故会报编译错误。加上作用域后,便可以指定访问基类中的成员变量和成员函数。另外,将基类指针指向一个派生类对象时,用基类指针调用的都是基类中的成员(不涉及虚函数,属于静态绑定)。
多继承
多继承是指派生类同时从多个基类派生。如果多个基类中有同名的public和protected成员,则会引起歧义,导致编译出错。由于基类中的private成员在派生类中不可访问,故同名的private成员不会引起问题。解决多基类同名的方法为:使用作用域访问指定基类中的同名成员。可参看下面的示例代码。
class CBase1
{
public:CBase1() : m_nNumber(66), m_strText("Hello"), m_bPassed(true){NULL;}int m_nNumber;protected:std::string m_strText;private:bool m_bPassed;
};class CBase2
{
public:CBase2() : m_nNumber(88), m_strText("CSDN"), m_bPassed(false){NULL;}int m_nNumber;protected:std::string m_strText;private:bool m_bPassed;
};class CDerived : public CBase1, public CBase2
{
public:void Show(){// 编译出错printf("data is %d, %s\n", m_nNumber, m_strText.c_str());// 输出:CBase1 data is 66, Helloprintf("CBase1 data is %d, %s\n", CBase1::m_nNumber, CBase1::m_strText.c_str());// 输出:CBase2 data is 88, CSDNprintf("CBase2 data is %d, %s\n", CBase2::m_nNumber, CBase2::m_strText.c_str());}
};
可以看到,由于CBase1和CBase2中均有m_nNumber和m_strText,在CDerived中直接访问这两个成员,会引发编译错误。通过指定作用域CBase1::和CBase2::,可以在派生类中指定访问CBase1和CBase2的成员。
虚函数
虚函数在C++中主要是为了实现多态机制。所谓多态,也就是用基类的指针指向派生类的实例,然后通过基类的指针调用派生类实例的成员函数。可参看下面的示例代码。
class CBase
{
public:CBase() : m_nData1(66){NULL;}virtual void Test1(){printf("CBase Test1\n");}virtual void Test2(){printf("CBase Test2\n");}virtual void Test3(){printf("CBase Test3\n");}private:int m_nData1;
};class CDerived : public CBase
{
public:CDerived() : CBase(), m_nData2(88){NULL;}virtual void Test1(){printf("CDerived Test1\n");}virtual void Test2(){printf("CDerived Test2\n");}private:int m_nData2;
};CBase *pBase = new CDerived();
pBase->Test1(); // 输出:CDerived Test1
pBase->Test2(); // 输出:CDerived Test2
可以看到,通过基类指针pBase调用虚函数Test1和Test2时,调用的是派生类中的函数。
那么,虚函数是如何实现的呢?
在C++中,具有虚函数的类都有一张虚函数表。这个表相当于一个一维数组,用于存储类中所有虚函数的地址。编译器必须保证对象实例最开始的位置存放指向虚函数表的指针,然后才能存放其他成员。可通过下面的示例代码来理解虚函数表的概念。
typedef void (*Test)();CBase base;
Test pTest1 = (Test)*((size_t *)*(size_t *)(&base));
pTest1();
Test pTest2 = (Test)*((size_t *)*(size_t *)(&base) + 1);
pTest2();
int nData = (int)*((size_t *)(&base) + 1);
printf("data is %d\n", nData);CDerived derived;
pTest1 = (Test)*((size_t *)*(size_t *)(&derived));
pTest1();
pTest2 = (Test)*((size_t *)*(size_t *)(&derived) + 1);
pTest2();
Test pTest3 = (Test)*((size_t *)*(size_t *)(&derived) + 2);
pTest3();
int nData1 = (int)*((size_t *)(&derived) + 1);
int nData2 = (int)*((size_t *)(&derived) + 2);
printf("data is %d, %d\n", nData1, nData2);
上述示例的输出如下:
CBase Test1
CBase Test2
data is 66
CDerived Test1
CDerived Test2
CBase Test3
data is 66, 88
可以看到,我们完全通过指针的操作就访问了类实例中的虚函数和成员变量。在上面的代码中,(size_t *)(&base)为指向虚函数表的指针,*(size_t *)(&base)为虚函数表的地址,相当于一维数组的地址,(size_t *)*(size_t *)(&base)指向虚函数表中第一个虚函数的地址,*((size_t *)*(size_t *)(&base))则是第一个虚函数。其他虚函数和成员变量的指针转换与此类似,这里不再赘述。下图给出了类实例base和derived的内存布局结构,供大家参考。
上面讨论的都是单继承的情况,多继承时,原理类似,只是更复杂些,这里就不再深入介绍了。
虚继承
虚继承是为了解决菱形继承中,存在多份公共基类的拷贝,从而导致二义性的问题。在定义派生类时,如果在基类的名字前面加上virtual关键字,则构成虚继承。先通过下面的示例代码来看看菱形继承的问题。
class CBase
{
public:CBase() : m_nNumber(1){printf("CBase default constructor\n");}CBase(int nNumber) : m_nNumber(nNumber){printf("CBase constructor: %d\n", nNumber);}protected:int m_nNumber;
};class CDerived1 : public CBase
{
public:CDerived1() : CBase(66){printf("CDerived1 constructor\n");}
};class CDerived2 : public CBase
{
public:CDerived2() : CBase(88){printf("CDerived2 constructor\n");}
};class CFinal : public CDerived1, public CDerived2
{
public:CFinal() : CDerived1(), CDerived2(){printf("CFinal constructor\n");}void Show(){printf("CFinal show: %d\n", m_nNumber); // 编译出错printf("CFinal show 1: %d\n", CDerived1::m_nNumber);printf("CFinal show 2: %d\n", CDerived2::m_nNumber);}
};CFinal final;
final.Show();
上述示例的输出如下:
CBase constructor: 66
CDerived1 constructor
CBase constructor: 88
CDerived2 constructor
CFinal constructor
CFinal show 1: 66
CFinal show 2: 88
可以看到,CFinal继承了CDerived1和CDerived2,而CDerived1和CDerived2都继承了CBase。在CFinal中直接访问公共基类CBase中的成员变量m_nNumber时,便会存在二义性问题。虽然可以通过指定作用域来分别访问CDerived1和CDerived2中的m_nNumber,但CBase存在多份的问题仍然存在(调用了两次CBase的构造函数)。
再来看看使用虚继承时的示例代码。
class CBase
{
public:CBase() : m_nNumber(1){printf("CBase default constructor\n");}CBase(int nNumber) : m_nNumber(nNumber){printf("CBase constructor: %d\n", nNumber);}protected:int m_nNumber;
};class CDerived1 : public virtual CBase
{
public:CDerived1() : CBase(66){printf("CDerived1 constructor\n");}
};class CDerived2 : public virtual CBase
{
public:CDerived2() : CBase(88){printf("CDerived2 constructor\n");}
};class CFinal : public CDerived1, public CDerived2
{
public:CFinal() : CDerived1(), CDerived2(){printf("CFinal constructor\n");}void Show(){printf("CFinal show: %d\n", m_nNumber); // 编译正常printf("CFinal show 1: %d\n", CDerived1::m_nNumber);printf("CFinal show 2: %d\n", CDerived2::m_nNumber);}
};CFinal final;
final.Show();
上述示例的输出如下:
CBase default constructor
CDerived1 constructor
CDerived2 constructor
CFinal constructor
CFinal show: 1
CFinal show 1: 1
CFinal show 2: 1
可以看到,使用虚继承后,公共基类CBase的构造函数只调用了一次,且调用的是默认构造函数。这是因为虚基类的构造函数比较特殊,与常规的构造函数有所不同。由于从虚基类派生出来的每一个派生类中,其构造函数都调用了基类的构造函数,这样编译器就无法确定到底用哪一个派生类来构造基类对象。最终,编译器会忽略所有派生类中对基类构造函数的调用,而选择调用基类的默认构造函数。
如果基类的默认构造函数不存在,则编译器将报错。解决该问题的方法是:显式在CFinal中调用CBase的其他构造函数。示例代码如下:
class CFinal : public CDerived1, public CDerived2
{
public:CFinal() : CDerived1(), CDerived2(), CBase(2){printf("CFinal constructor\n");}void Show(){printf("CFinal show: %d\n", m_nNumber);printf("CFinal show 1: %d\n", CDerived1::m_nNumber);printf("CFinal show 2: %d\n", CDerived2::m_nNumber);}
};
相关文章:
使用继承与派生的6大要点
概述 面向对象编程技术非常看重软件的可重用性,在C中,可重用性是通过继承机制来实现的。继承机制允许程序员在保持原有类的数据和功能的基础上进行扩展,增加新的数据和功能,从而构成一个新的类,也称为派生类。原有类&a…...
加一-力扣66-java高效方案
一、题目描述给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。你可以假设除了整数 0 之外,这个整数不会以零开头。示例 1:输入:di…...
记一次 .NET 某游戏网站 CPU爆高分析
一:背景 1. 讲故事 这段时间经常有朋友微信上问我这个真实案例分析连载怎么不往下续了,关注我的朋友应该知道,我近二个月在研究 SQLSERVER,也写了十多篇文章,为什么要研究这东西呢? 是因为在 dump 中发现…...
集群使用——资源管理和租户创建
概述 OceanBase 数据库是多租户的分布式数据库,租户使用的资源建立在资源池上。资源池包含了资源单元,而资源单元则规定了具体资源的量化(如 CPU、Memory、Disk_Size 和 IOPS 等)。 创建租户前,必须规定租户使用的资源…...
谷歌浏览器登录失败,提示【无法同步到“...@gmail.com”】
首先安装Chrome同步助手(Chrome-Sync-Helper,看了很多博客,谷歌浏览器同步问题好像都要用这个),改成.rar,解压,文件夹_metadata重命名为metadata,然后添加到谷歌浏览器的扩展程序中。…...
75 111111
选择题(共75题,合计75.0分) 1. 选项ABCD中显示了所创造的商业价值以及在产品中实施各种功能需要进行的开发工作。团队应优先实施哪项功能? The business value created and the development effort needed to implement the various features in the product are sh…...
分销系统逻辑
相关概念 主营商户: 提供分销商品和佣金的商户分销商: 拥有自己的销售渠道,能够帮助推动产品销售的个人或商户消费者: 购买分销商品的人。佣金: 主营商户返还给经销商的比例抽成 分销功能设计 (1)分销商准入规则设计 无规则: 没有分销商的准入门槛限制…...
MySQL视图特性
文章目录MySQL视图特性基本使用准备测试表创建视图修改视图影响基表修改基表影响视图删除视图视图规则和限制MySQL视图特性 视图的概念 视图是一个虚拟表,其内容由查询定义,同真实的表一样,视图包含一系列带有名称的列和行数据。视图中的数据…...
RabbitMQ详解(二):Docker安装RabbitMQ
在Docker上安装部署RabbitMQ方便快捷,不需要额外安装Erlang环境,所以写该篇文章先来介绍如何在Docker上部署RabbitMQ。 一、安装并运行 (1)、在docker hub 中查找rabbitmq镜像 docker search rabbitmq:3.9.12-management带有“mangement”的版本&…...
如何使用代码注释:关于JavaScript与TypeScript 注释和文档的自动生成
如何使用代码注释:关于JavaScript与TypeScript 注释和文档的自动生成jcLee95:https://blog.csdn.net/qq_28550263?spm1001.2101.3001.5343 邮箱 :291148484163.com 本文地址:https://blog.csdn.net/qq_28550263/article/detail…...
Echarts 设置面积区域图(areaStyle核心)
第011个点击查看专栏目录Echarts折线区域面积图的视觉效果更加饱满丰富,在系列不多的场景下尤其适用。区域面积图将折线到坐标轴的空间设置背景色,用区域面积表达数据。通过 areaStyle 设置折线图的填充区域样式,将其设为为 {} 表示使用默认…...
pandas——字符串处理【建议收藏】
pandas——字符串处理 作者:AOAIYI 创作不易,如果觉得文章不错或能帮助到你学习,记得点赞收藏评论一下哦 文章目录pandas——字符串处理一、实验目的二、实验原理三、实验环境四、实验内容五、实验步骤1.cat() 拼接字符串2.split()切片字符串…...
反射,枚举,lambda表达式
目录 1、反射 1.1 基本概念 1.2 反射相关的类 1.3 创建 Class 对象 1.4 反射的使用 1.4.1 通过反射创建对象: 1.4.2 获取私有的构造方法 1.4.3 获取私有的成员变量 1.4.4 获取私有的方法 1.5 总结 2、枚举 2.1 认识枚举 2.2 使用枚举 2.3 枚举与反射…...
.Net Core对于RabbitMQ封装分布式事件总线
首先我们需要了解到分布式事件总线是什么; 分布式事件总线是一种在分布式系统中提供事件通知、订阅和发布机制的技术。它允许多个组件或微服务之间的协作和通信,而无需直接耦合或了解彼此的实现细节。通过事件总线,组件或微服务可以通过发布…...
GPIO功能描述
GPIO 文章目录 GPIO1. 功能描述1.1 OSCI/OSCO 引脚1.3 HSEIN/HSEOUT引脚1.2 Bit-Band1.4 VRTCAFx引脚1.5 EWKUPx引脚1.6 QSPI0 引脚1.7 LVDIN引脚1.8 SARADC引脚1.9 ADCIN引脚2. 测试项描述2.1 PAD Location2.2 LBOR和BOR复位2.3 驱动能力2.4 模拟态\高阻态2.5 SWD\JTAG2.6 输出…...
指派问题与匈牙利法讲解
指派问题概述:实际中,会遇到这样的问题,有n项不同的任务,需要n个人分别完成其中的1项,每个人完成任务的时间不一样。于是就有一个问题,如何分配任务使得花费时间最少。通俗来讲,就是n*n矩阵中&a…...
day5——冒泡排序,选择排序和插入排序的学习
选择排序冒泡排序插入排序 选择排序 选择排序的基本思路就是: 首先假定第一个的下表为所有元素中最小的一个, 然后用后面的每一个元素跟这个元素进行比较, 如果后面的元素比这个元素更小一点, 那么就将找到的最小的元素的下标和…...
Windows 数据类型 (Windows Data Types)
参考:https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types 要求 要求值最低受支持的客户端Windows XP [仅限桌面应用]最低受支持的服务器Windows Server 2003 [仅限桌面应用]HeaderBaseTsd.h;WinDef.h;WinNT.hAPIENTRY 系统函数的调用约…...
九龙证券|本周5只新股申购,特斯拉、蔚来、理想的供应商来A股了!
据现在组织,2月13日到17日共有5只新股申购,其间上证主板2只,深证主板1只,北交所2只。 2月14日发动打新的深证主板新股多利科技成立于2010年,是一家专心于轿车冲压零部件及相关模具的开发、出产与出售的企业。从2020年…...
设计模式(持续更新)
本文主要是记录java的设计模式在实际工作中的应用案例,或者是对设计模式的个人理解及备忘 一、单例模式Singleton 工作场景(静态类): 在外部系统对接中,需要调用外部系统A的接口,但是接口是有身份校验的…...
Prometheus 告警规则
Prometheus 告警规则 Prometheus官方内置的第三方报警通知包括:邮件、 即时通讯软件(如Slack、Hipchat)、移动应用消息推送(如Pushover)和自动化运维工具(例如:Pagerduty、Opsgenie、Victorops) Promethe…...
mulesoft MCIA 破釜沉舟备考 2023.02.13.02
mulesoft MCIA 破釜沉舟备考 2023.02.13.03 1. According to MuleSoft, which deployment charcateristic applies to a microservices application architecture?2. A mule application designed to fulfil two requirements3. A mule application must periodically process…...
获取DLL运行时路径的方法
之前项目中发现的问题,记录下解决方案1. 问题背景OVVRNTool项目中,底层图像基本操作功能由DLL库函数提供,上层基于DLL封装了两个应用CMD和GUI,然后通过Qt打包分发;发布是直接采用绿色免安装的方式打包,具体…...
“华为杯”研究生数学建模竞赛2006年-【华为杯】D题:学生面试中教师安排的优化与算法(附获奖论文)
赛题描述 高校自主招生是高考改革中的一项新生事物,现在仍处于探索阶段。某高校拟在全面衡量考生的高中学习成绩及综合表现后再采用专家面试的方式决定录取与否。该校在今年自主招生中,经过初选合格进入面试的考生有N人,拟聘请老师M人。每位学生要分别接受4位老师(简称该学…...
【JavaScript】复习 【对象参数】【函数参数】
js不会检查任何参数类型,任何参数都可以作为参数传递 1、对象参数 改变量随便改,改对象要看这个对象是不是有多个变量同时指向这个对象 const 用来定义常量,只能赋值一次。 变量------->对象------->属性 被const修饰的对象 …...
如何批量提取文件名到excel表格?
批量提取文件名到excel表格?关于这个问题相信很多人都遇到过,大多数人在第一次碰到的时候都不知道如何下手,大家都会立即在百度里面搜索相关方法教程,小编也试着搜索了一下,发现找到的很多方法都大同小异,需…...
CUDA线程层次一文搞懂|参加CUDA线上训练营
设备术语 Host:CPU 和 内存 (host memory)Device:GPU 和显存 (device memory) CUDA 线程层次 CUDA 线程层次分为: Thread 所有线程执行相同的核函数并行执行 Thread Block 执行在一个 Streaming Multiprocessor (SM)…...
Linux文件默认权限:umask
umask就是指定目前用户在建立文件或目录时候的权限默认值 查看方式有两种:一种可以直接输入umask,就可以看到数字类型的权限设置值,一种则是加入umask后加入-S(Symbolic)选项,就会以符号类型的方式来显示出…...
SonicWall:请立即修复SMA 1000 漏洞
近日,网络安全供应商SonicWall发布了关于安全移动访问 (SMA) 1000设备的三个安全漏洞的紧急报告,其中包括一个高威胁性的身份验证绕过漏洞。SonicWall指出,攻击者可以利用这些漏洞绕过授权,并可能破坏易受攻击的设备。 从报告中可…...
基于VS调试分析 + 堆栈观察问题代码段
文章目录问题代码段1 —— 阶乘之和问题代码段2 —— 越界的危害① 发现问题② 分析问题③ 思考问题【⭐堆栈原理⭐】④ 解决问题【DeBug与Release】👨程序员与测试人员👩✒总结与提炼问题代码段1 —— 阶乘之和 先来看一道C语言中比较基础的题目&#x…...
网站建设php招聘/免费推广网站排行榜
最小均方误差(MMSE)意义下的最优帧内预测推导: MMSE:Minimum Mean Squared Error,思想是将预测值和真值的误差的平方的期望(均值)最小化,以使得预测值尽量逼近真值,和真值差距尽可能小ÿ…...
深圳做网站报价/网站推广公司黄页
NOI OpenJudge 2971:抓住那头牛 无脑bfs?还不懂为什么我之前的方法不行……noijudge 看不到 部分数据…… #include <iostream> #include <cstdio> #include <cstring> #include <queue> using namespace std;int N, K; bool vis[100010 …...
赣州做网站建设/东莞seo建站如何推广
前言 在上一篇开始Java8之旅(六) -- 使用lambda实现Java的尾递归中,我们利用了函数的懒加载机制实现了栈帧的复用,成功的实现了Java版本的尾递归,然而尾递归的使用有一个重要的条件就是递归表达式必须是在函数的尾部,但是在很多实…...
wordpress把写博客按钮放在前台/国际军事新闻最新消息视频
《关于优化高职院校计算机一体化教学》本文是计算机一方面专科毕业论文范文跟优化和高职和院校和计算机和一体化和教学类论文范本.摘 要:随着计算机技术的不断发展,在我国各领域中,计算机技术得到了广泛的应用.在这种背景下,社会对计算机专业人才需求较多,这使得高职…...
个人注册公司需要哪些资料/厦门seo排名扣费
题目 题目链接 题解 数学 高精度。 如果直接按照计算多个数连续计算最小公倍数,那么显然要经过高精度乘法、高精度除法,两个高精度过于麻烦了。 换个思路,我们将每个数都分解质因数,全部数的最小公倍数必然由分解得到的质因数…...
WordPress电脑与手机/杭州百度推广优化排名
解析 JSON 数据也有很多种方法,可以使用官方提供的 JSONObject,也可以使 用谷歌的开源库 GSON。另外,一些第三方的开源库如 Jackson、FastJSON等也非常不错。 修改 MainActivity 中的代码,如下所示: public class Main…...