C++ 面向对象、特征、重载和重写、构造和析构、向上和向下转型、深浅拷贝。

什么是面向对象(Object-Oriented Programming, OOP)

1.面向对象是一种编程范式,它通过将软件系统的设计和开发分解为“对象”(Object)的方式来实现更好地组织代码。面向对象的核心思想是将程序的结构分为对象,这些对象包含数据和操作这些数据的函数(即方法)。每个对象是类的实例,而类定义了对象的属性和行为。OOP有助于提高代码的可维护性、可重用性和扩展性。

 2. 面向过程和面向对象的区别
面向过程:根据业务逻辑从上到下写代码

面向对象:将数据与函数绑定到一起,进行封装,加快开发程序,减少重复代码的重写过程

面向对象的四大基本特性

  1. 封装(Encapsulation)

    • 定义:封装是将对象的属性和方法包装起来,使得对象内部的数据只能通过定义的方法来访问或修改,从而保护数据的完整性。
    • 目的:隐藏内部实现,防止外部直接访问对象内部数据,提供一个接口与对象交互。

    示例

    class Person {
    private:
        string name;
        int age;

    public:
        // 设置名称
        void setName(string n) { name = n; }
        // 获取名称
        string getName() { return name; }
    };
     

  2. 继承(Inheritance)

    • 定义:继承是从现有类中派生新类的过程,新类可以继承父类的属性和方法,并且可以扩展或修改父类的行为。
    • 目的:复用代码,减少重复,实现代码的层次化结构。

    示例

    #include <iostream>
    using namespace std;

    class Base {
    public:
        int pub_member;
    protected:
        int prot_member;
    private:
        int priv_member;
    };

    class PublicDerived : public Base {
    public:
        void accessBase() {
            pub_member = 10;      // 可以访问
            prot_member = 20;     // 可以访问
            // priv_member = 30;  // 无法访问,编译错误
        }
    };

    class ProtectedDerived : protected Base {
    public:
        void accessBase() {
            pub_member = 10;      // 可以访问,但变为 protected
            prot_member = 20;     // 可以访问
            // priv_member = 30;  // 无法访问,编译错误
        }
    };

    class PrivateDerived : private Base {
    public:
        void accessBase() {
            pub_member = 10;      // 可以访问,但变为 private
            prot_member = 20;     // 可以访问
            // priv_member = 30;  // 无法访问,编译错误
        }
    };

    int main() {
        PublicDerived pubObj;
        pubObj.pub_member = 10;   // 可以访问(public)

        // ProtectedDerived protObj;
        // protObj.pub_member = 10; // 无法访问(protected)

        // PrivateDerived privObj;
        // privObj.pub_member = 10; // 无法访问(private)

        return 0;
    }

    public 继承:
    公开继承 (public) 是最常见的继承方式,表示“is-a”关系,派生类对象可以被当作基类对象使用。
    基类的 public 成员在派生类中仍然保持 public,protected 成员保持 protected。
    基类的 private 成员对派生类不可见。

    protected 继承:
    保护继承 (protected) 限制了派生类对基类成员的访问范围。
    基类的 public 和 protected 成员在派生类中都变为 protected。
    外部无法访问派生类中的这些成员,但派生类的子类仍然可以访问它们。

    private 继承:
    私有继承 (private) 是最为封闭的继承方式,表示“implemented-in-terms-of”关系。
    基类的 public 和 protected 成员在派生类中都变为 private,外部无法访问,派生类的子类也无法访问。
    通常用于当派生类不想暴露基类的接口时。

     
  3. 多态(Polymorphism)

    • 定义:多态允许对象以不同的形式出现,具体表现为同样的方法可以作用于不同的对象,而产生不同的行为。多态分为编译时多态(函数重载、运算符重载)和运行时多态(虚函数)。
    • 目的:通过统一接口处理不同的对象,提高代码的扩展性和灵活性。
    • 也可以理解为用父类型的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。实现多态,有二种方式,重写,重载

    示例

    class Animal {
    public:
        virtual void makeSound() {
            cout << "Some generic sound" << endl;
        }
    };

    class Dog : public Animal {
    public:
        void makeSound() override {
            cout << "Bark!" << endl;
        }
    };

    class Cat : public Animal {
    public:
        void makeSound() override {
            cout << "Meow!" << endl;
        }
    };

    void playSound(Animal* animal) {
        animal->makeSound();
    }
     

  4. 抽象(Abstraction)

    • 定义:抽象是指从复杂的现实问题中提取出关键特性,而忽略掉具体的细节。它通过接口或抽象类来定义一组必须被实现的方法。
    • 目的:隐藏复杂实现,仅保留相关功能,从而简化程序结构。

    示例

    class Shape {
    public:
        virtual void draw() = 0;  // 纯虚函数
    };

    class Circle : public Shape {
    public:
        void draw() override {
            cout << "Drawing a circle" << endl;
        }
    };

