C++三大特性——继承性(超万字详解)

news2024/9/23 15:26:06

目录

前言

一、封装

1. 封装(Encapsulation)

二、继承

1. 构造函数的调用顺序

原理:

2. 析构函数的调用顺序

原理:

3、派生类的隐藏 

1. 成员函数隐藏

2. 成员变量隐藏

3. 基类函数的重载隐藏

三、多重继承问题

1. 构造函数的调用顺序

2. 析构函数的调用顺序

3. 多重继承中的命名冲突

4. 菱形继承问题(Diamond Problem)

四、虚继承

1. 菱形继承问题(Diamond Problem)

2. 虚继承解决菱形继承问题

3. 虚基类表(Virtual Base Table,VBTBL)

虚基类表的主要功能:

4. 虚基类指针(Virtual Base Pointer,VBPTR)

虚基类指针的主要功能:

5. 虚基类表和虚基类指针的工作机制

6. 虚继承的内部工作过程

 五、虚继承问题例子

1、实例        

2. 虚基类指针(VBPtr)的生成

3. FinalDerived的继承情况

4. 虚基类指针如何工作

虚基类指针的作用:


前言

    在C++中,三大特性通常是指面向对象编程(OOP)的三大基本特性,它们是 封装(Encapsulation)继承(Inheritance)多态(Polymorphism)。本文重点讲述继承性,也简单介绍一些封装性。

一、封装

       

1. 封装(Encapsulation)

  • 定义:封装是将数据(成员变量)和操作数据的方法(成员函数)结合在一起,组成一个类,从而实现对数据的隐藏和保护。
  • 目的:通过封装,类的内部细节对外部隐藏,外部只能通过类提供的公有接口(如public的成员函数)来访问和操作内部数据。这种数据隐藏和访问控制机制,增强了程序的安全性和可维护性。
  • 实现
    • 数据成员通常声明为私有的(private),只有通过公共成员函数(如gettersetter)才能访问。
    • 通过访问控制符(publicprotectedprivate)来控制类的成员访问权限。
class Person {
private:
    std::string name;
    int age;

public:
    void setName(std::string newName) {
        name = newName;
    }

    std::string getName() {
        return name;
    }
};

        像上面这个代码体现了C++中的封装,他将函数,变量放入了一个类当中,作为了类的成员,像我们之前用的友元函数就破坏了封装,使得外部函数能够调用类中的成员。

二、继承

        是指,一个新的类继承/获取已存在的一个类或多个类的属性和行为

若一个类继承其他的一个类,称为单一继承,如果一个类继承其他多个类,称为多继承

当类B继承类A后:

称类A为父类,或者基类

称类B为子类,或者派生类

         那么如果你了解类的结构的话,应该知道,类当中每个成员都有对应的权限,当一个类继承了另一个类的时候,这些对应成员权限继承之后,在子类当中应该是什么权限呢?

        其实,我们在继承类的时候,也有一个继承方式,是按照public(公共),protected(保护),private(私有),这三中方式来进行继承,但是在父类当中的成员来说,他们也有自己的权限,其中的继承方式如下:

类的成员访问权限:

1、public:公有权限,类中、类外、子类都可以访问

2、protected:受保护权限,类中、子类中能够访问,类外不能访问

3、private:私有权限,类中能够访问,类外、子类都不能访问

继承方式:也有3种

1、public继承方式:基类的成员是什么权限,继承到派生类也是对应权限(除了private)

        a、基类中public的成员,继承到派生类中public下

        b、基类中protected的成员,继承到派生类中protected下

        c、基类中private的成员,虽然继承到派生类,但是子类无法访问(没有继承到private下)

2、protected继承方式:基类的权限会提高到protected(除了private)

        a、基类中public的成员,继承到派生类中protected下

        b、基类中protected的成员,继承到派生类中protected下

        c、基类中private的成员,虽然继承到派生类,但是子类无法访问(没有继承到private下)

3、private继承方式:基类的权限会提高到private(除了private)

        a、基类中public的成员,继承到派生类中private下

        b、基类中protected的成员,继承到派生类中private下

        c、基类中private的成员,虽然继承到派生类,但是子类无法访问(没有继承到private下)

 基类和派生的关系

        派生类会继承基类的所有成员,除了(基类的构造函数、析构函数);基类的private成员继承到派生类,但是派生类无法访问,如果一定要访问基类的私有成员,基类要有对应的接口函数    

  • 基类的私有成员是派生类无法直接访问的。这是为了实现面向对象编程中的封装性,保证基类的私有数据不被外界(包括派生类)随意修改或访问。
  • 如果派生类确实需要访问基类的私有成员,通常基类会提供公共或受保护的接口函数
