解锁C++多态的魔力:灵活与高效的编码艺术(上)

文章目录
- 前言
- 🌸一、多态的定义与概念
- 🌻1.1 多态的核心思想:
- 🌻1.2 多态的两种主要形式:
- 🌸二、多态的使用条件
- 🌻2.1 基类指针或引用
- 2.1.1 为什么需要基类指针或引用
- 🌻2.2 虚函数(virtual function)
- 2.2.1 虚函数的定义和基本特性
- 2.2.2 如何定义虚函数
- 总结
- 🌻2.3 重写虚函数(Override virtual function)
- 2.3.1 虚函数重写的三大条件
- 2.3.2 虚函数重写的两个例外
- 🌻2.4 虚析构函数(Virtual Destructor)的重写
- 2.4.1 为什么需要虚析构函数?
- 2.4.2 使用虚析构函数
- 2.4.3 虚析构函数的注意事项
- 总结
- 🌻2.5 C++11的override和final
- 2.5.1 `override` 关键字
- 2.5.2 `final` 关键字
- 🌻2.6 重载、覆盖(重写)、隐藏(重定义)的对比
- 🌸三、抽象类
- 🌻3.1 抽象类的定义
- 🌻3.2 抽象类的特点:
- 结语
前言
多态性是面向对象编程的重要特性之一,而C++通过虚函数、继承等机制实现了这一强大的功能。多态性使得代码更加灵活和可扩展,允许不同类型的对象以统一的方式进行操作。在本篇文章中,我们将深入探讨C++中多态的实现原理、使用场景及其优劣势,并通过具体代码示例展示如何利用多态来提升代码的可维护性和复用性。
🌸一、多态的定义与概念
**多态(Polymorphism)**是面向对象编程中的一个重要概念,字面意思是“多种形态”。在编程中,多态指的是使用相同的接口或方法名来操作不同类型的对象,从而实现不同的行为。它允许一个接口在不同的上下文中表现出不同的行为,增加了程序的灵活性和可扩展性。
🌻1.1 多态的核心思想:
多态性使得一个基类可以定义统一的接口,而不同的子类则提供具体的实现。在程序运行时,可以根据对象的实际类型选择调用适当的函数实现。这样做可以通过相同的代码处理不同类型的对象,而不必显式地指定它们的类型。
🌻1.2 多态的两种主要形式:
- 编译时多态(静态多态):通过函数重载和运算符重载来实现,编译器在编译时决定调用哪个函数。这种多态是在编译阶段确定的,因此被称为静态多态。
- 例如:函数重载、运算符重载。
- 运行时多态(动态多态):通过虚函数和继承来实现,程序在运行时根据对象的实际类型决定调用哪个函数。这种多态是在运行时确定的,因此被称为动态多态。
- 例如:虚函数、接口实现。
🌸二、多态的使用条件
🌻2.1 基类指针或引用
在C++的多态性中,基类指针或引用是实现多态调用的关键。通过基类指针或引用指向派生类对象,可以在运行时调用派生类的重写方法,而不依赖于对象的静态类型。这种方式称为运行时多态或动态多态。
2.1.1 为什么需要基类指针或引用
在C++中,如果直接使用派生类对象,即使它重写了基类的虚函数,编译器仍然会使用静态绑定,即在编译时确定调用的函数版本。而使用基类指针或引用时,C++会使用动态绑定(通过虚函数表)来决定在运行时调用派生类的版本。这是多态的核心机制。
【示例代码】
以下是一个使用基类指针或引用实现多态的简单示例:
#include <iostream>class Animal {
public:virtual void sound() const { // 基类中的虚函数std::cout << "Some generic animal sound" << std::endl;}virtual ~Animal() = default; // 虚析构函数
};class Dog : public Animal {
public:void sound() const override { // 派生类中重写 sound 方法std::cout << "Woof" << std::endl;}
};class Cat : public Animal {
public:void sound() const override { // 另一个派生类中重写 sound 方法std::cout << "Meow" << std::endl;}
};void makeSound(const Animal& animal) { // 基类引用,支持多态animal.sound(); // 动态绑定,根据实际对象类型调用派生类的方法
}int main() {Dog dog;Cat cat;// 使用基类引用,触发多态makeSound(dog); // 输出:WoofmakeSound(cat); // 输出:Meow// 使用基类指针,也可以实现多态Animal *animalPtr = new Dog();animalPtr->sound(); // 输出:Woofdelete animalPtr;return 0;
}
【代码分析】
- 基类中的虚函数:
Animal类中的sound方法是虚函数,允许在派生类中重写。 - 基类指针或引用:
makeSound函数接受一个Animal的引用,而不是具体的Dog或Cat对象,使其能够调用不同的sound实现。 - 动态绑定:在
main函数中,通过基类引用和指针来调用派生类的sound方法,输出的是实际派生类的结果。
🌻2.2 虚函数(virtual function)
在C++中,虚函数(virtual function) 是一种特殊的成员函数,通过它可以实现运行时多态。虚函数允许基类的指针或引用在运行时根据对象的实际类型调用派生类的重写方法,而不仅仅局限于基类的实现。这种机制在面向对象设计中非常重要,尤其在抽象接口、工厂模式等设计模式中广泛应用。
2.2.1 虚函数的定义和基本特性
- 虚函数是在基类中用关键字
virtual声明的成员函数。 - 虚函数可以在派生类中被重写(override),并在运行时决定调用派生类的重写方法。
- 虚函数必须通过基类指针或引用来调用,才能触发多态行为。
2.2.2 如何定义虚函数
虚函数在基类中声明时加上 virtual 关键字即可。推荐使用override关键字在派生类中重写虚函数,便于编译器检查是否正确地进行了重写。
[示例代码]
以下是一个虚函数的简单示例:
#include <iostream>class Animal {
public:virtual void sound() const { // 基类中的虚函数std::cout << "Some generic animal sound" << std::endl;}
};class Dog : public Animal {
public:void sound() const override { // 派生类中重写 sound 方法std::cout << "Woof" << std::endl;}
};class Cat : public Animal {
public:void sound() const override { // 另一个派生类中重写 sound 方法std::cout << "Meow" << std::endl;}
};void makeSound(const Animal &animal) { // 基类引用,支持多态animal.sound(); // 动态绑定,根据实际对象类型调用派生类的方法
}int main() {Dog dog;Cat cat;makeSound(dog); // 输出:WoofmakeSound(cat); // 输出:Meowreturn 0;
}
【代码解析】
- 基类声明虚函数:
Animal类中的sound方法声明为虚函数,因此派生类可以重写该方法。 - 派生类重写虚函数:
Dog和Cat类分别重写了sound方法,提供了各自的实现。 - 多态调用:
makeSound函数接受Animal类型的引用作为参数,在运行时会根据传入对象的实际类型调用相应的sound实现,输出Woof或Meow。
【注意事项】
- 构造函数不能是虚函数:构造函数不支持
virtual关键字,因为对象在构造时还未完成初始化。 - 静态成员函数不能是虚函数:静态成员函数不依赖于对象,无法实现多态。
- 基类指针或引用:虚函数的多态性只能通过基类的指针或引用来调用,如果直接使用派生类对象,则编译时会使用静态绑定。
总结
- 虚函数实现了C++的多态机制,允许基类指针或引用在运行时动态选择合适的派生类实现。
- 虚函数表支持动态绑定,通过表中指针定位到实际调用的函数。
虚函数使得代码在结构上更加灵活,提升了程序设计的可扩展性。
🌻2.3 重写虚函数(Override virtual function)
2.3.1 虚函数重写的三大条件
虚函数的重写(覆盖):派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的返回值类型、函数名字、参数列表完全相同),称子类的虚函数重写了基类的虚函数。
class Person
{
public:virtual void BuyTicket() const//虚函数{cout << "买全价票" << endl;}
};class Student : public Person
{
public:virtual void BuyTicket() const//虚函数{cout << "买半价票" << endl;}
};void Func(const Person& people)
{people.BuyTicket();
}int main()
{Func(Person()); //普通人Func(Student()); //学生return 0;
}
在重写基类虚函数时,派生类的虚函数在不加 virtual 关键字时,虽然也可以构成重写(因为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性),但是该种写法不是很规范,不建议这样使用。
2.3.2 虚函数重写的两个例外
在C++中,虚函数重写存在两个例外情况,即使满足了通常的虚函数重写条件,也不会被认为是对基类虚函数的重写。这两个例外是:
- 参数默认值不参与重写
在C++中,虚函数的重写不会受到参数默认值的影响,即使在基类的虚函数中定义了默认参数值,派生类重写时也可以选择不同的默认值。但是,当调用虚函数时,默认参数值总是根据指针或引用的静态类型确定,而不是动态类型。这意味着默认参数值在多态调用中不会变化。
示例:
#include <iostream>class Base {
public:virtual void printMessage(int times = 1) const { // 基类虚函数,默认值为1for (int i = 0; i < times; ++i)std::cout << "Base message" << std::endl;}
};class Derived : public Base {
public:void printMessage(int times = 3) const override { // 重写时设置默认值为3for (int i = 0; i < times; ++i)std::cout << "Derived message" << std::endl;}
};int main() {Base *ptr = new Derived();ptr->printMessage(); // 输出1次,因为默认值取自Base类delete ptr;return 0;
}
解释:虽然Derived类为printMessage方法设置了默认值3,但在多态调用时,默认值取决于基类Base的定义(即1),因为编译器在静态类型为Base时就已确定默认值。
- 返回类型的协变限制
虽然C++支持协变返回类型(即派生类的重写函数可以返回一个更具体的类型),但协变限制仅限于指针或引用类型。如果基类的虚函数返回非指针或非引用类型,派生类不能重写该虚函数并更改返回类型。
示例:
#include <iostream>class Base {
public:virtual int getValue() const { // 基类虚函数返回int类型return 42;}
};class Derived : public Base {
public:// 错误:无法重写并更改返回类型// double getValue() const override {// return 3.14;// }
};
解释:Base类的getValue函数返回int类型。即使Derived类想返回double,这种重写是不允许的,因为返回类型不是指针或引用,违反了协变的限制。
🌻2.4 虚析构函数(Virtual Destructor)的重写
在C++中,虚析构函数(Virtual Destructor)是一种特殊的析构函数,通过在基类中将析构函数声明为虚函数,可以确保在通过基类指针删除派生类对象时,派生类的析构函数被正确调用。这在涉及多态和动态内存管理时尤为重要,可以有效避免内存泄漏和资源未正确释放的问题。
2.4.1 为什么需要虚析构函数?
当基类指针指向派生类对象时,如果删除对象时基类的析构函数不是虚函数,那么调用的仅仅是基类的析构函数,而不会调用派生类的析构函数。这样,派生类中分配的资源就无法释放,导致内存泄漏或其他资源管理问题。
示例
以下是一个不使用虚析构函数的例子,演示潜在的内存泄漏问题:
#include <iostream>class Base {
public:~Base() { // 非虚析构函数std::cout << "Base destructor called" << std::endl;}
};class Derived : public Base {
public:~Derived() { // 派生类析构函数std::cout << "Derived destructor called" << std::endl;}
};int main() {Base* obj = new Derived();delete obj; // 仅调用 Base 的析构函数,不调用 Derived 的析构函数return 0;
}
输出
Base destructor called
解释:在删除obj时,由于基类的析构函数不是虚函数,因此只调用了Base的析构函数,没有调用Derived的析构函数。派生类中可能分配的资源未被释放,导致潜在的内存泄漏。
2.4.2 使用虚析构函数
通过将基类的析构函数声明为虚函数,可以确保正确调用派生类的析构函数,避免内存泄漏问题:
#include <iostream>class Base {
public:virtual ~Base() { // 虚析构函数std::cout << "Base destructor called" << std::endl;}
};class Derived : public Base {
public:~Derived() override { // 重写析构函数std::cout << "Derived destructor called" << std::endl;}
};int main() {Base* obj = new Derived();delete obj; // 正确调用 Derived 和 Base 的析构函数return 0;
}
输出:
Derived destructor called
Base destructor called
解释:在delete obj时,虚析构函数确保先调用Derived的析构函数,然后调用Base的析构函数,资源得到正确释放。
2.4.3 虚析构函数的注意事项
- 虚析构函数的必要性:任何含有虚函数的基类都应定义虚析构函数,以确保派生类对象通过基类指针删除时能够正确析构。
- 性能影响:虚析构函数会引入一定的性能开销(如虚函数表查找)。但对于具有多态需求的类,这是一个合理的取舍。
- 纯虚析构函数:基类析构函数也可以定义为纯虚函数,用于将类设计为抽象基类,但必须提供函数体,因为析构函数始终需要可执行代码。
class AbstractBase {
public:virtual ~AbstractBase() = 0; // 纯虚析构函数
};AbstractBase::~AbstractBase() {} // 提供析构函数体
总结
- 虚析构函数确保通过基类指针删除派生类对象时正确调用派生类的析构函数,避免内存泄漏。
- 基类析构函数声明为虚函数是实现多态的良好实践,尤其当基类有其他虚函数时。
- 纯虚析构函数可用来定义抽象基类,但仍需提供函数体。
🌻2.5 C++11的override和final
在C++中,override和final是C++11引入的两个关键字,主要用于类的继承和虚函数的管理。它们在面向对象编程中用于提高代码的安全性和可读性,确保虚函数的正确性和防止意外的重写。
2.5.1 override 关键字
override 关键字用于显式声明一个函数是从基类中**重写(override)**的虚函数。它能够帮助编译器检查函数是否确实重写了基类中的虚函数。如果函数签名不匹配(比如返回类型不同或参数不同),编译器会报错。
使用override的主要好处是:
- 增加代码的可读性,表明该函数是重写基类中的函数。
- 提供编译期检查,避免因为函数签名不匹配导致的隐藏错误。
示例:
class Base {
public:virtual void display() const {std::cout << "Base display" << std::endl;}
};class Derived : public Base {
public:void display() const override { // 正确重写了基类的 display 函数std::cout << "Derived display" << std::endl;}
};
如果你误写了函数签名,比如忘记了 const 修饰符:
class Derived : public Base {
public:void display() override { // 错误,没有 const 修饰符std::cout << "Derived display" << std::endl;}
};
编译器会报错,因为你没有正确重写基类的函数。
2.5.2 final 关键字
final 关键字用于两种情况:
- 防止类被继承:当你不希望某个类再被继承时,可以将这个类标记为
final。 - 防止虚函数被重写:当你不希望派生类重写某个虚函数时,可以将该虚函数标记为
final。
示例1:防止类被继承
class FinalClass final {// 该类不能再被继承
};// 下面的代码会导致编译错误
class DerivedClass : public FinalClass {// 错误:FinalClass 被标记为 final,不能被继承
};
示例2:防止虚函数被重写
class Base {
public:virtual void display() const {std::cout << "Base display" << std::endl;}
};class Derived : public Base {
public:void display() const final { // 这个函数不能再被派生类重写std::cout << "Derived display" << std::endl;}
};// 下面的代码会导致编译错误
class MoreDerived : public Derived {
public:void display() const override { // 错误:Derived::display 被标记为 final,不能被重写std::cout << "MoreDerived display" << std::endl;}
};
总结:
override:用于确保你正在重写基类中的虚函数,提供编译期检查。final:用于防止类被继承或者虚函数被重写。
这两个关键字提高了代码的安全性,避免继承或虚函数重写中的常见错误。
🌻2.6 重载、覆盖(重写)、隐藏(重定义)的对比

🌸三、抽象类
在C++中,抽象类是一种不能直接实例化的类,通常作为其他类的基类,目的是为子类提供接口定义。抽象类至少包含一个纯虚函数(pure virtual function),这是抽象类的核心特征。
🌻3.1 抽象类的定义
抽象类的定义中包含纯虚函数,纯虚函数的声明形式为:
virtual 返回类型 函数名(参数列表) = 0;
这个 = 0 表示该函数是纯虚函数,必须在派生类(子类)中实现。
以下是一个抽象类的简单例子:
#include <iostream>
using namespace std;// 定义抽象类 Shape
class Shape {
public:// 纯虚函数virtual void draw() = 0;virtual double area() = 0;
};// 定义派生类 Circle
class Circle : public Shape {
private:double radius;
public:Circle(double r) : radius(r) {}// 实现抽象类中的纯虚函数void draw() override {cout << "Drawing a Circle" << endl;}double area() override {return 3.14159 * radius * radius;}
};// 定义派生类 Rectangle
class Rectangle : public Shape {
private:double width, height;
public:Rectangle(double w, double h) : width(w), height(h) {}// 实现抽象类中的纯虚函数void draw() override {cout << "Drawing a Rectangle" << endl;}double area() override {return width * height;}
};int main() {Shape* shape1 = new Circle(5.0); // 创建Circle对象Shape* shape2 = new Rectangle(4.0, 6.0); // 创建Rectangle对象shape1->draw(); // 调用Circle的draw方法cout << "Area: " << shape1->area() << endl; // 调用Circle的area方法shape2->draw(); // 调用Rectangle的draw方法cout << "Area: " << shape2->area() << endl; // 调用Rectangle的area方法delete shape1;delete shape2;return 0;
}
- Shape 是一个抽象类,它包含两个纯虚函数
draw()和area()。 - Circle 和 Rectangle 是从 Shape 派生的类,它们实现了抽象类中的纯虚函数。
- 在
main()函数中,定义了两个指向抽象类的指针shape1和shape2,分别指向Circle和Rectangle对象,并调用了它们的具体实现。
🌻3.2 抽象类的特点:
- 不能直接实例化抽象类对象。例如
Shape不能直接创建对象。 - 抽象类中的纯虚函数必须在派生类中实现,否则派生类也会变成抽象类。
- 抽象类可以有数据成员和普通成员函数,但如果有纯虚函数,则它仍然是抽象类。
结语
通过对C++多态性的深入了解,我们可以更好地编写具有高扩展性和灵活性的代码。多态不仅让代码变得更具适应性,还能够减少代码重复,提高维护效率。在未来的开发中,合理运用多态将为我们的项目带来显著的提升。希望本文的讲解能够帮助读者在实践中更好地掌握这一重要概念。

今天的分享到这里就结束啦!如果觉得文章还不错的话,可以三连支持一下,17的主页还有很多有趣的文章,欢迎小伙伴们前去点评,您的支持就是17前进的动力!

相关文章:
解锁C++多态的魔力:灵活与高效的编码艺术(上)
文章目录 前言🌸一、多态的定义与概念🌻1.1 多态的核心思想:🌻1.2 多态的两种主要形式: 🌸二、多态的使用条件🌻2.1 基类指针或引用2.1.1 为什么需要基类指针或引用 🌻2.2 虚函数&am…...
k8s系列-Rancher 上操作的k8s容器网络配置总结
Rancher 上操作的k8s容器网络配置总结 要在 Rancher 中配置Spring Boot 应用 ykhd-zhjgyw-xpwfxfjfl 服务,正确的配置方式如下: 1. 应用程序监听端口 在 application.yaml 文件中,配置的应用监听端口是 10001,并且应用的上下文…...
2024年【氯化工艺】考试题库及氯化工艺考试内容
题库来源:安全生产模拟考试一点通公众号小程序 氯化工艺考试题库根据新氯化工艺考试大纲要求,安全生产模拟考试一点通将氯化工艺模拟考试试题进行汇编,组成一套氯化工艺全真模拟考试试题,学员可通过氯化工艺考试内容全真模拟&…...
从commit校验失效问题探究husky原理
一、背景 之前创建的项目,发现代码 commit 提交的时候没有了任何校验,具体表现: 一是 feat fix 等主题格式校验没有了二是代码 lint 不通过也能提交 尝试解决这个问题,并深入了解husky的实现原理,将相关的一些知识点…...
Azure OpenAI 服务上线具有音频和语音功能的 GPT-4o-Realtime-Preview,免费申请试用
微软宣布 GPT-4o-Realtime-Preview 音频和语音公开预览版的推出,这是对Microsoft Azure OpenAI 服务的重大增强,增加了高级语音功能并扩展了 GPT-4o 的多模式产品。 这一里程碑进一步巩固了 Azure 在人工智能领域的领导地位,尤其是在语音技术…...
基于IMX6UL的EPIT的定时器实验
定时器是最常用的外设,常常需要使用定时器来完成精准的定时功能,I.MX6U 提供了多 种硬件定时器,有些定时器功能非常强大。本章我们从最基本的 EPIT 定时器开始,学习如何配置EPIT 定时器,使其按照给定的时间,…...
FreeMarker模板引擎入门:从基础到实践的全面指南
前言 什么是FreeMarker FreeMarker是一个基于模板生成文本输出的通用工具,它使用纯Java编写,能够生成HTML、XML、JSON、RTF、Java源代码等多种格式的文本。FreeMarker模板引擎允许将数据模型与模板文件结合,生成动态的文本输出,广…...
YOLOv8模型改进 第十讲 添加全维度动态卷积(Omni-dimensional Dynamic Convolution,ODConv)
本篇文章将介绍一种全新的改进机制——全维度动态卷积ODConv,并展示其在YOLOv8中的实际应用。现全维动态卷积(Omni-dimensional Dynamic Convolution,ODConv)是一种先进的动态卷积设计,旨在通过引入多维注意力机制来提…...
【环境搭建】远程服务器搭建ElasticSearch
参考: 非常详细的阿里云服务器安装ElasticSearch过程..._阿里云服务器使用elasticsearch-CSDN博客 服务器平台:AutoDL 注意: 1、切换为非root用户,su 新用户名,否则ES无法启动 2、安装过程中没有出现设置账号密码…...
机器学习与神经网络:诺贝尔物理学奖的新篇章
机器学习与神经网络:诺贝尔物理学奖的新篇章 引言 近日,2024年诺贝尔物理学奖颁发给了机器学习与神经网络领域的研究者,这是历史上的首次。诺贝尔物理学奖通常授予在自然现象和物理物质研究方面做出重大贡献的科学家。然而,今年…...
倍福TwinCAT程序中遇到的bug
文章目录 问题描述:TwinCAT嵌入式控制器CX5140在上电启动后,X001网口接网线通讯灯不亮,软件扫描不到硬件网口 解决方法:硬件断电重启后,X001网口恢复正常 问题描述:TwinCAT软件点击激活配置后,…...
R语言实现logistic回归曲线绘制
方式一:编制函数 x<-rnorm(10000)#设置随机种子 #编写绘图函数代码快 f <- function(x){y 1/(1 exp(-x))plot(x,y)}#sigmoid函数 f(x) 方式二:Sigmoid函数代码 x<-rnorm(10000)#设置随机种子 #编写绘图函数代码块 #y<-1/(1exp(-x)) y&…...
零宽字符(ZWSP)
前言 一个“所见非所得”的问题,示例如下: 查看原始DOM发现存在特殊字符: zero-width-space(ZWSP) 零宽空格是一种不可打印的Unicode字符,用于可能需要换行处。 在HTML中,零宽空格可以替代标…...
作业 定时发送邮件
[rootlocalhost zyc]# date -s 12:28 2024年 10月 15日 星期二 12:28:00 CST [rootlocalhost zyc]# vim /etc/chrony.conf [rootlocalhost zyc]# systemctl restart chronyd [rootlocalhost zyc]# date 2024年 10月 15日 星期二 12:36:00 CST [rootlocalhost zyc]# chronyc s…...
【排序】——2.快速排序法(含优化)
快速排序法 递归法 霍尔版本(左右指针法) 1.思路 1、选出一个key,一般是最左边或是最右边的。 2、定义一个begin和一个end,begin从左向右走,end从右向左走。(需要注意的是:若选择最左边的数据作为key,则…...
AnaTraf | 网络分析系统:高效IT运维工具
目录 什么是网络分析系统? 网络分析系统的核心功能 二、网络分析系统在IT运维中的重要性 案例分析:如何快速应对网络拥塞 技巧分享:如何使用网络分析系统优化带宽 网络分析系统的部署与最佳实践 确定监控范围与关键设备 分析结果的可…...
踩坑日记:线上接口超时问题排查
1.背景: 上线后,功能测试. 进入小程序页面发现很慢,耗时超过5秒,打开skywalking发现大量接口耗时都很高. 2.top命令 服务器top命令查看cpu资源发现占用并不高 3.mysql查看sql运行情况 # 当前运行的所有事务 select * from information_schema.innodb_trx; 1 | …...
C语言中的段错误(Segmentation Fault):底层原理及解决方法
引言 在C语言编程中,“段错误”(通常由操作系统信号 SIGSEGV 触发)是一种常见的异常情况,它表明程序试图访问不受保护的内存区域。本文将深入探讨段错误的原因、底层原理、常见情况以及如何调试和解决这类错误。 段错误的定义 …...
1.两数之和 暴力枚举和暴力搜索法
1. 两数之和 已解答 简单 相关标签 相关企业 提示 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。 你可以假设每种输入只会对应一个答案,并且你不能使用两次相…...
你的收入达到了缴纳个人所得税的标准了吗?
在现代社会,个人所得税作为一种重要的税收形式,已经渗透到了我们每个人的日常生活中。它不仅关乎国家的财政收入,更与每个纳税人的切身利益息息相关。那么,你是否真正了解个人所得税的缴纳标准、计算方法以及相关的税收优惠政策呢…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...
基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...
【Linux】自动化构建-Make/Makefile
前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...
