当前位置: 首页 > news >正文

【C++深度探索】继承机制详解(一)

hello hello~ ,这里是大耳朵土土垚~💖💖 ,欢迎大家点赞🥳🥳关注💥💥收藏🌹🌹🌹
在这里插入图片描述

💥个人主页:大耳朵土土垚的博客
💥 所属专栏:C++入门至进阶
这里将会不定期更新有关C++的内容,希望大家多多点赞关注收藏💖💖

目录

  • 1.继承的概念
  • 2.继承定义
    • 2.1定义格式
    • 2.2访问限定符
    • 2.3继承方式
  • 3.基类和派生类对象赋值转换
  • 4.继承中的重定义(隐藏)
  • 5.派生类的默认成员函数
    • ✨构造函数
    • ✨拷贝构造
    • ✨赋值运算符重载
    • ✨析构函数
  • 6.结语

1.继承的概念

继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类子类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,继承是类设计层次的复用。

2.继承定义

2.1定义格式

下面我们看到Person是父类,也称作基类。Student是子类,也称作派生类。

//基类或父类
class Person
{
public:void Print(){cout << "name:" << _name << endl;cout << "age:" << _age << endl;}
protected:string _name = "peter";// 姓名int _age = 18;  //年龄
};//派生类或子类
class Student : public Person
{
protected:int _stuid; // 学号int _major;	//专业
};

在这里插入图片描述

2.2访问限定符

C++类的访问限定符用于控制类的成员(包括成员变量和成员函数)在类的外部的可访问性。C++中有以下三种访问限定符:

  • public: 公共访问限定符,任何地方都可以访问公共成员。可以在类的外部使用对象名和成员名直接访问公共成员。

  • private: 私有访问限定符,只有类内部的其他成员函数可以访问私有成员。类的外部无法直接访问私有成员,但可以通过公共成员函数间接访问私有成员。

  • protected: 保护访问限定符,只有类内部的其他成员函数和派生类的成员函数可以访问保护成员。类的外部无法直接访问保护成员,但可以通过公共成员函数或派生类的成员函数间接访问保护成员。

需要注意的是,访问限定符只在类的内部起作用,在类的外部没有直接的影响。同时,访问限定符可以用于类的成员变量和成员函数的声明中,默认情况下,成员变量和成员函数的访问限定符是private。

2.3继承方式

在这里插入图片描述
C++类的继承方式有以下几种:

  • 公有继承(public inheritance):使用关键字"public"表示的继承方式。在公有继承中,基类的公有成员和保护成员都可以在派生类中访问,私有成员不能在派生类中直接访问。
class Base {
public:// 公有成员
protected:// 保护成员
private:// 私有成员
};class Derived : public Base {// 公有继承
};
  • 保护继承(protected inheritance):使用关键字"protected"表示的继承方式。在保护继承中,基类的公有成员和保护成员在派生类中都变为保护成员私有成员不能在派生类中直接访问。
class Base {
public:// 公有成员
protected:// 保护成员
private:// 私有成员
};class Derived : protected Base {// 保护继承
};
  • 私有继承(private inheritance):使用关键字"private"表示的继承方式。在私有继承中,基类的公有成员和保护成员在派生类中都变为私有成员,私有成员不能在派生类中直接访问。
class Base {
public:// 公有成员
protected:// 保护成员
private:// 私有成员
};class Derived : private Base {// 私有继承
};

总结如下:

类成员/继承方式public继承protected继承private继承
基类的public成员派生类的public成员派生类的protected成员派生类的private成员
基类的protected成员派生类的protected成员派生类的protected成员派生类的private成员
基类的private成员在派生类中不可见在派生类中不可见在派生类中不可见

①基类的其他成员在子类的访问方式 == Min(成员在基类的访问限定符,继承方式),public > protected > private

这些继承方式可以根据具体的需求选择合适的方式

②基类private成员在派生类中无论以什么方式继承都是不可见的。这里的不可见是指基类的私有成员还是被继承到了派生类对象中,但是语法上限制派生类对象不管在类里面还是类外面都不能去访问它

例如:

//基类或父类
class Person
{
public:void Print(){cout << "name:" << _name << endl;cout << "age:" << _age << endl;}//保护成员
protected:string _name = "tutu";// 姓名int _age = 20;  //年龄//私有成员
private:string _tele = "123456";};//派生类或子类
class Student : public Person
{
public:void sPrint(){Person::Print();	//可以使用父类的公有成员}
protected:int _stuid; // 学号string _sname = _name;//可以访问父类的保护成员_namestring _stele = _tele; //不可以访问父类的私有成员_tele
};

结果如下:
在这里插入图片描述

上述父类Person中成员有三种访问限定分别是public、protected、private,而子类Student使用public继承父类,那么对于父类的公有成员在子类中的访问方式还是public,protected成员访问方式选择继承方式public和protected中较小的protected,同理父类的private成员继承到子类中也是选择private方式,在子类中不可访问

对于私有成员也是被继承到子类中,只是不可访问:

在这里插入图片描述

③基类private成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在派生类中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的。

④ 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式。

⑤在实际运用中一般使用都是public继承,几乎很少使用protetced/private继承,也不提倡使用protetced/private继承,因为protetced/private继承下来的成员都只能在派生类的类里面使用,实际中扩展维护性不强。

3.基类和派生类对象赋值转换

  • 派生类对象可以赋值给基类的对象 / 基类的指针 / 基类的引用。这里有个形象的说法叫切片或者切割。寓意把派生类中父类那部分切来赋值过去。

如下图所示:

在这里插入图片描述

  • 基类对象不能赋值给派生类对象

例如下面代码:

//父类
class Person
{
protected:string _name; // 姓名string _sex;  //性别int _age; // 年龄
};
//子类
class Student : public Person
{
public:int _No; // 学号
};
void Test()
{Student sobj;// 1.子类对象可以赋值给父类对象/指针/引用Person pobj = sobj;Person* pp = &sobj;Person& rp = sobj;//2.基类对象不能赋值给派生类对象sobj = pobj;//error
}

在这里插入图片描述

4.继承中的重定义(隐藏)

  • 在继承体系中基类和派生类都有独立的作用域。
  • 子类和父类中有同名成员,子类成员将屏蔽对父类同名成员的直接访问,这种情况叫隐藏,也叫重定义。

当一个类继承另一个类时,它可以重定义继承的成员函数或者成员变量。
需要注意的是如果是成员函数的隐藏,只需要函数名相同就构成隐藏。

  • 如果要访问被隐藏的父类的同名成员,可以在子类成员函数中,使用 父类::父类成员来显示访问

注意在实际中在继承体系里面最好不要定义同名的成员。

例如:

// Student的_num和Person的_num构成隐藏关系,可以看出这样代码虽然能跑,但是非常容易混淆
//父类
class Person
{
protected:string _name = "胡土土"; // 姓名int _num = 1234; // 身份证号
};//子类
class Student : public Person
{
public:void Print(){cout << " 姓名:" << _name << endl;cout << " 身份证号:" << Person::_num << endl;cout << " 学号:" << _num << endl;}
protected:int _num = 999; // 学号,与父类的_num重名构成隐藏
};void Test()
{Student s1;s1.Print();
};

结果如下:

在这里插入图片描述

我们发现当子类与父类有隐藏关系时,对于同名变量_num的调用,除非显示使用Person::_num 调用的是父类的成员变量,其他情况_num表示的都得子类中定义的变量,这是因为它们有不同的作用域,在子类中调用变量都是先从子类这个作用域中寻找。

再看下面的例子:

class A
{
public:void fun(){cout << "func()" << endl;}
};
class B : public A
{
public:void fun(int i){A::fun();cout << "func(int i)->" << i << endl;}
};void Test()
{B b;b.fun(10);
}

这里 B中的fun和A中的fun不是构成重载,因为不是在同一作用域
B中的fun和A中的fun构成隐藏,成员函数满足函数名相同就构成隐藏。

结果如下:

在这里插入图片描述
如果Test函数中:

void Test()
{B b;b.fun();//这里没有给参数
}

结果如下:

在这里插入图片描述

使用对象b调用fun()没有给参数,这样编译是不通过的,因为这样调用是调用的类B中的成员函数fun是需要传参的,如果要调用基类中的fun函数就必须显示调用,代码如下:

void Test()
{B b;b.A::fun();//显示调用A中的fun函数
}

结果如下:
在这里插入图片描述

5.派生类的默认成员函数

在这里插入图片描述

6个默认成员函数,“默认”的意思就是指我们不写,编译器会变我们自动生成一个,那么在派生类中,(先不考虑取地址重载)这几个成员函数是如何生成的呢?

例如如下父类:

//有如下Person父类
class Person
{
public:Person(const char* name = "tutu"): _name(name){cout << "Person()" << endl;}Person(const Person& p): _name(p._name){cout << "Person(const Person& p)" << endl;}Person& operator=(const Person& p){cout << "Person operator=(const Person& p)" << endl;if (this != &p)_name = p._name;return *this;}~Person(){cout << "~Person()" << endl;}
protected:string _name; // 姓名
};

✨构造函数