class Base {
private:
    int privateData;

protected:
    int getPrivateData() {
        return privateData;  // 基类提供受保护的接口函数
    }

public:
    void setPrivateData(int data) {
        privateData = data;  // 基类提供公共的接口函数
    }
};

class Derived : public Base {
public:
    void printPrivateData() {
        // 可以通过基类的公有或受保护函数访问私有成员
        std::cout << "Private data: " << getPrivateData() << std::endl;
    }
};

int main() {
    Derived d;
    d.setPrivateData(42);  // 通过公有接口访问私有成员
    d.printPrivateData();  // 输出:Private data: 42
    return 0;
}

 派生类不会继承基类的构造函数和析构函数,如下:

class Base {
public:
    Base(int x) {  // 基类的构造函数
        std::cout << "Base constructor called with " << x << std::endl;
    }
};

class Derived : public Base {
public:
    Derived(int y) : Base(y) {  // 派生类通过初始化列表调用基类构造函数
        std::cout << "Derived constructor called" << std::endl;
    }
};

int main() {
    Derived d(10);  // 输出:Base constructor called with 10
                    // 输出:Derived constructor called
    return 0;
}

1. 构造函数的调用顺序

当实例化一个派生类对象时,系统会按照以下顺序调用构造函数:

  • 基类的构造函数先被调用,负责初始化基类的成员。
  • 然后调用派生类的构造函数,负责初始化派生类的成员。
原理:
  • 在实例化派生类时,基类的构造函数必须首先运行,因为派生类的对象本质上是一个扩展的基类对象。如果基类没有正确初始化,派生类无法保证其功能的正确性。
  • 如果派生类的构造函数没有显式调用基类的构造函数,则默认会调用基类的默认构造函数(如果有)。
  • 可以通过派生类的构造函数的初始化列表来显式指定调用哪个基类的构造函数。
#include <iostream>
using namespace std;

class Base {
public:
    Base() {
        cout << "Base constructor called" << endl;
    }
    Base(int x) {
        cout << "Base constructor with argument " << x << " called" << endl;
    }
    ~Base() {
        cout << "Base destructor called" << endl;
    }
};

class Derived : public Base {
public:
    Derived() : Base(10) {  // 在初始化列表中显式调用基类的构造函数
        cout << "Derived constructor called" << endl;
    }
    ~Derived() {
        cout << "Derived destructor called" << endl;
    }
};

int main() {
    Derived d;  // 实例化派生类对象
    return 0;
}

2. 析构函数的调用顺序

析构函数的调用顺序与构造函数的顺序相反

  • 首先调用派生类的析构函数,释放派生类对象的资源。
  • 然后调用基类的析构函数,负责清理基类的资源。
原理:
  • 当销毁一个派生类对象时,派生类的资源先被释放,因为派生类的成员依赖基类对象的成员。
  • 只有当派生类对象的析构函数执行完毕后,基类的析构函数才会被调用,确保所有成员都正确销毁。
class Base {
public:
    Base() {
        cout << "Base constructor called" << endl;
    }
    ~Base() {
        cout << "Base destructor called" << endl;
    }
};

class Derived : public Base {
public:
    Derived() {
        cout << "Derived constructor called" << endl;
    }
    ~Derived() {
        cout << "Derived destructor called" << endl;
    }
};

int main() {
    Derived d;  // 实例化派生类对象
    return 0;
}

3、派生类的隐藏 

1. 成员函数隐藏

        如果派生类中的成员函数与基类的成员函数同名,即使参数不同,基类中的函数也会被隐藏,而不是重载。为了调用基类中的同名成员函数,需要使用作用域运算符::)来显式调用基类的版本。

#include <iostream>
using namespace std;

class Base {
public:
    void display() {
        cout << "Base class display" << endl;
    }
    void display(int x) {
        cout << "Base class display with argument: " << x << endl;
    }
};

class Derived : public Base {
public:
    void display() {
        cout << "Derived class display" << endl;
    }
};

