多态的一些问题

🏷️ 问答题:

1. 什么是多态?

多态(Polymorphism)是面向对象编程中的一个重要概念,指的是同一操作作用于不同对象时,可以表现出不同的行为方式。多态性允许不同类型的对象以统一的接口进行操作,从而提高代码的灵活性和可扩展性。

多态主要有两种形式:编译时多态(静态多态)和运行时多态(动态多态)。

编译时多态(静态多态)

编译时多态通过函数重载和模板实现。它在编译时确定调用的具体方法。

  1. 函数重载:同名函数根据参数类型和数量的不同,实现不同的功能。

    class Print {
    public:void print(int i) {std::cout << "Printing int: " << i << std::endl;}void print(double f) {std::cout << "Printing float: " << f << std::endl;}void print(const std::string& s) {std::cout << "Printing string: " << s << std::endl;}
    };
    
  2. 模板:使用模板定义可以处理不同类型的泛型函数或类。

    template <typename T>
    void print(T value) {std::cout << "Printing value: " << value << std::endl;
    }
    

运行时多态(动态多态)

运行时多态通过继承和虚函数实现。在运行时根据对象的实际类型确定调用的具体方法。

  1. 继承与虚函数:基类中的虚函数可以在派生类中被重写,并且通过基类指针或引用调用时,会根据实际对象类型调用相应的重写函数。
    class Base {
    public:virtual void show() {std::cout << "Base show" << std::endl;}
    };class Derived : public Base {
    public:void show() override {std::cout << "Derived show" << std::endl;}
    };void display(Base* obj) {obj->show();
    }int main() {Base b;Derived d;display(&b); // 输出 "Base show"display(&d); // 输出 "Derived show"return 0;
    }
    

总结

多态性使得代码更具灵活性和可扩展性,能够通过统一的接口处理不同类型的对象,从而实现代码的复用和模块化。静态多态通过函数重载和模板在编译时实现,而动态多态通过继承和虚函数在运行时实现。

2. 什么是重载、重写(覆盖)、重定义(隐藏)?

重载、重写(覆盖)和重定义(隐藏)是面向对象编程中的三个不同概念,它们各自有不同的用途和特性。下面详细解释这三个概念:

重载(Overloading)

重载指的是在同一个作用域内,函数名相同但参数列表不同(参数的数量或类型不同)。重载可以发生在同一个类中,也可以在全局作用域中。

  • 例子
    class Print {
    public:void print(int i) {std::cout << "Printing int: " << i << std::endl;}void print(double f) {std::cout << "Printing float: " << f << std::endl;}void print(const std::string& s) {std::cout << "Printing string: " << s << std::endl;}
    };
    
    在这个例子中,print函数被重载了三次,分别处理不同类型的参数。

重写(覆盖,Overriding)