在 C++ 中,重载(Overloading)和重写(Overriding)是两种不同的概念,它们都允许函数的行为在某种程度上发生变化,但在使用方式和适用场景上有显著的不同。

2.1 重载(Overloading)

重载是指在同一个作用域中,允许定义多个同名函数,但它们的参数列表必须不同。重载函数可以根据传递的不同类型或数量的参数执行不同的功能。重载常见于函数重载运算符重载

函数重载的实现

函数重载要求函数名称相同,但参数类型参数个数参数顺序必须不同。

示例

#include <iostream>
using namespace std;

class Calculator {
public:
    // 重载加法函数,处理整数加法
    int add(int a, int b) {
        return a + b;
    }

    // 重载加法函数,处理浮点数加法
    double add(double a, double b) {
        return a + b;
    }

    // 重载加法函数,处理三个数的加法
    int add(int a, int b, int c) {
        return a + b + c;
    }
};

int main() {
    Calculator calc;

    cout << calc.add(10, 20) << endl;        // 调用整数加法
    cout << calc.add(10.5, 20.3) << endl;    // 调用浮点数加法
    cout << calc.add(1, 2, 3) << endl;       // 调用三个整数加法

    return 0;
}
 

运算符重载的实现

运算符重载允许开发者为自定义类型定义特定的操作符行为(如 +-== 等)。

示例

#include <iostream>
using namespace std;

class Complex {
private:
    double real;
    double imag;

public:
    Complex(double r, double i) : real(r), imag(i) {}

    // 重载加法运算符
    Complex operator+(const Complex& other) {
        return Complex(real + other.real, imag + other.imag);
    }

    void display() {
        cout << real << " + " << imag << "i" << endl;
    }
};

int main() {
    Complex c1(3.0, 4.0);
    Complex c2(1.0, 2.0);
    Complex c3 = c1 + c2;  // 使用重载的加法运算符

    c3.display();  // 输出:4 + 6i

    return 0;
}
 

2.2 重写(Overriding)

重写是指在继承关系中,子类重新定义从父类继承而来的函数,以实现不同的行为。重写通常用于运行时多态,通过父类指针或引用调用子类的重写方法。这涉及到虚函数(virtual)的使用。

重写的实现
  • 重写的前提是函数必须在父类中标记为 virtual
  • 子类的重写方法必须和父类的虚函数函数签名完全一致(包括返回类型、参数类型等)。

示例

#include <iostream>
using namespace std;

class Animal {
public:
    // 定义虚函数
    virtual void makeSound() {
        cout << "Some generic animal sound" << endl;
    }
};

class Dog : public Animal {
public:
    // 重写父类的虚函数
    void makeSound() override {
        cout << "Bark!" << endl;
    }
};

class Cat : public Animal {
public:
    // 重写父类的虚函数
    void makeSound() override {
        cout << "Meow!" << endl;
    }
};

int main() {
    Animal* animal1 = new Dog();
    Animal* animal2 = new Cat();

    animal1->makeSound();  // 输出:Bark!
    animal2->makeSound();  // 输出:Meow!

    delete animal1;
    delete animal2;

    return 0;
}
 

 