int main() {
    Derived d;

    d.display();  // 调用派生类的 display 函数
    // d.display(10);  // 错误!派生类隐藏了基类的所有同名函数

    // 显式调用基类的函数
    d.Base::display(10);  // 调用基类的 display(int) 函数

    return 0;
}

注意,在调用基类的成员函数的时候,要加上作用域运算符,来表示是个函数是基类的,否则报错,

2. 成员变量隐藏

        与成员函数类似,如果派生类中的成员变量与基类中的成员变量同名,派生类的成员变量也会隐藏基类的成员变量。要访问基类中的同名成员变量,依然需要使用作用域运算符。

class Base {
public:
    int var = 10;
};

class Derived : public Base {
public:
    int var = 20;
};

int main() {
    Derived d;

    cout << "Derived class var: " << d.var << endl;      // 输出派生类的 var
    cout << "Base class var: " << d.Base::var << endl;   // 使用作用域运算符访问基类的 var

    return 0;
}

3. 基类函数的重载隐藏

        在C++中,重载函数的隐藏行为比较特殊。如果派生类中定义了一个与基类同名的函数,即使该函数的参数列表不同,基类中的所有同名函数都会被隐藏。这与函数重载不同,因为在这种情况下,派生类并没有继承基类的同名函数。

class Base {
public:
    void func() {
        cout << "Base class func()" << endl;
    }
    void func(int x) {
        cout << "Base class func(int): " << x << endl;
    }
};

class Derived : public Base {
public:
    using Base::func;  // 显式引入基类的 func 重载
    void func() {
        cout << "Derived class func()" << endl;
    }
};

int main() {
    Derived d;
    d.func();        // 调用派生类的 func()
    d.func(10);      // 调用基类的 func(int) 重载

    return 0;
}

三、多重继承问题

        多重继承是C++中的一个独特特性,允许一个派生类同时继承多个基类。这意味着一个类可以从两个或多个父类派生,从而继承这些基类中的成员。C++通过这种方式实现了极大的灵活性,但同时也引入了潜在的复杂性,如命名冲突菱形继承问题

        

#include <iostream>
using namespace std;

class Base1 {
public:
    void func1() {
        cout << "Function from Base1" << endl;
    }
};

class Base2 {
public:
    void func2() {
        cout << "Function from Base2" << endl;
    }
};

class Derived : public Base1, public Base2 {
public:
    void derivedFunc() {
        cout << "Function from Derived" << endl;
    }
};

int main() {
    Derived d;
    d.func1();       // 调用 Base1 的函数
    d.func2();       // 调用 Base2 的函数
    d.derivedFunc(); // 调用 Derived 类的函数

    return 0;
}

1. 构造函数的调用顺序

当一个类继承了多个父类(多重继承)时,构造函数的调用顺序是:

  • 父类的构造函数先被调用,然后再调用派生类的构造函数。
  • 如果有多个父类,按照继承的声明顺序调用基类的构造函数。
  • 派生类的构造函数总是在所有基类的构造函数执行完之后才执行。
#include <iostream>
using namespace std;

class Base1 {
public:
    Base1() {
        cout << "Base1 constructor called" << endl;
    }
};

class Base2 {
public:
    Base2() {
        cout << "Base2 constructor called" << endl;
    }
};

class Derived : public Base1, public Base2 {
public:
    Derived() {
        cout << "Derived constructor called" << endl;
    }
};

int main() {
    Derived d;
    return 0;
}

2. 析构函数的调用顺序

析构函数的调用顺序与构造函数的顺序正好相反

  • 当一个派生类对象被销毁时,首先调用派生类的析构函数
  • 然后按照继承的逆序依次调用各个基类的析构函数。
  • 如果有多个父类,按照继承声明的逆序调用基类的析构函数。
#include <iostream>
using namespace std;

class Base1 {
public:
    ~Base1() {
        cout << "Base1 destructor called" << endl;
    }
};

class Base2 {
public:
    ~Base2() {
        cout << "Base2 destructor called" << endl;
    }
};

class Derived : public Base1, public Base2 {
public:
    ~Derived() {
        cout << "Derived destructor called" << endl;
    }
};

int main() {
    Derived d;
    return 0;
}

3. 多重继承中的命名冲突