重写(或覆盖)指的是在派生类中重新定义基类中的虚函数。重写的函数签名必须与基类中的虚函数签名完全相同。重写用于在派生类中提供基类函数的具体实现,以实现运行时多态。

  • 例子
    class Base {
    public:virtual void show() {std::cout << "Base show" << std::endl;}
    };class Derived : public Base {
    public:void show() override { // 注意: 这里使用了 override 关键字std::cout << "Derived show" << std::endl;}
    };
    
    在这个例子中,Derived类中的show函数重写了Base类中的虚函数show

重定义(隐藏,Hiding)

重定义(或隐藏)指的是在派生类中重新定义基类中的非虚函数名称相同但参数不同的函数。重定义会隐藏基类中的同名函数,但不会影响虚函数的行为。

  • 例子
    class Base {
    public:void show() {std::cout << "Base show" << std::endl;}
    };class Derived : public Base {
    public:void show(int i) { // 隐藏了 Base 类的 show 函数std::cout << "Derived show with int: " << i << std::endl;}
    };
    
    在这个例子中,Derived类中的show(int i)函数重定义(隐藏)了Base类中的show()函数。当通过派生类对象调用show函数时,基类中的show函数会被隐藏。

总结

  • 重载(Overloading):在同一个作用域内,函数名相同但参数列表不同。
  • 重写(Overriding):在派生类中重新定义基类的虚函数,签名必须相同。
  • 重定义(隐藏,Hiding):在派生类中重新定义基类中的非虚函数或名称相同但参数不同的函数,隐藏基类中的同名函数。

注意 重载和隐藏的区别?

重载(Overloading)和隐藏(Hiding)是两种不同的函数处理方式,在C++中有着不同的语义和用法。以下是它们的主要区别:

重载(Overloading)

重载是指在同一个作用域中,函数名称相同但参数列表不同(参数的数量或类型不同)。重载的函数在编译时根据传递的参数类型和数量来选择具体调用的函数。

  • 特性

    • 发生在同一作用域(通常是在同一个类内,但也可以在全局作用域)。
    • 函数名相同,但参数列表必须不同。
    • 可以返回不同的类型,但返回类型不会影响重载的判定。
    • 不同重载的函数可以有不同的实现。
  • 例子

    class Example {
    public:void func(int i) {std::cout << "Function with int: " << i << std::endl;}void func(double d) {std::cout << "Function with double: " << d << std::endl;}void func(int i, double d) {std::cout << "Function with int and double: " << i << ", " << d << std::endl;}
    };
    

    在这个例子中,func函数被重载了三次,每次都有不同的参数列表。

隐藏(Hiding)

隐藏是指在派生类中重新定义一个与基类中具有相同名称的非虚函数或具有不同参数列表的函数。这会导致基类中的同名函数在派生类的作用域中不可见。

  • 特性

    • 发生在继承层次结构中。
    • 派生类中的函数名与基类中的函数名相同,但可以有不同的参数列表。
    • 基类的函数在派生类中被隐藏,即使参数列表不同。
    • 为了调用被隐藏的基类函数,需要使用作用域解析运算符(::)。
  • 例子

    class Base {
    public:void func(int i) {std::cout << "Base function with int: " << i << std::endl;}
    };class Derived : public Base {
    public:void func(double d) {std::cout << "Derived function with double: " << d << std::endl;}
    };int main() {Derived d;d.func(10.5); // 调用 Derived::func(double)// d.func(10); // 错误:Base::func(int) 被隐藏d.Base::func(10); // 正确:调用 Base::func(int)return 0;
    }
    

    在这个例子中,Derived类中的func(double)函数隐藏了Base类中的func(int)函数。当通过派生类对象调用func函数时,只有派生类的函数可见。

主要区别总结

  • 重载:在同一个作用域内,函数名相同但参数列表不同,不涉及继承。
  • 隐藏:发生在继承层次结构中,派生类中重新定义的函数会隐藏基类中的同名函数,无论参数列表是否不同。

3. 多态的实现原理?

多态(Polymorphism)是面向对象编程中的核心概念,它允许同一接口调用在不同对象上产生不同的行为。多态的实现主要依赖于继承和虚函数。下面详细解释多态的实现原理:

虚函数表(Virtual Table,vtable)

多态的关键在于虚函数表(vtable),这是一个指向函数指针的数组,每个==包含虚函数==的类都有一个虚函数表。虚函数表中存储了类的虚函数地址。在运行时,通过基类指针调用虚函数时,程序会查找虚函数表,进而调用实际的函数实现。

虚函数表指针(Virtual Table Pointer,vptr)

每个包含虚函数的类对象都有一个指向虚函数表的指针,称为虚函数表指针(vptr)。在对象构造时,编译器会自动设置这个指针,使其指向正确的虚函数表。

实现步骤

  1. 类的声明:基类中声明虚函数,派生类中重写这些虚函数。

    class Base {
    public:virtual void show() {std::cout << "Base show" << std::endl;}
    };class Derived : public Base {
    public:void show() override {std::cout << "Derived show" << std::endl;}
    };
    
  2. 对象创建和虚函数表指针初始化

    • 创建 Base 类对象时,编译器设置 vptr 指向 Base 类的虚函数表。
    • 创建 Derived 类对象时,编译器设置 vptr 指向 Derived 类的虚函数表。
  3. 函数调用:通过基类指针或引用调用虚函数。

    void display(Base* obj) {obj->show(); // 通过 vptr 查找 vtable 并调用实际的 show() 实现
    }int main() {Base b;Derived d;display(&b); // 调用 Base::show()display(&d); // 调用 Derived::show()return 0;
    }
    

工作原理

  • display 函数被调用时,它接收一个基类指针 obj
  • obj->show() 调用时,编译器生成代码,通过 objvptr 查找虚函数表。
  • 虚函数表包含了实际函数实现的地址,因此程序会根据 vptr 指向的虚函数表,调用正确的函数实现。

内存布局

  • 基类对象

    [vptr] -> [Base::show() address]
    
  • 派生类对象

    [vptr] -> [Derived::show() address]
    

总结

多态的实现依赖于以下机制:

  1. 虚函数表(vtable):存储类的虚函数地址。
  2. 虚函数表指针(vptr):每个对象都有一个指向其类的虚函数表的指针。
  3. 动态绑定:在运行时通过 vptr 查找虚函数表并调用实际的函数实现。

这种机制使得不同类型的对象可以通过同一个基类接口被调用,表现出不同的行为,从而实现运行时多态。

4. inline函数可以是虚函数吗?

答:可以,不过编译器就忽略inline属性,这个函数就不再是inline,因为虚函数要放到虚表中去。

在C++中,inline函数和虚函数可以结合使用,但它们的行为和目的有所不同。以下是详细解释:

inline函数

inline函数是建议编译器将函数的代码内联到调用处,以减少函数调用的开销。inline是一个编译器提示,编译器可以选择忽略它。

虚函数

虚函数是用于实现运行时多态的函数。虚函数通过虚函数表(vtable)和虚函数表指针(vptr)来实现动态绑定,以便在运行时决定调用哪个函数实现。

结合使用

虽然inline函数和虚函数的目的是不同的,但它们可以结合使用。具体来说:

  • 虚函数可以声明为inline:这在语法上是允许的。
  • 内联虚函数的实际情况:由于虚函数需要在运行时通过虚函数表进行动态绑定,编译器通常不会内联虚函数的调用,即使它们被声明为inline。这是因为虚函数的动态绑定与内联的静态绑定机制不兼容。

示例

class Base {
public:virtual inline void show() {std::cout << "Base show" << std::endl;}
};class Derived : public Base {
public:inline void show() override {std::cout << "Derived show" << std::endl;}
};

在这个示例中,Base类中的show函数和Derived类中的show函数都被声明为inline。但是,当通过基类指针或引用调用show函数时,编译器会进行动态绑定,这使得函数不太可能被内联。

具体情况分析

  1. 虚函数表和动态绑定:虚函数在运行时通过虚函数表进行动态绑定,因此编译器在编译时无法知道具体调用哪个函数实现。这与内联函数的静态绑定机制相冲突。
  2. 优化器的决定:尽管声明了inline,编译器的优化器通常会根据具体情况决定是否内联函数。由于虚函数的动态特性,编译器通常不会内联它们。
  3. 纯虚函数:纯虚函数(pure virtual functions)不能有定义,因此也不能是inline的。

5. 静态成员可以是虚函数吗?

答:不能,因为静态成员函数没有this指针,使用类型::成员函数的调用方式无法访问虚函数表,所以静态成员函数无法放进虚函数表。

静态成员函数(static member function)不能是虚函数(virtual function)。这是因为静态成员函数和虚函数在C++中的作用和实现机制不同,并且它们的概念不兼容。以下是详细解释:

静态成员函数

  • 定义:静态成员函数是属于类本身,而不是类的某个对象的函数。
  • 调用方式:它们可以通过类名直接调用,也可以通过对象调用,但在内部不依赖于对象实例(没有this指针)。
  • 特点:静态成员函数无法访问类的非静态成员(包括成员变量和成员函数),因为它们不依赖于具体的对象实例。

虚函数

  • 定义:虚函数是用于实现运行时多态的成员函数。
  • 调用方式:它们通过对象的虚函数表(vtable)和虚函数表指针(vptr)进行动态绑定。
  • 特点:虚函数必须依赖于对象实例,因为虚函数表是每个对象的一部分。虚函数通过this指针访问对象的其他成员。

互不兼容的原因

由于静态成员函数和虚函数的本质区别,它们不能兼容:

  1. 对象依赖性:虚函数依赖于对象实例进行动态绑定,而静态成员函数不依赖于对象实例,没有this指针。
  2. 虚函数表:虚函数需要对象的虚函数表来实现多态,而静态成员函数属于类本身,不在任何对象的虚函数表中。

示例和错误演示

下面是一个错误示例,试图将静态成员函数声明为虚函数:

class Example {
public:static virtual void func(); // 错误:静态成员函数不能是虚函数
};void Example::func() {std::cout << "Static function" << std::endl;
}

编译器会报错,因为静态成员函数不能被声明为虚函数。

结论

在C++中,静态成员函数和虚函数是两个互不兼容的概念。静态成员函数不能是虚函数,因为它们不依赖于对象实例,无法进行动态绑定,也没有虚函数表支持。

6. 构造函数可以是虚函数吗?

答:不能,因为对象中的虚函数表指针是在构造函数初始化列表阶段才初始化的。

构造函数不能是虚函数。以下是原因和详细解释:

构造函数的作用和特性

  • 构造函数的作用:构造函数用于初始化对象的状态。在对象创建时,构造函数被调用,用来设置对象的初始值和进行必要的初始化操作。
  • 调用时机:构造函数是在对象创建时调用的,是对象生命周期的起点。

虚函数的作用和特性

  • 虚函数的作用:虚函数用于实现运行时多态。通过基类指针或引用调用虚函数时,会根据实际对象的类型调用相应的派生类实现。
  • 虚函数表(vtable):虚函数依赖于虚函数表进行动态绑定。每个对象在创建时,会通过其虚函数表指针(vptr)指向正确的虚函数表。

不兼容的原因

构造函数不能是虚函数,原因如下:

  1. 对象创建和初始化顺序:在对象创建时,基类的构造函数会先于派生类的构造函数被调用。如果构造函数是虚函数,那么在调用基类构造函数时,派生类的虚函数表还没有初始化,这会导致不可预知的行为。

  2. 虚函数表的设置:虚函数表指针是在构造函数期间设置的。在基类的构造函数中,对象还没有完全构造完成,虚函数表也尚未设置。因此,不能在构造函数中进行虚函数的动态绑定。

  3. 逻辑冲突:构造函数的主要目的是初始化对象,而虚函数的主要目的是实现多态。构造函数是对象生命周期的起点,而虚函数依赖于对象已经存在并且其类型已经确定。将这两者结合在一起在逻辑上是不合理的。

示例和错误演示

试图将构造函数声明为虚函数会导致编译错误:

class Base {
public:virtual Base(); // 错误:构造函数不能是虚函数
};Base::Base() {// 构造函数的实现
}

编译器会报错,因为构造函数不能被声明为虚函数。

结论

构造函数不能是虚函数,因为构造函数在对象创建时被调用,而虚函数依赖于对象的虚函数表进行动态绑定。由于对象在构造期间虚函数表尚未完全设置,因此构造函数无法实现多态。这个设计决策确保了对象创建和初始化的正确性和一致性。

7. 析构函数可以是虚函数吗?什么场景下析构函数是虚函数?

答:可以,并且最好把基类的析构函数定义成虚函数。

析构函数可以是虚函数,并且在某些场景下必须将析构函数声明为虚函数,以确保正确的资源释放和内存管理。下面是详细的解释和场景分析:

虚析构函数的概念

  • 虚析构函数的作用:虚析构函数用于在删除一个指向派生类对象的基类指针时,确保正确调用派生类的析构函数,从而正确释放资源。
  • 动态绑定:通过虚函数表(vtable)实现动态绑定,使得在删除基类指针时,可以调用到正确的派生类析构函数。

为什么需要虚析构函数

当使用多态删除对象时(即通过基类指针删除派生类对象),如果基类析构函数不是虚函数,那么只会调用基类的析构函数,而不会调用派生类的析构函数。这会导致派生类的资源(如动态内存、文件句柄等)没有被正确释放,造成资源泄漏。

示例

假设我们有如下类结构:

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

如果使用基类指针删除派生类对象:

int main() {Base* obj = new Derived();delete obj; // 未定义行为,仅调用 Base 的析构函数return 0;
}

在这种情况下,只有Base的析构函数被调用,而Derived的析构函数不会被调用。这会导致Derived类中的资源没有被正确释放。

使用虚析构函数的正确做法

为了确保删除基类指针时正确调用派生类的析构函数,基类的析构函数应该声明为虚函数:

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

在这种情况下,当通过基类指针删除派生类对象时:

int main() {Base* obj = new Derived();delete obj; // 正确调用 Derived 的析构函数return 0;
}

输出将会是:

Base constructor
Derived constructor
Derived destructor
Base destructor

这表明,派生类的析构函数被正确调用,资源得到了正确释放。

总结

  • 析构函数可以是虚函数,并且在某些情况下必须是虚函数,以确保通过基类指针删除派生类对象时,能够正确调用派生类的析构函数。
  • 场景:当一个类用于继承,并且可能通过基类指针或引用操作派生类对象时,基类的析构函数应该声明为虚函数。

这种设计确保了对象的正确析构,防止资源泄漏,维护程序的健壮性和可靠性。

8. 对象访问普通函数快还是虚函数更快?

答:首先如果是普通对象,是一样快的。如果是指针对象或者是引用对象,则调用的普通函数快,因为构成多态,运行时调用虚函数需要到虚函数表中去查找。

9. 虚函数表是在什么阶段生成的,存在哪的?

答:虚函数表是在编译阶段就生成的,一般情况下存在代码段(常量区)的。

10. C++菱形继承的问题?虚继承的原理?

C++中的菱形继承和虚拟继承涉及多重继承的复杂情况。以下是详细解释:

菱形继承问题

菱形继承指的是一种多重继承结构,其中一个类派生自两个基类,而这两个基类又派生自同一个祖先类。这种结构形状如菱形,因此得名。

问题

  1. 重复继承:派生类通过两个路径继承了祖先类的成员,导致成员的重复。
  2. 数据冗余:派生类对象中会包含多个基类的副本,导致数据冗余和不一致性。
  3. 二义性:调用祖先类的成员时,编译器无法确定调用哪个基类的成员,导致二义性。

示例

class A {
public:int data;
};class B : public A {
};class C : public A {
};class D : public B, public C {
};

在这个例子中,类 D 继承了两次 A 类的成员,导致 D 中存在两个 data 成员。

虚拟继承的原理

虚拟继承是一种解决菱形继承问题的机制。通过虚拟继承,可以确保只有一个祖先类的实例被继承,从而避免数据冗余和二义性。

虚拟继承的实现

  1. 虚基类:使用关键字 virtual 声明基类为虚基类。
  2. 共享基类实例:虚拟继承确保派生类共享一个基类实例,而不是创建多个副本。
  3. 虚基类指针:编译器在对象中维护一个指针,指向唯一的基类实例。

示例

class A {
public:int data;
};class B : virtual public A {
};class C : virtual public A {
};class D : public B, public C {
};

在这个例子中,类 D 通过虚拟继承的方式,确保 A 类的实例只有一个。

虚拟继承的工作原理

  1. 虚基类指针:每个包含虚基类的对象实例都包含一个指向虚基类子对象的指针。这个指针由编译器自动管理。
  2. 虚基类表:编译器在每个类中生成一个虚基类表(vbase table),用于定位虚基类子对象。
  3. 内存布局:虚基类的子对象在内存中只存在一份,所有派生类共享这个子对象。

访问虚基类成员

当访问虚基类的成员时,通过虚基类指针(vptr)和虚基类表(vbase table)来定位唯一的虚基类实例,从而确保数据的一致性。

结论

  • 菱形继承问题:在多重继承中,同一基类被多次继承导致数据冗余和二义性。
  • 虚拟继承的解决方案:通过 virtual 关键字声明虚基类,确保只继承一个基类实例,避免数据冗余和二义性。
  • 虚拟继承的实现原理:使用虚基类指针和虚基类表在内存中共享基类实例,编译器负责管理这些细节。

虚拟继承在C++中是一个强大的机制,用于处理复杂的多重继承结构,确保代码的正确性和一致性。

11. 什么是抽象类?抽象类的作用?

答:抽象类强制重写了虚函数,另外抽象类体现出了接口继承关系。

什么是抽象类?

抽象类是一个不能实例化的类,用来定义接口或抽象方法。抽象类通常包含一个或多个纯虚函数(pure virtual functions),这些函数在抽象类中没有具体实现,必须在派生类中实现。

纯虚函数的定义格式如下:

virtual void functionName() = 0;

抽象类的作用

  1. 定义接口:抽象类用于定义一组接口,派生类必须实现这些接口。这使得不同的派生类可以通过这些公共接口进行互操作。
  2. 实现多态性:抽象类通过虚函数机制实现运行时多态性。基类指针或引用可以指向不同的派生类对象,通过调用虚函数实现不同的行为。
  3. 代码重用:抽象类可以包含一些具体的实现,派生类可以继承这些实现,避免重复代码。

示例

抽象类的定义和使用
#include <iostream>// 定义一个抽象类 Shape
class Shape {
public:// 纯虚函数virtual void draw() = 0;// 可以包含一些具体实现void display() {std::cout << "Displaying shape." << std::endl;}
};// 派生类 Circle 继承自 Shape
class Circle : public Shape {
public:// 实现纯虚函数void draw() override {std::cout << "Drawing a circle." << std::endl;}
};// 派生类 Rectangle 继承自 Shape
class Rectangle : public Shape {
public:// 实现纯虚函数void draw() override {std::cout << "Drawing a rectangle." << std::endl;}
};int main() {// Shape s; // 错误:不能实例化抽象类// 使用基类指针指向派生类对象Shape* shape1 = new Circle();Shape* shape2 = new Rectangle();shape1->draw(); // 调用 Circle 的 draw 方法shape2->draw(); // 调用 Rectangle 的 draw 方法shape1->display(); // 调用基类的 display 方法shape2->display(); // 调用基类的 display 方法delete shape1;delete shape2;return 0;
}

在这个示例中:

  • Shape 是一个抽象类,包含一个纯虚函数 draw 和一个具体函数 display
  • CircleRectangleShape 的派生类,它们实现了 draw 函数。
  • Shape 类不能直接实例化,但可以通过基类指针指向派生类对象,实现多态调用。

主要特点

  • 不可实例化:抽象类不能直接创建对象。
  • 纯虚函数:至少包含一个纯虚函数。
  • 派生类实现:派生类必须实现所有的纯虚函数,否则派生类也会成为抽象类。

作用总结

  1. 接口定义:抽象类定义了一组必须实现的接口,确保派生类实现这些接口。
  2. 实现多态:通过抽象类和虚函数实现运行时多态,使得不同派生类对象可以通过同一接口进行操作。
  3. 代码重用:抽象类可以包含一些通用的实现,派生类可以继承这些实现,减少代码重复。

抽象类在设计模式和框架中非常重要,它们提供了一种定义和实现接口的方式,使得代码更加模块化和可扩展。

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

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

相关文章

tomlkit mypy error: Value of type “Item | Container“ is not indexable [index]

使用tomlkit进行TOML文件的读写时&#xff0c;mypy静态检查报错如下&#xff1a; demo.py:5: error: Value of type "Item | Container" is not indexable [index]poetry_conf doc[tool][poetry]^~~~~~~~~~~~~~~~~~~~~ demo.py:7: error: Unsupported target for …

香港服务器无法访问是什么情况?

香港服务器无法访问是什么情况?简单来说&#xff0c;这意味着香港服务器没有响应请求&#xff0c;客户端无法访问。此错误可能由于多种原因而发生&#xff0c;包括网络连接问题、服务器停机、防火墙限制和 DNS 错误。当发生服务器无法访问错误时&#xff0c;它会影响您网站的性…

OncePerRequestFilter 和 GenericFilterBean比较

OncePerRequestFilter 和 GenericFilterBean 都是Spring框架提供的用于构建自定义Servlet过滤器&#xff08;Filter&#xff09;的基类&#xff0c;它们主要用于处理Web请求的拦截和处理逻辑。以下是它们各自的详细说明&#xff1a; GenericFilterBean 类描述&#xff1a;Gen…

Qt for android : libusb在android中使用

简介 如何在Qt for Android中使用libusb&#xff0c; 其实libusb的文档里面都写的很清楚&#xff0c; 这里只是稍微做下整理。 libusb libusb github源码 libusb release的版本, 有编译好的静态 步骤 1. 下载libusb libusb v1.0.027 源码包 2. 整理提取libusb android使用源…

Docker 私有仓库部署和管理

目录 一、案例一 概述 二、案例一 前置知识点 2.1、什么是 Docker Compose 2.2、什么是 Consul 三、案例一 使用 docker Compose 搭建 Consul 集群环境 3.1、案例实验环境 3.2、案例需求 四、案例实施 4.1、Docker 网络通信 1&#xff09;端口映射 2&#xf…

运筹学_3.运输问题(特殊的线性规划)

目录 前言3.1 平衡运输问题中初始基可行解确定运输问题平衡运输与非平衡运输平衡运输问题的数学模型单纯形法解决平衡运输问题&#xff0c;初始可行基的确认 3.2 平衡运输问题的最优解判别求检验数表上作业法 3.3 产销不平衡的运输问题运输问题中产大于销的问题运输问题中产小于…

【MySQL访问】

文章目录 一、C远程连接到MySQLmysql_init()函数mysql_real_connect&#xff08;&#xff09;函数实战案例 二、处理查询select的细节mysql_store_result()函数获取结果行和列获取select结果获取行内容获取列属性 三、MySQL图形化界面连接 关于动态链接&#xff0c;请看这篇文章…

Nginx 实战-02-nginx proxy_pass 服务代理访问 使用笔记 ubuntu nodejs

前言 大家好&#xff0c;我是老马。很高兴遇到你。 我们为 java 开发者实现了 java 版本的 nginx https://github.com/houbb/nginx4j 如果你想知道 servlet 如何处理的&#xff0c;可以参考我的另一个项目&#xff1a; 手写从零实现简易版 tomcat minicat 手写 nginx 系列 …

达梦数据库(五) -------- 达梦数据库+mybatisPlus+springboot

前言&#xff1a;安装完达梦数据库后&#xff0c;需要初始化实例&#xff0c;在初始化实例时&#xff0c;需要注意大小写敏感的设置。大小写敏感只能在初始化数据库的时候设置&#xff0c;默认为大小写敏感&#xff0c;一旦设置成功就无法修改&#xff0c;如果想要修改&#xf…

elementui el-tooltip文字提示组件弹出层内容格式换行处理

1、第一种 1.1 效果图 1.2、代码 <template><div class"wrapper"><el-tooltip class"content" effect"dark" placement"top"><div slot"content"><div v-html"getTextBrStr(text)"&…

centOS 编译C/C++

安装C和C编译器 yum -y install gcc*查看CenterOS系统信息 cat /etc/system-releaseCentOS Linux release 8.2.2004 (Core)查看gcc版本 gcc --versiongcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-4) Copyright (C) 2018 Free Software Foundation, Inc. This is free software…

深入理解同步与异步编程:从概念到实践

导言&#xff1a; 在软件开发中&#xff0c;同步和异步是两种常见的编程模式。深入理解这两种模式的工作原理对于提高代码的效率和性能至关重要。本文将从概念、原理和实践三个方面介绍同步和异步编程&#xff0c;帮助读者更好地理解和应用这两种编程模式。 同步编程&#xf…

ai虚拟主播自动切换的实现

前段时间,看到b站突然冒出很多ai主播,输入数字切换小姐姐.感觉挺有趣.思考了以下决定手动实现一下. 然后就陷入长达5天的踩坑中 由于是自建的webrtc服务器,很自然的想直接收流转发,这也是最优的方案, 然而实际上遇到许多不是很友好的bug, 然后再想使用rtp转发,依然不理想. 最后…

低代码开发:助企构建数字化应用平台

随着信息技术的快速发展&#xff0c;数字化应用平台已经成为企业提升竞争力、实现业务创新的关键。然而&#xff0c;传统的应用开发方式往往面临着开发周期长、成本高昂、技术门槛高等问题&#xff0c;这使得许多企业望而却步。而低代码开发技术的出现&#xff0c;为企业构建数…

【第十二节】C++控制台版本贪吃蛇小游戏

目录 一、游戏简介 1.1 游戏概述 1.2 实现功能 1.3 开发环境 二、实现设计 2.1 C类的设计 2.2 项目结构 2.3 代码设计 三、程序运行截图 3.1 游戏界面 3.2 自定义地图 3.3 常规游戏界面 一、游戏简介 1.1 游戏概述 本游戏是一款基于C语言开发的控制台版本贪吃蛇游…

cwiseMax、cwiseMin函数

一、cwiseMax含义 cwiseMax是Eigen库中的一个函数&#xff0c;用于求两个矩阵或向量的逐元素最大值。它的作用类似于std::max函数&#xff0c;但是可以同时处理多个元素&#xff0c;且支持矩阵和向量。 举例&#xff1a; 例如&#xff0c;对于两个向量a和b&#xff0c;cwiseMax…

Python中的魔法函数

大家好&#xff0c;Python作为一种高级编程语言&#xff0c;以其简洁、优雅和易读性而闻名。然而&#xff0c;Python的强大之处不仅仅在于其语法的简洁性&#xff0c;还在于其灵活的面向对象编程范式。在Python中&#xff0c;有一类特殊的方法被称为“魔法函数”&#xff0c;它…

神器!!Python热重载调试【送源码】

在 Python 开发的路上&#xff0c;调试是我们不可避免的一环。 而今天推荐的开源项目Reloadium &#xff0c;让你在不重启程序的情况下实现代码的即时更新和调试。 &#x1f504; Reloadium 功能亮点&#xff1a; 1. 热重载魔法&#xff1a; Reloadium 不仅仅能够实现代码的…

电脑缺失msvcp120.dll要如何解决,学会这七个方法,轻松摆脱困扰

msvcp120.dll 是 Microsoft Visual C 2013 运行时库的一部分&#xff0c;它提供了 C 标准库的实现&#xff0c;使得开发者能够利用丰富的 C 功能来构建复杂的应用程序。这个文件对于使用了 C 标准库的应用程序来说是必不可少的。当这些应用程序运行时&#xff0c;它们会动态链接…

Docker管理工具Portainer忘记admin登录密码

停止Portainer容器 docker stop portainer找到portainer容器挂载信息 docker inspect portainer找到目录挂载信息 重置密码 docker run --rm -v /var/lib/docker/volumes/portainer_data/_data:/data portainer/helper-reset-password生成新的admin密码&#xff0c;使用新密…