在这个例子中,DogCat 都重写了 Animal 类中的 makeSound 方法。当我们通过父类指针调用 makeSound 时,调用的是子类的版本,这就是运行时多态的效果。

2.3 重载与重写的区别

特性重载(Overloading)重写(Overriding)
发生时机编译时:在编译时通过函数签名区分不同的函数。运行时:通过虚函数表在运行时选择合适的重写方法。
适用范围同一个类中,或者在全局作用域中定义的多个同名函数。继承体系中的子类对父类虚函数的重新定义。
函数签名要求必须有不同的参数类型、数量或顺序,返回值可以相同或不同。函数签名必须与父类完全一致,包含返回类型。
使用场景当同一个功能可以通过不同的参数类型或数量实现时。当子类需要修改父类的行为时使用,且通常伴随多态实现。
是否依赖继承关系不依赖继承。依赖继承,必须在子类中定义。
是否需要虚函数不需要。需要虚函数或纯虚函数(virtual 关键字)。
执行效率在编译时就确定调用哪个重载函数,因此效率较高。需要在运行时通过虚函数表查找,效率相对较低。

2.4 总结

  1. 重载是通过改变参数列表来实现相同函数名的不同功能,适用于同一作用域中。
  2. 重写是子类对父类虚函数的重新定义,适用于继承关系,并且通常伴随着多态的实现。
  3. 编译时 vs 运行时:重载是编译时行为,重写是运行时行为。

图表总结

特性重载(Overloading)重写(Overriding)
时机编译时运行时
作用域同一类或全局范围继承关系中的子类和父类
参数要求参数类型、数量或顺序不同与父类方法签名完全一致
虚函数无需虚函数必须是虚函数或纯虚函数
主要功能通过不同参数处理相同逻辑子类修改父类的行为

3.1 构造函数的种类及作用

构造函数是类的一部分,用于在对象创建时初始化对象的状态。C++ 中有以下几种类型的构造函数:

1. 默认构造函数(Default Constructor)

默认构造函数是不带参数或所有参数都有默认值的构造函数,用于在没有显式传递参数时初始化对象。

  • 作用:默认构造函数用于初始化对象为一个默认状态。当没有自定义构造函数时,编译器会自动生成一个默认的构造函数。

示例

class Person {
public:
    Person() {
        cout << "Default constructor called!" << endl;
    }
};

int main() {
    Person p;  // 调用默认构造函数
}
 

2. 带参数的构造函数(Parameterized Constructor)

带参数的构造函数允许在对象创建时传递参数,并根据参数的值初始化对象的属性。

  • 作用:带参数构造函数用于灵活地初始化对象,传递不同的参数以定制化对象的状态。

示例

class Person {
public:
    string name;
    int age;
    
    Person(string n, int a) {  // 带参数构造函数
        name = n;
        age = a;
    }
};

int main() {
    Person p("Alice", 30);  // 创建对象时传递参数
    cout << p.name << ", " << p.age << endl;
}
 

3. 拷贝构造函数(Copy Constructor)

拷贝构造函数用于通过已有对象初始化新对象,即使用一个对象的值来创建另一个相同类型的对象。其形式为 ClassName(const ClassName &other)

  • 作用:在需要创建一个新对象并将已有对象的数据复制给它时使用,常见于对象作为函数参数或返回值的场景。

示例

class Person {
public:
    string name;
    
    // 拷贝构造函数
    Person(const Person &other) {
        name = other.name;
    }
};

int main() {
    Person p1("Alice");
    Person p2 = p1;  // 调用拷贝构造函数
    cout << p2.name << endl;
}
 

4. 移动构造函数(Move Constructor)

移动构造函数用于将资源从一个对象“移动”到另一个对象,避免不必要的复制。其形式为 ClassName(ClassName &&other),传递的是右值引用。

  • 作用:在需要“移动”资源(如堆内存)而不是复制时,可以显著提高性能。

示例

class Person {
public:
    string* name;
    
    Person(string n) {
        name = new string(n);
    }