在多重继承中,如果两个基类拥有同名的成员(变量或函数),派生类将面临命名冲突。这种情况下,派生类需要通过作用域运算符显式地指定调用哪个基类的成员。

#include <iostream>
using namespace std;

class Base1 {
public:
    void show() {
        cout << "Base1 show" << endl;
    }
};

class Base2 {
public:
    void show() {
        cout << "Base2 show" << endl;
    }
};

class Derived : public Base1, public Base2 {
public:
    void display() {
        cout << "Derived display" << endl;
    }
};

int main() {
    Derived d;

    // d.show();  // 错误:编译器无法确定调用哪一个基类的 show()

    d.Base1::show();  // 显式调用 Base1 的 show()
    d.Base2::show();  // 显式调用 Base2 的 show()
    d.display();      // 调用 Derived 类的 display()

    return 0;
}

4. 菱形继承问题(Diamond Problem)

        菱形继承是多重继承中的一个经典问题,通常在两个基类都有相同的基类时出现。这种情况下,派生类会通过不同路径继承相同的基类,导致基类中的成员被继承多次,出现二义性和冗余。

#include <iostream>
using namespace std;

class Base {
public:
    int value;
    Base() : value(10) {}
};

class Derived1 : public Base {
};

class Derived2 : public Base {
};

class FinalDerived : public Derived1, public Derived2 {
public:
    void show() {
        // value 是从 Derived1 和 Derived2 都继承来的,出现二义性
        // cout << value;  // 错误:编译器不知道该从 Derived1 还是 Derived2 继承的 Base 使用 value
    }
};

int main() {
    FinalDerived fd;
    // fd.show();  // 无法编译通过,二义性问题

    return 0;
}

 这里就出现了菱形继承问题,那么我们通过虚继承这种机制来解决这种二义性问题

四、虚继承

        虚继承(virtual inheritance)是C++解决菱形继承问题的一种机制。虚继承主要用于处理多重继承中可能出现的重复继承同一个基类的情况,以避免派生类中存在多个相同基类的副本,从而引发的冗余和二义性问题。

1. 菱形继承问题(Diamond Problem)

        菱形继承问题通常在一个类通过多重继承继承自两个基类,而这两个基类又共享同一个基类时出现。这样,最底层的派生类会通过两个不同的路径继承同一个基类,导致该基类的成员在派生类中出现多份副本,从而引发歧义或重复定义的问题。在多重继承中不可避免

        菱形继承结构如下:

       Base
      /    \
Derived1  Derived2
      \    /
    FinalDerived

2. 虚继承解决菱形继承问题

        为了解决这个问题,C++提供了虚继承。通过虚继承,基类的成员在派生类中只存在一个副本,即使通过多个路径继承基类,也不会创建多份冗余副本。

        虚继承: 在中间子类继承公共基类时,在继承方式前面加上关键字 virtual 。 而后派生子类(汇聚到子类),就只会保留一份公共继承的数据 在派生到子类时,汇聚到子类中,在子类的构造函数需要手动指定 公共基类的构造函数

        只要通过 virtual 关键字 进行 虚继承,在子类中额外添加了虚基类指针,指向虚基类表,存储公共基类的成员,

        那么下面我将介绍在虚继承问题中,虚基类表指针和虚基类表的工作原理,以便理解和记忆

 虚基类指的是那些在继承关系中通过虚继承的方式继承的基类,而不是仅仅指“最开始继承的类”。通过虚继承,派生类不会创建多份基类的副本,无论通过几条继承路径,最终派生类中都只有一份虚基类的实例。

3. 虚基类表(Virtual Base Table,VBTBL)

虚基类表是C++编译器在编译过程中生成的数据结构,主要用于虚继承的类。当类使用虚继承时,编译器创建一个虚基类表,用于存储派生类和基类成员之间的偏移量,以确保在多重继承情况下访问基类的成员时,可以正确地找到基类的成员。

        注意:虚基类表(Virtual Base Table, VBTBL)的主要功能就是存储虚基类成员在派生类对象中的偏移量。除此之外,虚基类表本身不存储其他信息。它的作用相对简单,但在虚继承的场景下,它是至关重要的,确保基类的成员能够在多重继承中被唯一、正确地访问。