  • 派生类的构造函数必须调用基类的默认构造函数初始化基类的那一部分成员。如果基类没有默认的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用基类的构造函数。
//基于上面Person的派生类Student
class Student : public Person
{
protected:int _num; //学号
};
int main()
{Student s;return 0;
}

结果如下:
在这里插入图片描述

在这里插入图片描述

我们发现对于父类中的成员它会自动调用父类Person的默认构造函数与析构函数

  • 如果父类Person没有默认构造函数,那么我们就需要在初始化列表里显示调用父类的构造函数
    例如:
    在这里插入图片描述

当我们将基类的默认构造函数中的缺省值"tutu",去掉,它就不再是默认构造函数,那么在创建子类Student对象时就不会自动调用默认构造函数,会保错,那么这时我们就需要在初始化列表里显示调用

代码如下:

class Student : public Person
{
public:Student(const char* name, int num):Person(name)	//显示调用父类构造函数, _num(num){}	
protected:int _num; //学号
};int main()
{Student s("tutu", 111);;return 0;
}

结果如下:
在这里插入图片描述

还有一种显示调用情况:

在这里插入图片描述

这种情况是不可取的,这是因为规定在初始化列表中是不可以使用父类的成员的

✨拷贝构造

  • 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。

默认生成拷贝构造一般情况下够用,只有当子类成员涉及深拷贝时就必须自己实现拷贝构造

这里也可以自己显示实现一下拷贝构造:

class Student : public Person
{
public://构造函数Student(const char* name, int num):Person(name)	//显示调用父类构造函数, _num(num){}	//拷贝构造Student(const Student& st):Person(st)	//利用前面学习的基类与派生类的赋值转换,_num(st._num){}
protected:int _num; //学号
};

注意这里Person(st)中调用Person中的拷贝构造实现赋值兼容

✨赋值运算符重载

  • 派生类的operator=必须要调用基类的operator=完成基类的复制。

✨析构函数