    // 移动构造函数
    Person(Person&& other) {
        name = other.name;
        other.name = nullptr;  // 释放原对象的资源
    }

    ~Person() {
        delete name;
    }
};

int main() {
    Person p1("Alice");
    Person p2 = std::move(p1);  // 调用移动构造函数
}
 

3.2 析构函数(Destructor)

析构函数在对象的生命周期结束时被调用,用于释放资源。析构函数的名称与类名相同,但前面有个波浪符号 ~,且不接受参数。

作用
  • 用于清理对象在生存期内分配的资源(如内存、文件句柄、网络连接等),防止资源泄露。

示例

class Person {
public:
    Person() {
        cout << "Constructor called!" << endl;
    }

    ~Person() {
        cout << "Destructor called!" << endl;
    }
};

int main() {
    Person p;  // 构造函数会在对象创建时调用,析构函数会在对象销毁时调用
}
 

3.3 只定义析构函数时,自动生成哪些构造函数?

如果在类中只定义析构函数而没有定义构造函数,编译器将自动生成以下几种构造函数:

  1. 默认构造函数:如果类中没有任何构造函数,编译器将生成一个默认构造函数,用于默认初始化对象。
  2. 拷贝构造函数:如果类没有自定义的拷贝构造函数,编译器将生成一个浅拷贝的拷贝构造函数。
  3. 拷贝赋值运算符:如果没有自定义的赋值运算符,编译器会生成一个默认的赋值运算符进行浅拷贝。
  4. 移动构造函数(如果需要):编译器可能会根据需要生成一个默认的移动构造函数。
  5. 移动赋值运算符(如果需要):类似于移动构造函数。

注意:如果类中有指针或其他需要深拷贝的资源管理,默认生成的构造函数和赋值运算符可能会导致资源管理问题(如重复释放内存)。

3.4 一个类默认会生成哪些函数?

当你定义一个类但没有显式定义构造函数、析构函数或赋值运算符时,编译器会自动生成以下函数:

  1. 默认构造函数:用于在不传递参数时初始化对象。如果类没有定义任何构造函数,编译器会生成一个默认构造函数。

  2. 拷贝构造函数:用于通过另一个同类型的对象初始化新对象。默认的拷贝构造函数执行浅拷贝,将对象的所有成员逐字复制。

  3. 拷贝赋值运算符(operator=):用于将一个对象赋值给另一个相同类型的对象。编译器生成的默认赋值运算符同样执行浅拷贝。

  4. 析构函数:用于销毁对象并释放资源。默认析构函数不会执行任何特定操作,只会清理对象的内存。

  5. 移动构造函数:如果类使用了动态资源管理(如指针),并且你未定义移动构造函数,编译器可能会自动生成一个移动构造函数。

  6. 移动赋值运算符:同样地,如果类涉及动态资源,编译器可能会生成一个移动赋值运算符。

3.5 总结

函数类型自动生成的条件作用
默认构造函数如果没有任何构造函数初始化对象,所有成员初始化为默认值
拷贝构造函数如果没有自定义拷贝构造函数使用已有对象初始化新对象,浅拷贝
拷贝赋值运算符如果没有自定义赋值运算符将一个对象赋值给另一个对象,浅拷贝
析构函数如果没有自定义析构函数在对象生命周期结束时调用,释放资源
移动构造函数如果没有自定义移动构造函数,且需要时生成将资源从一个对象“移动”到另一个对象,避免不必要的复制
移动赋值运算符如果没有自定义移动赋值运算符,且需要时生成将资源从一个对象移动给另一个对象

4.1 C++ 类对象的初始化顺序

在 C++ 中,类对象的初始化顺序是确定的,并且遵循以下规则:

  1. 基类先于派生类

    • 如果类有继承关系,则先初始化基类的部分,再初始化派生类的部分。
    • 初始化顺序是基类先于派生类
  2. 成员变量按照声明顺序初始化

    • 类的成员变量按照它们在类中的声明顺序进行初始化,而不是按照它们在初始化列表中的顺序。
  3. 初始化列表优先于构造函数体

    • 如果类的构造函数包含初始化列表,成员变量在进入构造函数体之前就会被初始化。