虚基类表的主要功能:
  • 存储基类成员的偏移量:虚基类表中记录了基类成员相对于派生类对象的内存偏移量。这样,当需要访问虚基类的成员时,能够通过偏移量正确定位。
  • 管理公共基类的访问:当多个类通过虚继承继承同一个基类时,虚基类表确保在最终派生类中,只有一份公共基类的数据。

4. 虚基类指针(Virtual Base Pointer,VBPTR)

虚基类指针是每个使用虚继承的类的对象内部的一个指针,指向该类的虚基类表。通过虚基类指针,编译器可以动态确定派生类中访问基类成员的位置。

虚基类指针的主要功能:
  • 指向虚基类表:虚基类指针存储在每个使用虚继承的类的对象中,指向虚基类表。
  • 确保唯一的基类副本:在复杂的继承关系中,虚基类指针帮助派生类正确访问公共基类,确保派生类只保留一个基类的副本,而不是多次继承同一个基类副本。

5. 虚基类表和虚基类指针的工作机制

        当一个类通过虚继承继承基类时,编译器在每个虚继承类的对象中插入一个虚基类指针,指向该类的虚基类表。在派生类中,虚基类表用于存储公共基类的成员在派生类对象中的相对偏移位置。这样,派生类的对象可以通过虚基类指针找到虚基类表,并通过虚基类表访问公共基类的成员。

6. 虚继承的内部工作过程

  • 虚基类指针:每个虚继承类的对象中都有一个虚基类指针,用于指向虚基类表。虚基类指针帮助派生类正确访问虚基类的成员。
  • 虚基类表:虚基类表记录了公共基类在派生类对象中的位置偏移量,这样在复杂继承关系中,无论从哪条路径访问基类,最终都能访问到同一个基类副本。

 五、虚继承问题例子

1、实例        

看下面的例子:

class Base {
public:
    int baseValue;
    Base() : baseValue(42) {}
};

class Derived1 : virtual public Base {
public:
    int derived1Value;
    Derived1() : derived1Value(100) {}
};

class Derived2 : virtual public Base {
public:
    int derived2Value;
    Derived2() : derived2Value(200) {}
};

class FinalDerived : public Derived1, public Derived2 {
public:
    int finalValue;
    FinalDerived() : finalValue(300) {}
};

在这里:

  • Base类是一个基类。
  • Derived1Derived2分别虚继承Base
  • FinalDerived类通过Derived1Derived2间接继承Base

那么虚基类表指针是怎么来的呢?

2. 虚基类指针(VBPtr)的生成

当一个类通过虚继承继承基类时,编译器为该类的对象插入一个虚基类指针(VBPtr),该指针指向虚基类表(VBTBL),虚基类表存储了基类成员在派生类对象内存布局中的偏移量。

在继承链中,Derived1Derived2 都虚继承了 Base,因此:

  • Derived1的对象会有一个虚基类指针,指向虚基类表,用于确定Base类成员在Derived1对象中的位置。
  • Derived2的对象也有类似的虚基类指针,指向虚基类表,用于确定Base类成员在Derived2对象中的位置。

3. FinalDerived的继承情况

FinalDerived继承了Derived1Derived2时,由于Base是通过虚继承共享的,FinalDerived只会拥有Base类的一个实例。在这种情况下,FinalDerived继承了Derived1Derived2中的虚基类指针(VBPtr),但这两个指针指向的是同一个虚基类表,用于管理Base类的唯一实例。

 那么那么肯定有这样一个问题:

FinalDerived派生类在继承Derived1后,是不是也继承了虚基类表指针,那么这个指针存放的是BaseDerived1对象的偏移量,还是FinalDerivedBase的偏移量?”

答案是:虚基类表中的偏移量指的是Base类成员相对于最终派生类(在此例中是FinalDerived类)对象起始地址的偏移量

  • FinalDerived继承了Derived1Derived2时,虚基类表记录的是Base类成员相对于FinalDerived对象的偏移量。这是因为FinalDerived对象是实际使用的类,而Base类的成员在FinalDerived对象中的具体位置需要通过虚基类表的偏移量来确定。
  • 虚基类表中的偏移量并不会记录Derived1Base之间的偏移量,因为虚基类表的任务是帮助确定虚基类成员在最终派生类对象中的位置,而不是中间派生类对象中的位置。这样你理解了吗。

4. 虚基类指针如何工作