  • 派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能保证派生类对象先清理派生类成员再清理基类成员的顺序。

如果自己显示写析构函数:

//析构函数
~Student()
{~Person();//这样写是错误的
}

因为多态的原因,析构函数的名字会被统一处理为destructor(),所以这里调用会构成隐藏,会循环调用,所以要指定作用域:

//析构函数
~Student()
{Person::~Person();cout << "~Student()" << endl;
}

但是我们发现Person的析构函数居然调用了两次:

在这里插入图片描述

这是因为析构函数具有特殊性,在子类析构函数调用完之后会自动调用父类的析构函数,所以即便是自己显示实现了子类的析构函数也不需要自己主动调用父类的析构函数

所以不需要自己主动调用父类的析构函数,否则会报错

其核心原因在于初始化时先构造父类再构造子类,而析构时先析构子类再析构父类,因为子类析构时是可能用到父类成员的,先父后子可能会出错

所以为了保证先析构子类再析构父类,编译器会在析构了子类后自动调用父类的析构函数

总结如下:

默认成员函数\子类成员内置成员自定义成员子类中的父类成员(整体)
默认生成的构造不做处理调用自定义类型的默认构造调用父类的默认构造
默认生成的拷贝构造值拷贝调用自定义类型的拷贝构造调用父类的拷贝构造
默认生成的赋值重载直接赋值调用自定义类型的赋值重载调用父类的赋值重载
默认生成的析构函数不做处理调用自定义类型的析构函数自动调用父类的析构函数

对于构造和析构:
派生类对象初始化先调用基类构造再调派生类构造。
派生类对象析构清理先调用派生类析构再调基类的析构

6.结语

继承可以分为公有继承(public inheritance)、保护继承(protected inheritance)和私有继承(private inheritance)。继承在C++中的应用非常广泛,可以用于构建复杂的类层次结构,提供代码的复用性和灵活性。但是,在使用继承时也需要注意避免多层次的继承导致的类关系复杂性增加,以及合理设计基类和派生类之间的关系。以上就是今天的所以内容啦~ 完结撒花~ 🥳🎉🎉

相关文章:

【C++深度探索】继承机制详解(一)

hello hello~ &#xff0c;这里是大耳朵土土垚~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#xff1a;大耳朵土土垚的博客 &#x1…...

力扣第218题“天际线问题”

在本篇文章中&#xff0c;我们将详细解读力扣第218题“天际线问题”。通过学习本篇文章&#xff0c;读者将掌握如何使用扫描线算法和堆来解决这一问题&#xff0c;并了解相关的复杂度分析和模拟面试问答。每种方法都将配以详细的解释&#xff0c;以便于理解。 问题描述 力扣第…...

帝国cms未审核文章可视化预览效果

有时候为了让编辑更加清楚的看到别人审核之后的效果&#xff0c;同时文章有需要下一级审核才能在前端展示出来&#xff0c;今天就来展示一个未审核文章预览审核后的效果 这次给某出版社开发的时候&#xff0c;他们需要实现编辑能够预览自己发布之后的审核效果&#xff0c;所以就…...

医院管理系统带万字文档医院预约挂号管理系统基于spingboot和vue的前后端分离java项目java课程设计java毕业设计

文章目录 仓库管理系统一、项目演示二、项目介绍三、万字项目文档四、部分功能截图五、部分代码展示六、底部获取项目源码带万字文档&#xff08;9.9&#xffe5;带走&#xff09; 仓库管理系统 一、项目演示 医院管理系统 二、项目介绍 基于springbootvue的前后端分离医院管…...

爬虫技术在物联网数据采集中的应用

爬虫技术在物联网数据采集中的应用案例主要包括以下几个方面&#xff1a; 电商平台数据采集&#xff1a;例如&#xff0c;使用Python编写的网络爬虫可以用于爬取京东网页相关数据&#xff0c;如品牌、标题、价格、店铺等&#xff0c;并进行数据处理及可视化展示。这种方法不仅可…...

spring boot初始化的几个总结

spring intializr File->New->Project 注意&#xff1a;Spring Initializer中 Java版本选择模块已经不支持1.8了。 Spring Boot 3.x要求 Java最低版本为17&#xff0c; 最新的SpringBoot版本已经要求Java22了 所以&#xff0c;你可以升级Java版本&#xff0c;使用Spri…...

springcloud第4季 seata报could not find any implementation for class

一 问题说明 1.1 描述 在使用seata2.0alibaba-cloud 2022.0.0.0-RC2nacos 2.2.3 模拟下订单分布式事务场景&#xff0c;出现如下问题&#xff1a;java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0 查看服务端&#xff1a;java.util.ServiceCo…...

IT之家最新科技热点

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…...

对象实例化过程

目录 一、Java对象实例化在JVM中的过程&#xff1a; 类加载与初始化 分配内存 初始化对象内存 设置对象头 执行初始化方法 构造方法执行 二、对象的创建过程 一、Java对象实例化在JVM中的过程&#xff1a; 类加载与初始化&#xff1a; 当JVM需要实例化一个对象时&#xff0c;它…...

常见漏洞之XSS

一、XSS简介 XSS&#xff08;Cross-Site Scripting&#xff0c;跨站脚本攻击&#xff09;是一种常见的网络攻击方式&#xff0c;通过在网页中注入恶意脚本&#xff0c;当其他用户浏览这些网页时&#xff0c;这些嵌入的恶意脚本会在其浏览器上执行&#xff0c;从而进行各种恶意…...

Python变量的命名规则与赋值方式

第二章&#xff1a;Python 基础语法 第一节&#xff1a;变量的命名规则与赋值方式 2.1.1 引言 在编程中&#xff0c;变量是存储数据的基本单元。变量的命名和赋值是编程语言中表达和操作数据的基础。了解和遵循变量命名规则对于编写清晰、可维护的代码至关重要。 2.1.2 变量…...

昇思25天学习打卡营第7天|网络构建

昇思25天学习打卡营第7天|网络构建 前言函数式自动微分函数与计算图微分函数与梯度计算Stop GradientAuxiliary data神经网络梯度计算 个人任务打卡&#xff08;读者请忽略&#xff09;个人理解与总结 前言 非常感谢华为昇思大模型平台和CSDN邀请体验昇思大模型&#xff01;从今…...

扩展阅读:什么是中断

如果用一句话概括操作系统的原理,那就是:整个操作系统就是一个中断驱动的死循环,用最简单的代码解释如下: while(true){doNothing(); } 其他所有事情都是由操作系统提前注册的中断机制和其对应的中断处理函数完成的。我们点击一下鼠标,敲击一下键盘,执行一个程序,…...

git 命令学习之branch 和 tag 操作

引言 在项目一个迭代过程结束之时&#xff0c;或是一个版本发布之后&#xff0c;我们要进行 新版本的开发&#xff0c;这时就需要对原来的项目代码进行封存&#xff0c;以及新项目代码的开始&#xff0c;这时就需要用到 branch 和 tag 操作。下面简单说说对这两个操作的理解。…...

如何理解 IEEE 754 单精度浮点型能表示的最小绝对值、最大绝对值

文章目录 解答最小绝对值最大绝对值总结 细节理解1. 为什么非规格化数的指数偏移量为126&#xff08;而不是127&#xff09;&#xff1f;规格化数与非规格化数非规格化数的指数偏移量非规格化数的尾数非规格化数的值示例 解答 IEEE 754单精度浮点数使用32位来表示一个数值&…...

LeetCode 算法:二叉树的右视图 c++

原题链接&#x1f517;&#xff1a;二叉树的右视图 难度&#xff1a;中等⭐️⭐️ 题目 给定一个二叉树的 根节点 root&#xff0c;想象自己站在它的右侧&#xff0c;按照从顶部到底部的顺序&#xff0c;返回从右侧所能看到的节点值。 示例 1: 输入: [1,2,3,null,5,null,4…...

Java 并发编程常见问题

1、线程状态它们之间是如何扭转的&#xff1f; 1、谈谈对于多线程的理解&#xff1f; 1、对于多核CPU&#xff0c;多线程可以提升CPU的利用率&#xff1b; 2、对于多IO操作的程序&#xff0c;多线程可以提升系统的整体性能及吞吐量&#xff1b; 3、使用多线程在一些场景下可…...

网络基础:静态路由

静态路由是一种由网络管理员手动配置的路由方式&#xff0c;用于在网络设备&#xff08;如路由器或交换机&#xff09;之间传递数据包。与动态路由不同&#xff0c;静态路由不会根据网络状态的变化自动调整。 不同厂商的网络设备在静态路由的配置上有些许差异&#xff1b;下面…...

库存管理系统基于spingboot vue的前后端分离仓库库存管理系统java项目java课程设计java毕业设计

文章目录 库存管理系统一、项目演示二、项目介绍三、部分功能截图四、部分代码展示五、底部获取项目源码&#xff08;9.9&#xffe5;带走&#xff09; 库存管理系统 一、项目演示 库存管理系统 二、项目介绍 基于spingboot和vue前后端分离的库存管理系统 功能模块&#xff…...

【ArcGIS AddIn插件】【可用于全国水旱灾害风险普查】全网最强洪水淹没分析插件-基于8邻域种子搜索算法-有源淹没分析算法

最近有很多GIS小伙伴咨询我关于基于8邻域种子搜索算法的有源淹没分析插件的使用方法及原理&#xff0c;咱们通过这篇文章给大家详细介绍下这款插件的运行机制。 一、插件类型及适用版本 本插件属于ArcGIS AddIn工具条插件&#xff0c;基于ArcGIS Engine10.2.2的开发环境开发的&…...

微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】

微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来&#xff0c;Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)

本文把滑坡位移序列拆开、筛优质因子&#xff0c;再用 CNN-BiLSTM-Attention 来动态预测每个子序列&#xff0c;最后重构出总位移&#xff0c;预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵&#xff08;S…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险

C#入门系列【类的基本概念】&#xff1a;开启编程世界的奇妙冒险 嘿&#xff0c;各位编程小白探险家&#xff01;欢迎来到 C# 的奇幻大陆&#xff01;今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类&#xff01;别害怕&#xff0c;跟着我&#xff0c;保准让你轻松搞…...

Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么&#xff1f;它的作用是什么&#xff1f; Spring框架的核心容器是IoC&#xff08;控制反转&#xff09;容器。它的主要作用是管理对…...

如何配置一个sql server使得其它用户可以通过excel odbc获取数据

要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据&#xff0c;你需要完成以下配置步骤&#xff1a; ✅ 一、在 SQL Server 端配置&#xff08;服务器设置&#xff09; 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到&#xff1a;SQL Server 网络配…...

快速排序算法改进:随机快排-荷兰国旗划分详解

随机快速排序-荷兰国旗划分算法详解 一、基础知识回顾1.1 快速排序简介1.2 荷兰国旗问题 二、随机快排 - 荷兰国旗划分原理2.1 随机化枢轴选择2.2 荷兰国旗划分过程2.3 结合随机快排与荷兰国旗划分 三、代码实现3.1 Python实现3.2 Java实现3.3 C实现 四、性能分析4.1 时间复杂度…...