示例

#include <iostream>
using namespace std;

class Base {
public:
    Base() {
        cout << "Base class initialized" << endl;
    }
};

class Derived : public Base {
public:
    int x;
    int y;

    // 使用初始化列表
    Derived(int a, int b) : x(a), y(b) {
        cout << "Derived class initialized" << endl;
    }
};

int main() {
    Derived d(10, 20);
    return 0;
}

输出顺序

Base class initialized
Derived class initialized

这里的顺序是:

  • 基类 Base 先被初始化。
  • 派生类 Derived 中的成员 xy 按照声明顺序初始化。
  • 构造函数体最后执行。

4.2 多重继承下的初始化顺序

在多重继承中,基类的初始化顺序与它们在类声明中的顺序一致,而不是在初始化列表中的顺序。

示例

#include <iostream>
using namespace std;

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

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

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

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

输出顺序

Base1 class initialized
Base2 class initialized
Derived class initialized
 

在多重继承的情况下,Base1Base2 的初始化顺序与它们在 Derived 类中的声明顺序一致(即从左到右),而派生类 Derived 最后被初始化。

4.3 类型转换:上向下转型和向下转型

4.3.1 上向转型(Upcasting)

上向转型是指将派生类对象的指针或引用转换为基类类型。这种转换是安全的,因为派生类对象包含基类的部分。

  • 特点
    • 隐式转换:编译器自动进行上向转型,无需显式指定。
    • 转换后,只有基类的成员可以通过该指针或引用访问。

示例

class Base {
public:void show() {cout << "Base class" << endl;}
};class Derived : public Base {
public:void show() {cout << "Derived class" << endl;}
};int main() {Derived d;Base* basePtr = &d;  // 上向转型basePtr->show();     // 调用基类的 show() 方法
}

输出

Base class

在上向转型时,即使派生类重写了基类的方法,使用基类指针调用的仍然是基类的方法,除非基类的方法是虚函数virtual)。

4.3.2 下向转型(Downcasting)

下向转型是指将基类对象的指针或引用转换为派生类类型。这种转换不安全,因为基类对象可能并不包含派生类的部分,因此需要使用 dynamic_cast 来确保转换的安全性。

  • 特点
    • 下向转型需要显式进行。
    • 使用 dynamic_cast 来确保安全性,失败时返回 nullptr
    • 通常涉及多态和虚函数。

示例

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

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

int main() {
    Base* basePtr = new Derived();  // 上向转型
    Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);  // 下向转型
    
    if (derivedPtr) {
        derivedPtr->show();  // 输出:Derived class
    } else {
        cout << "Failed to cast" << endl;
    }
    
    delete basePtr;
}
 

在这个例子中,dynamic_cast 确保下向转型的安全性,如果转换失败,derivedPtr 会是 nullptr

4.4 深拷贝和浅拷贝

4.4.1 浅拷贝(Shallow Copy)

浅拷贝只复制对象的,对于指针成员,它只复制指针本身的地址,而不复制指针所指向的对象。这可能导致多个对象指向同一个内存区域,进而引发资源共享问题或重复释放的问题。

示例

class Person {
public:
    char* name;

    Person(const char* n) {
        name = new char[strlen(n) + 1];
        strcpy(name, n);
    }

    // 浅拷贝构造函数(默认)
    Person(const Person& other) {
        name = other.name;  // 只复制指针地址,未分配新内存
    }

    ~Person() {
        delete[] name;  // 重复释放可能会导致错误
    }
};
 

问题:当一个对象被销毁时,指针所指向的内存会被释放,如果有多个对象共享相同的指针地址,会导致重复释放内存的错误。

4.4.2 深拷贝(Deep Copy)

深拷贝不仅复制对象本身的值,还为每个指针成员分配新的内存,并复制指针指向的内容。这样每个对象都有独立的资源,不会共享同一个内存区域。