FinalDerived中,Base类的成员(例如baseValue)只存在一份副本。编译器会确保通过虚基类指针,派生类对象可以正确访问Base类的成员。

虚基类指针的作用:
  • Derived1的虚基类指针FinalDerived对象中指向虚基类表,该表包含Base类相对于FinalDerived的偏移量。
  • Derived2的虚基类指针同样指向同一个虚基类表,确保无论是通过Derived1路径还是通过Derived2路径访问Base类成员,访问的都是FinalDerived对象中的唯一Base实例。

 关于虚继承中析构函数和构造函数的调用顺序,这里简单说明一下,和多重继承中的顺序是一样的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2157865.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【网络】TCP协议的简单使用

目录 echo_service server 单进程单线程 多进程 多线程 线程池 client echo_service_code echo_service 还是跟之前UDP一样&#xff0c;我们先通过实际的代码来实现一些小功能&#xff0c;简单的来使用TCP协议进行简单的通信&#xff0c;话不多说&#xff0c;我们先实现…

LabVIEW提高开发效率技巧----合理使用数据流与内存管理

理使用数据流和内存管理是LabVIEW开发中提高性能和稳定性的关键&#xff0c;特别是在处理大数据或高频率信号时&#xff0c;优化可以避免内存消耗过大、程序卡顿甚至崩溃。 1. 使用 Shift Register 进行内存管理 Shift Register&#xff08;移位寄存器&#xff09; 是 LabVIE…

五分钟上手Spring AI Alibaba,轻松打造智能聊天应用

文章目录 快速上手快速体验示例示例开发指南总结 快速上手 Spring AI Alibaba 已经完全适配了阿里云通用模型&#xff0c;接下来&#xff0c;我们将学习如何使用 spring ai alibaba 开发一个基于通用模型服务的智能聊天应用。 快速体验示例 下载项目 运行以下命令下载源码&…

【产品更新】中汇保函-电子保函管理平台

中汇保函 新增 1.手机扫描保函验真二维码直接跳转小程序模块&#xff0c;验真快人一步。 2.新增客户服务服务&#xff0c;可直接联系微信客服。 优化 1.提交申请、登录程序响应速度。 更新内容说明 1.手机扫描保函验真二维码直接跳转小程序模块&#xff0c;验真快人一步。 2.…

从零开始之AI面试小程序

从零开始之AI面试小程序 文章目录 从零开始之AI面试小程序前言一、工具列表二、部署流程1. VMWare安装2. Centos安装3. Centos环境配置3.1. 更改子网IP3.2. 配置静态IP地址 4. Docker和Docker Compose安装5. Docker镜像加速源配置6. 部署中间件6.1. MySQL部署6.2. Redis部署 7.…