实现深拷贝的拷贝构造函数
class Person {
public:char* name;Person(const char* n) {name = new char[strlen(n) + 1];strcpy(name, n);}// 深拷贝构造函数Person(const Person& other) {name = new char[strlen(other.name) + 1];  // 分配新内存strcpy(name, other.name);  // 复制内容}~Person() {delete[] name;  // 正常释放内存}
};int main() {Person p1("Alice");Person p2 = p1;  // 调用深拷贝构造函数return 0;
}

深拷贝的优点

  • 每个对象都拥有独立的内存资源,不会互相影响。
  • 避免了共享指针带来的资源管理问题,如重复释放。

4.5 总结

概念描述
初始化顺序基类先于派生类,成员按照声明顺序初始化,初始化列表先于构造函数体。
多重继承初始化顺序基类按声明顺序初始化,派生类最后初始化。
上向转型将派生类对象转换为基类类型,隐式转换,常用于多态。
下向转型将基类对象转换为派生类类型,使用 dynamic_cast 进行安全转换。
浅拷贝只复制指针地址,多个对象共享同一块内存,可能导致资源管理问题。
深拷贝为每个指针成员分配新的内存并复制内容,确保每个对象有独立的资源,避免共享指针问题。

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

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

相关文章

element plus的el-select分页

摘要&#xff1a; el-select的数据比较多的时候&#xff0c;必须要分页&#xff0c;处理方案有全部数据回来&#xff0c;或者添加搜索功能&#xff0c;但是就有个问题就是编辑的时候回显问题&#xff0c;必须要保证select的数据有对应的id与name匹配回显&#xff01; <el-fo…

计算机网络-VRRP实验配置

前面我们大致学习了VRRP的概念和基本原理&#xff0c;但是网络这块就是要多敲命令多用才能印象深刻&#xff0c;今天开始进行一些实验配置&#xff0c;结合日常工作的场景分析VRRP在实际工作中的应用。 一、典型VRRP虚拟网关拓扑 相比于传统单网关&#xff0c;采用VRRP虚拟网关…

Qt/C++编写的mqtt调试助手使用说明

一、使用说明 第一步&#xff0c;选择协议前缀&#xff0c;可选mqtt://、mqtts://、ws://、wss://四种&#xff0c;带s结尾的是走ssl通信&#xff0c;ws表示走websocket通信。一般选默认的mqtt://就好。第二步&#xff0c;填写服务所在主机地址&#xff0c;可以是IP地址也可以…

2024.10月11日--- SpringMVC拦截器

拦截器 1 回顾过滤器&#xff1a; Servlet规范中的三大接口&#xff1a;Servlet接口&#xff0c;Filter接口、Listener接口。 过滤器接口&#xff0c;是Servlet2.3版本以来&#xff0c;定义的一种小型的&#xff0c;可插拔的Web组件&#xff0c;可以用来拦截和处理Servlet容…

Python 自动排班表格(代码分享)

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

CentOS安装NVIDIA驱动、CUDA以及nvidia-container-toolkit

0.提前准备 0.1.更新yum源&#xff08;以阿里为例&#xff09; 0.1.1 备份当前的yum源 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 0.1.2 下载新的CentOS-Base.repo 到/etc/yum.repos.d/ CentOS 5 wget -O /etc/yum.repos.d/CentOS-Base…

ORM框架简介

什么是ORM&#xff1f; ORM&#xff08;Object-Relational Mapping&#xff0c;对象关系映射&#xff09;是一种编程技术&#xff0c;用于在关系数据库和对象程序语言之间转换数据。ORM框架允许开发者以面向对象的方式来操作数据库&#xff0c;而不需要编写复杂的SQL语句。简单…

【Linux】命令行下的增删查改之“查看”

致谢:Linux常用命令大全(手册) – 真正好用的Linux命令在线查询网站 提供的命令查询 头部内容获取(head) head命令的功能是显示文件开头的内容&#xff0c;默认值为前10行。 指令参数&#xff1a; -n 定义显示行数 -c 指定显示头部内容的字符数 -v 总是显示文件名的头信…

告别手动计数:智能统计模型用量,释放设计潜力