华为OD机试 - 出租车计费(Python/JS/C/C++ 2024 E卷 100分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试真题&#xff08;Python/JS/C/C&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加入华为OD刷题交流群&#xff0c;…

飞睿智能实时雷达活体探测传感器模块,智能家居静止检测实时感知人员有无

随着科技的飞速发展&#xff0c;我们的生活正在经历着未有的创新。在这个创新的浪潮中&#xff0c;实时雷达活体探测传感器模块的技术正逐渐崭露头角&#xff0c;以其独特的优势为我们的生活带来安全与便捷。今天&#xff0c;我们就来详细探讨一下这项技术&#xff0c;看看它是…

帮13岁小孩哥2分钟完成开发,这位AI程序员究竟是何方神圣?

通义灵码再升级&#xff0c;真AI程序员来了 随着通义系列基础模型能力的全面提升&#xff0c;各个具体领域的应用模型也随之飞升。这次在云栖大会上迎来重磅升级的&#xff0c;就包括用于代码生成的通义灵码。 一年前的通义灵码还只能完成基础的辅助编程任务&#xff0c;很难…

基于SpringBoot和Vue框架的医保管理系统的设计与实现

文未可获取一份本项目的java源码和数据库参考。 1.研究的主要内容与方法 &#xff08;1&#xff09;主要内容 医保管理系统采用B/S模式进行开发&#xff0c;采用Springboot框架、VUE技术、Idea为环境、MySQL为数据库开发。主要功能有&#xff1a;个人资料管理、投保用户管理、…

上海我店平台 8月新增注册用户89w 两年破百亿销售额!

近年来&#xff0c;网络空间内涌现了一个备受瞩目的新平台——“上海我店”&#xff0c;其公布的业绩数据显示&#xff0c;短短三年内&#xff0c;该平台交易流水已突破百亿大关&#xff0c;上月更是迎来了近百万的新增注册用户&#xff0c;这一消息迅速吸引了众多商家的目光。…

【深度好文】你必须要知道-大模型的上下文窗口(Context Window )

Context Window 上下文窗口&#xff1a;捕捉信息的范围 上下文窗口指的是 AI 模型在生成回答时考虑的 Token 数量。它决定了模型能够捕捉信息的范围。上下文窗口越大&#xff0c;模型能够考虑的信息就越多&#xff0c;生成的回答也就越相关和连贯。 在语言模型中&#xff0c;上…

SysML图例-手电筒

DDD领域驱动设计批评文集>> 《软件方法》强化自测题集>> 《软件方法》各章合集>>

第二证券:股价为什么出现大跌?股价大跌时怎么办?

股票是预期收益率较大的出资之一&#xff0c;但同时股票商场的动摇也会是比较大的&#xff0c;股价大涨大跌都是有或许出现的。股价大涨会让出资者获利更多&#xff0c;而大跌也会加大出资者的损失。下面为我们分析股价为什么会大跌&#xff0c;并介绍股价大跌出资者应该如何应…

【测试】——Selenium API (万字详解)

&#x1f4d6; 前言&#xff1a;本文详细介绍了如何利用Selenium进行Web自动化测试&#xff0c;包括定位元素&#xff08;如cssSelector和xpath&#xff09;、常用操作函数&#xff08;如点击、输入等&#xff09;、窗口管理、键盘鼠标事件和浏览器导航&#xff0c;以及处理弹窗…

linux 的 sed 命令的 使用学习

&#xff08;1&#xff09; sed 概述&#xff1a; &#xff08;2&#xff09; 首先谢谢 b 站这位老师&#xff0c;这位专家的完美讲解 讲解继续&#xff1a; &#xff08;3&#xff09; 关于 sed 里的模式&#xff1a; &#xff08;4&#xff09; sed 支持的常用的对文本编辑的…

LIN总线CAPL函数—— 设置报头同步间隔场长度(linSetBreakLength)

&#x1f345; 我是蚂蚁小兵&#xff0c;专注于车载诊断领域&#xff0c;尤其擅长于对CANoe工具的使用&#x1f345; 寻找组织 &#xff0c;答疑解惑&#xff0c;摸鱼聊天&#xff0c;博客源码&#xff0c;点击加入&#x1f449;【相亲相爱一家人】&#x1f345; 玩转CANoe&…

爬虫 ----hook

目录 定义&#xff1a; 了解什么是hook? 举例 hook XHR请求 XMLHttpRequest 案例地址&#xff1a; Interceptors-拦截器 HOOK cookie操作 cookie 示范 常见的hook代码总结 1.Hook Cookie 2.Hook Header 3.Hook URL 4.Hook JSON.stringify 5.Hook JSON.parse 6.Ho…

5G Multicast/Broadcast Services(MBS) (四)

这篇是有关MBS RRC相关的一些基本内容,内容不多,但是感觉很关键,主要包括SI,MBS网络侧相关的内容,L2 协议架构,cell reselection prioritity以及MBS接收的一些内容,希望有帮助。 SI 在MBS场景中,SI和常规5G一样分为Minimum SI和Other SI。Minimum SI是MIB和SIB1,Min…

智能创造的幕后推手:AIGC浪潮下看AI训练师如何塑造智能未来

文章目录 一、AIGC时代的算法与模型训练概览二、算法与模型训练的关键环节三、AI训练师的角色与职责四、AI训练师的专业技能与素养五、AIGC算法与模型训练的未来展望《AI训练师手册&#xff1a;算法与模型训练从入门到精通》亮点内容简介作者简介谷建阳 目录 《医学统计学从入门…

Cisco Packet Tracer超详细下载安装教程(附中文版插件)

一、安装包下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1RK8iQ9lJG__vBEGCYVYNSA 提取码&#xff1a;1lvb 压缩包解压密码&#xff1a;66668888&#xff0c;不能正常解压的&#xff0c;推荐使用360压缩解压 二、安装教程&#xff1a; 1.双击启动安装包 2.点击N…