添加HanTop-MKT&#xff0c;免费获取统计零件数量模型 非标设备行业的设计BOM因为涉及物料采购与装配数量要求&#xff0c;往往面临着需要数据准确性的严格要求&#xff0c;在缺乏自动化工具情况下&#xff0c;手动统计零件用量变得更加困难&#xff0c;且数据准确性得不到保障…

【uniapp】设置公共样式,实现公共背景等

目录 1、 全局渐变背景色 2.1 创建common目录 2.2 在common下新建style和images等目录 2.3 在style下新建common-style.scss 2.4 common-style输入全局渐变颜色 2.5 引入样式 2.6 业务页面引入 2.7 展示 2、全局字体颜色 2.1 新建base-style.scss文件 2.2 设置base-…

07 django管理系统 - 部门管理 - 搜索部门

在dept_list.html中&#xff0c;添加搜索框 <div class"container-fluid"><div style"margin-bottom: 10px" class"clearfix"><div class"panel panel-default"><!-- Default panel contents --><div clas…

Redis 其他类型 渐进式遍历

我们之前已经学过了Redis最常用的五个类型了&#xff0c;然而Redis还有一些在特定场景下比较好用的类型 Redis最关键的五个数据类型&#xff1a; 上面的类型是非常常用&#xff0c;很重要的类型。 除此之外的其他类型不常用&#xff0c;只是在特定的场景能够发挥用处&#…

无极低码课程【java(jdk)windows下安装及环境变量配置】

在Windows环境中安装JDK 7教程 Java Development Kit (JDK) 是开发Java应用程序所必需的工具包。本教程将指导您在Windows操作系统上安装JDK 7。 准备工作 下载JDK 7安装包 访问 Oracle官方网站 下载JDK 8的安装包。选择适合您操作系统的安装包(例如 jdk-7u80-windows-x64.ex…

vmware虚拟机 报错:客户机操作系统已禁用 CPU,请关闭或重置虚拟机 的解决方法

打开cpu虚拟化全部进行勾选 ctrl e 进行关机 勾选上打开就好了 如果没有那个选项 关机>打开虚拟机>管理>更改硬件兼容性> 往小处改改> >更改此虚拟机

[LeetCode] 515. 在每个树行中找最大值

题目描述&#xff1a; 给定一棵二叉树的根节点 root &#xff0c;请找出该二叉树中每一层的最大值。 示例1&#xff1a; 输入: root [1,3,2,5,3,null,9] 输出: [1,3,9]示例2&#xff1a; 输入: root [1,2,3] 输出: [1,3]提示&#xff1a; 二叉树的节点个数的范围是 [0,10…

基于SpringBoot的个性化健康建议平台

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理基于智能推荐的卫生健康系统的相关信息成为…

OpenTrans

比较的方法Cat-Seg不好复现

Spring 实现 3 种异步流式接口,干掉接口超时烦恼

大家好&#xff0c;我是小富&#xff5e; 如何处理比较耗时的接口&#xff1f; 这题我熟&#xff0c;直接上异步接口&#xff0c;使用 Callable、WebAsyncTask 和 DeferredResult、CompletableFuture等均可实现。 但这些方法有局限性&#xff0c;处理结果仅返回单个值。在某…

幸运7游戏模拟 python

题目&#xff1a; 幸运"7"游戏,用计算机模拟掷骰子的过程&#xff0c;测算两个骰子点数之和为7的概率。 游戏规则是你丢两个骰子&#xff0c;如果其点数之和为7你就赢4元&#xff0c;不是7你就输1元。 假设你刚开始有10元&#xff0c;当全部输掉为0元的时候游戏结…

【网络安全】1,600$:Auth0 错误配置

未经许可,不得转载。 文章目录 前言正文漏洞案例修复建议前言 Auth0 是一个广泛用于网站和应用程序的身份验证平台,负责管理用户身份并确保其服务的安全访问。该平台提供了多种工作流程,以无缝集成登录和注册流程。 在 Auth0 中创建新应用时,注册选项默认启用。当系统禁用…