c++类全面讲解

文章目录

  • 前言
  • 类的基本概念
    • 基本结构
    • 类与结构体的区别
    • 示例代码
  • 类的属性和方法
    • 属性(成员变量)
    • 方法(成员函数)
    • 访问修饰符
    • 示例代码
  • 类的构造函数和析构函数
    • 构造函数
    • 析构函数
    • 示例代码
  • 类的构造函数重载
    • 重载构造函数
    • 示例代码
  • 类中的拷贝构造函数和赋值运算符
    • 拷贝构造函数
    • 赋值运算符
    • 示例代码
  • 类中的静态成员
      • 静态成员变量
      • 静态成员函数
      • 示例代码
  • 类中的继承
    • 继承的类型
    • 示例代码公有继承
    • 示例代码:私有继承
    • 示例代码:保护继承
  • 多态
    • 多态的类型
    • 虚函数和动态多态
      • 示例代码
  • 友元函数和友元类
    • 友元函数
    • 友元类
    • 示例代码
  • 运算符重载
    • 运算符重载的基本概念
    • 示例代码
  • 模板类
    • 模板类的基本概念
    • 示例代码
  • 高级特性
    • 虚继承
    • 多重继承
    • 抽象类
    • 接口
    • 虚继承示例代码
    • 多重继承
    • 示例代码:多重继承
    • 抽象类
    • 示例代码:抽象类
    • 接口
    • 示例代码:接口
  • 总结
    • 万字长文,朋友们点赞、关注啊!!!


前言

这次主要讲类的基础、构造函数与析构函数的使用,以及继承和多态。


类的基本概念

在C++中,类是一种用于创建对象的数据结构,它封装了数据(属性)和操作这些数据的方法(函数)。类定义了对象的特性和行为。

基本结构

一个类通常包括以下部分:

  • 数据成员:代表对象的属性。
  • 成员函数:定义对象可以执行的操作。
  • 访问修饰符:如 publicprivateprotected,用于控制成员的访问权限。

类与结构体的区别

  • 在C++中,类和结构体非常相似,但一个主要区别是默认的访问权限。在类中,默认的成员访问权限是私有(private),而在结构体中,默认是公有(public)。

示例代码

下面是一个简单的类定义和使用的例子:

#include <iostream>
#include <string>// 定义一个类
class Person {
public:     // 公有访问修饰符// 构造函数Person(std::string name, int age) : name(name), age(age) {}// 成员函数void introduce() {std::cout << "Name: " << name << ", Age: " << age << std::endl;}private:    // 私有访问修饰符// 数据成员std::string name;int age;
};int main() {// 创建Person类的对象Person person("Alice", 30);// 调用成员函数person.introduce();return 0;
}

在这个例子中:

  • Person 类有两个私有数据成员:nameage
  • 类有一个公共构造函数,它接受 nameage 参数来初始化对象。
  • introduce 是一个公共成员函数,用于打印对象的信息。
  • main 函数中,我们创建了一个 Person 对象并调用了它的 introduce 方法。

当然,让我们详细探讨C++中类的属性和方法,同时提供一个完整的代码示例。

类的属性和方法

属性(成员变量)

  • 属性是类中定义的变量,它们代表对象的状态或特性。在类中声明属性,可以使得每个对象都有自己的一套属性。

方法(成员函数)

  • 方法是类中定义的函数,它们用于执行操作,可以访问和修改对象的属性。方法提供了与对象交互的接口。

访问修饰符

  • 访问修饰符决定了类成员的访问级别。最常用的有三种:
    • public:可以被任何外部代码访问。
    • private:只能被类的其他成员(方法或友元)访问。
    • protected:只能被类本身、派生类及友元访问。

示例代码

下面是一个类的属性和方法的简单示例:

#include <iostream>
#include <string>class Car {
public:// 构造函数Car(std::string model, int year) : model(model), year(year) {}// 公共方法void displayInfo() {std::cout << "Car Model: " << model << ", Year: " << year << std::endl;}// 设置年份void setYear(int newYear) {year = newYear;}// 获取年份int getYear() {return year;}private:// 私有属性std::string model;int year;
};int main() {// 创建Car类的对象Car myCar("Toyota", 2020);// 调用公共方法myCar.displayInfo();// 更新年份myCar.setYear(2022);// 再次显示信息myCar.displayInfo();return 0;
}

在这个例子中:

  • Car 类有两个私有属性:modelyear
  • 公共方法 displayInfo 用于打印汽车信息。
  • 另外两个公共方法 setYeargetYear 分别用于设置和获取年份。
  • main 函数中,我们创建了一个 Car 对象,展示了如何使用这些方法来操作对象的状态。

类的构造函数和析构函数

构造函数

  • 构造函数在创建类的对象时自动调用。
  • 它的主要作用是初始化对象的属性。
  • 构造函数的名称与类名相同,并且没有返回类型。
  • 可以有参数,也可以没有(默认构造函数)。
  • 可以进行重载,即一个类可以有多个构造函数,只要它们的参数列表不同。

析构函数

  • 析构函数在对象销毁时自动调用。
  • 它的主要作用是进行清理工作,如释放资源、关闭文件等。
  • 析构函数的名称是类名前加上波浪符号(~),没有返回类型,也不接受参数。
  • 每个类只能有一个析构函数。

示例代码

下面是一个包含构造函数和析构函数的C++类示例:

#include <iostream>
#include <string>class Book {
public:// 构造函数Book(std::string title, std::string author) : title(title), author(author) {std::cout << "Book '" << title << "' by " << author << " created." << std::endl;}// 析构函数~Book() {std::cout << "Book '" << title << "' by " << author << " destroyed." << std::endl;}// 显示书籍信息的方法void displayInfo() {std::cout << "Title: " << title << ", Author: " << author << std::endl;}private:std::string title;std::string author;
};int main() {// 创建Book对象Book myBook("1984", "George Orwell");// 使用对象的方法myBook.displayInfo();// 对象myBook在这里会被自动销毁,调用析构函数return 0;
}

在这个例子中:

  • Book 类有两个私有属性:titleauthor
  • 它有一个构造函数,用于初始化这些属性,并打印一条创建消息。
  • 还有一个析构函数,当对象被销毁时,它会打印一条销毁消息。
  • main 函数中创建了一个 Book 对象,然后调用了它的 displayInfo 方法。程序结束时,myBook 对象的析构函数会被自动调用。

构造函数和析构函数使得对象的初始化和销毁自动执行,有助于管理资源和避免内存泄漏。

类的构造函数重载

在C++中,可以为一个类定义多个构造函数,只要它们的参数列表不同。这就是所谓的构造函数重载。重载构造函数允许以不同的方式初始化同一个类的对象。

重载构造函数

  • 目的:提供不同的方式来初始化对象。
  • 方法:在同一个类中定义多个构造函数,每个构造函数的参数类型、个数或顺序至少有一个不同。
  • 使用场景:需要根据不同的数据或条件创建对象时非常有用。

示例代码

下面的例子演示了如何在C++中重载构造函数:

#include <iostream>
#include <string>class Rectangle {
public:// 构造函数1:接受两个参数Rectangle(int w, int h) : width(w), height(h) {std::cout << "Rectangle created with width " << width << " and height " << height << std::endl;}// 构造函数2:接受一个参数explicit Rectangle(int size) : width(size), height(size) {std::cout << "Square created with size " << size << std::endl;}// 方法:计算面积int getArea() const {return width * height;}private:int width, height;
};int main() {// 使用第一个构造函数Rectangle rect1(10, 20);// 使用第二个构造函数Rectangle rect2(10);std::cout << "Area of rect1: " << rect1.getArea() << std::endl;std::cout << "Area of rect2: " << rect2.getArea() << std::endl;return 0;
}

在这个例子中:

  • Rectangle 类有两个构造函数。第一个接受两个参数(宽和高),第二个仅接受一个参数(正方形的边长)。
  • 两个构造函数具有不同的参数列表,因此它们被重载了。
  • main 函数中,我们分别使用两种不同的构造函数创建了两个 Rectangle 对象。

通过重载构造函数,Rectangle 类可以灵活地根据提供的参数来初始化对象,使得对象的创建更加灵活。

类中的拷贝构造函数和赋值运算符

拷贝构造函数

  • 拷贝构造函数在创建类的一个新对象时使用另一个对象的内容进行初始化时调用。
  • 它通常有一个参数,即对同类型对象的引用。
  • 如果没有自定义拷贝构造函数,编译器会提供一个默认的拷贝构造函数,进行逐成员的拷贝。

赋值运算符

  • 赋值运算符用于将一个对象的内容复制到另一个已经存在的对象中。
  • 与拷贝构造函数不同,赋值运算符在对象已经初始化后使用。
  • 如果不自定义赋值运算符,编译器将提供一个默认的,进行逐成员的赋值。

示例代码

下面是一个展示拷贝构造函数和赋值运算符使用的示例:

#include <iostream>
#include <string>class Person {
public:// 构造函数Person(std::string name) : name(name) {}// 拷贝构造函数Person(const Person& other) : name(other.name) {std::cout << "Copied Person: " << name << std::endl;}// 赋值运算符Person& operator=(const Person& other) {if (this != &other) { // 防止自赋值name = other.name;}return *this;}// 显示姓名void printName() {std::cout << "Person's name is: " << name << std::endl;}private:std::string name;
};int main() {Person person1("Alice");Person person2 = person1; // 调用拷贝构造函数Person person3("Bob");person3 = person1; // 调用赋值运算符person1.printName();person2.printName();person3.printName();return 0;
}

在这个示例中:

  • Person 类包含一个构造函数、一个拷贝构造函数和一个赋值运算符。
  • 当我们用 person1 初始化 person2 时,调用了拷贝构造函数。
  • 当我们将 person1 赋值给 person3 时,调用了赋值运算符。

拷贝构造函数和赋值运算符对于管理资源(如动态分配的内存)非常重要,可以防止诸如浅拷贝和资源泄漏等问题。在设计类时,根据需要合理地实现这两个函数是非常重要的。

类中的静态成员

静态成员可以是变量或函数,它们属于类本身,而不是类的任何特定对象。这意味着静态成员由类的所有对象共享。

静态成员变量

  • 静态成员变量是类的所有对象共享的变量。它们不属于任何单个对象。
  • 静态变量在程序的生命周期内只被初始化一次,并且在类的所有对象之间共享。
  • 它们通常用于存储类级别的信息,比如对象计数。

静态成员函数

  • 静态成员函数可以在不创建类的对象的情况下调用。
  • 它们只能访问静态成员变量和其他静态成员函数。
  • 通常用于执行不依赖于对象状态的操作。

示例代码

以下是一个包含静态成员的C++类的示例:

#include <iostream>class MyClass {
public:// 构造函数MyClass() {// 每创建一个对象,计数器增加objectCount++;}// 静态成员函数static int getObjectCount() {return objectCount;}private:// 静态成员变量static int objectCount;
};// 初始化静态成员变量
int MyClass::objectCount = 0;int main() {MyClass obj1;MyClass obj2;MyClass obj3;// 直接通过类名调用静态成员函数std::cout << "Total objects: " << MyClass::getObjectCount() << std::endl;return 0;
}

在这个例子中:

  • MyClass 类有一个静态成员变量 objectCount,用于跟踪创建的对象数量。
  • 类中有一个静态成员函数 getObjectCount,它返回 objectCount 的值。
  • main 函数中,我们创建了三个 MyClass 的对象,并通过类名直接调用 getObjectCount 来显示创建的对象总数。

类中的继承

继承是面向对象编程的一个基本概念,它允许基于一个类(基类)创建一个新的类(派生类)。这种机制提供了代码重用和层次化分类的能力。

继承的类型

  • 公有继承(public inheritance):基类的公有成员和保护成员在派生类中保持其原有的访问级别。
  • 保护继承(protected inheritance):基类的公有成员和保护成员在派生类中变成保护成员。
  • 私有继承(private inheritance):基类的公有成员和保护成员在派生类中变成私有成员。

示例代码公有继承

#include <iostream>
#include <string>// 基类
class Animal {
public:Animal(std::string name) : name(name) {}void eat() {std::cout << name << " is eating." << std::endl;}protected:std::string name;
};// 派生类
class Dog : public Animal {
public:Dog(std::string name) : Animal(name) {}void bark() {std::cout << name << " is barking." << std::endl;}
};int main() {Dog myDog("Buddy");myDog.eat();  // 调用基类方法myDog.bark(); // 调用派生类方法return 0;
}

在这个例子中:

  • Animal 是一个基类,具有一个公有方法 eat 和一个受保护的成员变量 name
  • Dog 是从 Animal 公有继承而来的派生类。它继承了 Animal 的特性,并添加了自己的方法 bark
  • main 函数中,我们创建了一个 Dog 对象,可以调用从基类继承的 eat 方法以及派生类的 bark 方法。

当然,我可以提供私有继承和保护继承的示例,以进一步阐释这些继承类型在C++中的应用。

示例代码:私有继承

#include <iostream>
#include <string>// 基类
class Vehicle {
public:Vehicle(std::string type) : type(type) {}protected:std::string type;
};// 派生类 - 私有继承
class Car : private Vehicle {
public:Car(std::string type) : Vehicle(type) {}void showType() {std::cout << "Car type: " << type << std::endl; // 可以访问基类的保护成员}
};int main() {Car myCar("SUV");myCar.showType(); // 正确// 下面的代码将会产生编译错误,因为type在Car中是私有的// std::cout << myCar.type << std::endl;return 0;
}

示例代码:保护继承

#include <iostream>
#include <string>// 基类
class Device {
public:Device(std::string name) : name(name) {}protected:std::string name;
};// 派生类 - 保护继承
class Printer : protected Device {
public:Printer(std::string name) : Device(name) {}void printName() {std::cout << "Printer name: " << name << std::endl; // 可以访问基类的保护成员}
};int main() {Printer myPrinter("HP LaserJet");myPrinter.printName(); // 正确// 下面的代码将会产生编译错误,因为name在Printer中是保护的// std::cout << myPrinter.name << std::endl;return 0;
}

多态

多态是面向对象编程的一个核心概念,允许对象以不同的方式响应相同的消息(或方法调用)。在C++中,多态主要通过虚函数(virtual functions)实现。

多态的类型

  • 编译时多态:也称为静态多态,主要通过函数重载和运算符重载实现。
  • 运行时多态:也称为动态多态,主要通过虚函数和函数覆盖(override)实现。

虚函数和动态多态

  • 虚函数允许派生类重写(override)基类中的函数。
  • 使用虚函数时,类的行为将根据对象的实际类型,而非其声明类型来确定。
  • 动态多态只能通过指针或引用来实现。

示例代码

以下是一个展示C++中使用虚函数实现多态的示例:

#include <iostream>// 基类
class Shape {
public:// 虚函数virtual void draw() const {std::cout << "Drawing a shape." << std::endl;}// 虚析构函数virtual ~Shape() {}
};// 派生类1
class Circle : public Shape {
public:void draw() const override { // 重写虚函数std::cout << "Drawing a circle." << std::endl;}
};// 派生类2
class Rectangle : public Shape {
public:void draw() const override { // 重写虚函数std::cout << "Drawing a rectangle." << std::endl;}
};void drawShape(const Shape& shape) {shape.draw(); // 动态绑定
}int main() {Circle circle;Rectangle rectangle;drawShape(circle);    // 输出: Drawing a circle.drawShape(rectangle); // 输出: Drawing a rectangle.return 0;
}

在这个示例中:

  • Shape 是一个基类,具有一个虚函数 draw 和一个虚析构函数。
  • CircleRectangle 是从 Shape 派生的类,它们重写了 draw 方法。
  • drawShape 函数接受一个 Shape 类型的引用,并调用 draw 方法。由于 draw 是虚函数,实际调用的是对象的动态类型对应的方法,这就是多态的体现。

友元函数和友元类

友元在C++中是一种特殊的机制,允许特定的函数或类访问另一个类的私有(private)和保护(protected)成员。

友元函数

  • 友元函数不是类的成员,但它可以访问类的所有私有和保护成员。
  • 友元函数通过在类内部使用 friend 关键字声明。
  • 友元函数常用于操作两个类的私有数据,例如,重载某些运算符时。

友元类

  • 友元类的所有成员函数都可以访问另一个类的私有和保护成员。
  • 通过将一个类声明为另一个类的友元,可以提高类间的耦合性。
  • 友元关系不是相互的。如果类A是类B的友元,这并不意味着类B是类A的友元。

示例代码

以下是展示友元函数和友元类的示例:

#include <iostream>// 前向声明
class Box;class Contents {
public:explicit Contents(int value) : value(value) {}// 友元函数声明friend void showContents(const Box& b);private:int value;
};class Box {
public:explicit Box(int secret) : secret(secret) {}// 友元类声明friend class SecretInspector;private:int secret;Contents contents{123}; // 假设内容是私有的
};// 友元类
class SecretInspector {
public:void inspect(const Box& b) {std::cout << "Box secret: " << b.secret << std::endl;}
};// 友元函数实现
void showContents(const Box& b) {std::cout << "Box contents: " << b.contents.value << std::endl;
}int main() {Box myBox(42);SecretInspector inspector;inspector.inspect(myBox); // 访问Box的私有数据showContents(myBox); // 访问Box中Contents的私有数据return 0;
}

在这个示例中:

  • Box 类有一个私有成员 secret 和一个私有嵌套对象 contents
  • SecretInspector 类被声明为 Box 的友元类,因此它可以访问 Box 的所有私有成员。
  • showContents 函数被声明为 Box 的友元函数,因此它可以访问 Box 中的 contents 的私有成员。

运算符重载

运算符重载是一种形式的多态,允许你定义或改变运算符(如 +, -, *, / 等)在自定义类型(如类或结构体)上的行为。

运算符重载的基本概念

  • 目的:使自定义类型的对象可以使用标准运算符进行操作。
  • 方法:通过在类内定义一个特殊的成员函数或友元函数来实现。这个函数使用 operator 关键字后跟要重载的运算符符号。
  • 限制:不能创建新的运算符,只能重载已有的运算符。某些运算符(如 ::, .*, .?:)不能被重载。

示例代码

下面是一个如何重载加法运算符的示例:

#include <iostream>class Coordinate {
public:Coordinate(int x, int y) : x(x), y(y) {}// 运算符 '+' 重载Coordinate operator+(const Coordinate& other) const {return Coordinate(x + other.x, y + other.y);}// 输出坐标的友元函数friend std::ostream& operator<<(std::ostream& os, const Coordinate& coord);private:int x, y;
};// 输出运算符 '<<' 的重载
std::ostream& operator<<(std::ostream& os, const Coordinate& coord) {os << "(" << coord.x << ", " << coord.y << ")";return os;
}int main() {Coordinate point1(1, 2);Coordinate point2(3, 4);Coordinate sum = point1 + point2;std::cout << "Sum of coordinates: " << sum << std::endl;return 0;
}

在这个示例中:

  • Coordinate 类重载了加法运算符(+),使其能够用于两个坐标对象的加法。
  • 重载运算符+返回一个新的 Coordinate 对象,其 xy 值是两个操作数对象的 xy 值之和。
  • 同时,为了能够方便地打印坐标,重载了输出运算符(<<)。

模板类

模板类是一种强大的C++特性,允许编写与数据类型无关的通用代码。

模板类的基本概念

  • 目的:实现代码的泛型编程,即相同的代码可以用于不同的数据类型。
  • 方法:使用关键字 template 定义模板,后面跟一个或多个模板参数。
  • 使用场景:当你需要类似的行为对多种数据类型执行时,比如容器类(如 vectormap 等)。

示例代码

以下是一个定义和使用模板类的示例:

#include <iostream>// 模板类定义
template<typename T>
class Box {
public:Box(T content) : content(content) {}T getContent() {return content;}private:T content;
};int main() {// 使用模板类创建整数盒子Box<int> intBox(123);// 使用模板类创建字符串盒子Box<std::string> stringBox("Hello World");std::cout << "Integer Box contains: " << intBox.getContent() << std::endl;std::cout << "String Box contains: " << stringBox.getContent() << std::endl;return 0;
}

在这个示例中:

  • Box 类是一个模板类,它有一个模板参数 T。这个 T 可以在创建 Box 对象时被替换为任何类型。
  • 类中的 content 成员变量和 getContent 方法都使用了模板参数 T
  • main 函数中,我们创建了两个 Box 对象:一个用于整数 (int),另一个用于字符串 (std::string)。

高级特性

虚继承

  • 用途:解决多重继承中的菱形继承问题(即两个派生类继承自同一个基类,再被另一个类同时继承时的冗余和歧义问题)。
  • 实现:通过 virtual 关键字在继承时使用。

多重继承

  • 用途:允许一个类同时从多个基类继承。
  • 注意事项:需要小心处理由多个基类引入的复杂性,如成员冲突和菱形继承问题。

抽象类

  • 用途:作为基类,定义一个接口,但不完全实现所有功能,留给派生类去实现。
  • 特点:包含至少一个纯虚函数(用 = 0 表示)。

接口

  • 概念:在C++中通常通过完全抽象的类实现(即所有成员函数都是纯虚函数)。
  • 用途:定义一个类必须遵循的方法,但不提供任何实现。

虚继承示例代码

#include <iostream>class Base {
public:virtual void print() {std::cout << "Base" << std::endl;}
};// 虚继承
class Derived1 : virtual public Base {
public:void print() override {std::cout << "Derived1" << std::endl;}
};class Derived2 : virtual public Base {
public:void print() override {std::cout << "Derived2" << std::endl;}
};class Final : public Derived1, public Derived2 {
public:// 调用最近的覆盖void print() override {Derived2::print();}
};int main() {Final obj;obj.print(); // 输出 "Derived2"// 通过基类引用访问Base& baseRef = obj;baseRef.print(); // 同样输出 "Derived2"return 0;
}

在这个示例中:

  • Base 是一个基类,Derived1Derived2 都通过虚继承继承自 Base
  • Final 类从 Derived1Derived2 继承,解决了潜在的菱形继承问题。
  • print 方法在 Derived1Derived2 中被覆盖,并在 Final 中再次覆盖。

当然,我可以为多重继承、抽象类和接口提供相应的C++示例。

多重继承

多重继承允许一个类同时继承自多个基类。

示例代码:多重继承

#include <iostream>// 基类1
class Printer {
public:void print() {std::cout << "Printing document" << std::endl;}
};// 基类2
class Scanner {
public:void scan() {std::cout << "Scanning document" << std::endl;}
};// 派生类,从两个基类继承
class MultifunctionMachine : public Printer, public Scanner {};int main() {MultifunctionMachine mfm;mfm.print();  // 调用Printer的成员mfm.scan();   // 调用Scanner的成员return 0;
}

抽象类

抽象类至少包含一个纯虚函数,并且不能直接实例化。

示例代码:抽象类

#include <iostream>// 抽象基类
class Shape {
public:// 纯虚函数virtual void draw() const = 0;
};// 派生类
class Circle : public Shape {
public:void draw() const override {std::cout << "Drawing a circle." << std::endl;}
};int main() {Circle circle;circle.draw();  // 调用派生类的实现// Shape shape; // 错误:不能实例化抽象类return 0;
}

接口

在C++中,接口可以通过完全抽象的类(只有纯虚函数)实现。

示例代码:接口

#include <iostream>// 接口
class Drawable {
public:virtual void draw() const = 0;
};// 实现接口的类
class Rectangle : public Drawable {
public:void draw() const override {std::cout << "Drawing a rectangle." << std::endl;}
};int main() {Rectangle rect;rect.draw();  // 调用具体实现return 0;
}

总结

这次从类的基础知识开始,讲了构造函数、析构函数、以及类的成员变量和方法。

接着,讲了重载构造函数、拷贝构造函数、赋值运算符以及静态成员。

然后讲了继承、多态、友元类和友元函数。

最后模板类的概念,还有一些高级特性的基本概念

万字长文,朋友们点赞、关注啊!!!

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

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

相关文章

多模态大模型Vary:扩充视觉Vocabulary,实现更细粒度的视觉感知

前言 现代大型视觉语言模型(LVLMs)具有相同的视觉词汇- CLIP&#xff0c;它可以涵盖大多数常见的视觉任务。然而&#xff0c;对于一些需要密集和细粒度视觉感知的特殊视觉任务&#xff0c;例如文档级OCR或图表理解&#xff0c;特别是在非英语场景下&#xff0c;clip风格的词汇…

EDG浏览器:解决问题的全新选择

文章目录 文章目录 前言 一、 新版Edge简介是什么&#xff1f; 二、问题 为什么要卸载新版Edge浏览器&#xff1f; 卸载前的准备工作 Windows系统下的卸载方法 macOS系统下的卸载方法 2.读入数据 总结 前言 当然&#xff01;这是一篇关于新版Edge卸载指南的前言建议&#xff1…

Springboot集成RabbitMq二

接上一篇&#xff1a;Springboot集成RabbitMq一-CSDN博客 1、搭建项目-消费者 与之前一样 2、创建配置类 package com.wym.rabbitmqconsumer.utils;import org.springframework.amqp.core.Binding; import org.springframework.amqp.core.BindingBuilder; import org.spring…

JDK17 - 开发者视角,从 JDK8 ~ JDK17 都增加了哪些新特性

目录 前言 一、站在开发视角&#xff0c;从 JDK8 升级到 JDK17 都有哪些新特性 1.1、JDK8 新特性 1.1.1、Optional 类 a&#xff09;简介 b&#xff09;使用方法 c&#xff09;使用场景 1.2、JDK9 新特性 1.2.1、Optional - ifPresentOrElse 解决 if-else 1.2.2、Opt…

sql的性能优化之——distinct与group by

表A &#xff08;uid,bid) &#xff0c; uid代表&#xff1a;用户id bid代表&#xff1a;uid关注的用户id 表数据示例&#xff1a; uid bid 1 2 2 1 1 3 ------我的答案 selectt1.uid,t1.bid from tbl t1 join(selectuid,bidfrom tbl)t2 on t1.uid t2.bid…

Java程序设计阶段测试1

一、单选题&#xff08;共15题&#xff1b; 共30.0分&#xff09; 2.0分 1、以下哪个是Java应用程序main方法的有效定义? A.public static void main(); B.public static void main( String args ); C.public static void main( String args[] ); D.public static boolea…

Go Lang Fiber介绍

利用GoLang Fiber进行高性能Web开发 在不断发展的Web开发世界中&#xff0c;选择合适的框架至关重要。速度、简洁性和强大的功能集是每个开发者都追求的品质。在使用Go构建Web应用时&#xff0c;“Fiber”作为一个强大且轻量级的框架在众多选择中脱颖而出。在这份全面的指南中…

扩展:键盘录入笔记(next()、nextLine()、nextInt()、nextDouble())

文章目录 一&#xff0c;键盘录入涉及到的方法如下&#xff1a;1&#xff09;next&#xff08;&#xff09;、nextLine&#xff08;&#xff09;&#xff1a;代码示例&#xff1a;代码示例&#xff1a; 2&#xff09;nextInt&#xff08;&#xff09;&#xff1a;代码示例&…

java静态代理动态代理理解和例子解析包含demo

demo 基本背景 // 背景: 有一家甜品点,有2类机器,面包和蛋糕机器, 接口 BreadMachine CakeMachine // 面包机器有蜂蜜和黄油2种,类 BreadButter BreadBee // 蛋糕机器有水果和巧克力2种,类 CakeFruit CakeChocolate package com.ah.test.proxy.shop1; // 面包…

无辅源电压继电器 RWY-D2/3 180-440VAC 导轨安装 josef约瑟

RWY-D1型电压继电器&#xff1b; RWY-D2型电压继电器&#xff1b; 一、 概述 RWY-D系列电压继电器&#xff08;以下简称本继电器&#xff09;用于发电机、变压器和输电线的电器保护装置中&#xff0c;作为过电压保护或低电压闭锁的启动原件。本继电器为集成电路静态型继电器…

设计模式--适配器模式

适配器模式 适配器模式&#xff08;Adapter&#xff09;&#xff0c;将一个类的接口转换为客户希望的另一个接口&#xff0c;Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 系统的数据和行为都正确&#xff0c;但接口不符合时&#xff0c;我们应该…

Python入门学习篇(十七)——封装、继承、多态

1 封装 1.1 理解 属性和方法书写到类里面的操作即为封装 封装可以理解成私有化属性和私有化方法1.2 示例代码 class Person():p_num 0 # 用于统计数量def __init__(self, name, age, sex, job):# __name为私有化属性self.__name nameself.age ageself.sex sexself.job …

使用anaconda创建爬虫spyder工程

1.由于每个工程使用的环境都可能不一样&#xff0c;因此一个好的习惯就是不同的工程都创建属于自己的环境&#xff0c;在anaconda中默认的环境是base&#xff0c;我们现在来创建一个名为spyder的环境&#xff0c;专门用于爬虫工程&#xff1a; //括号中名字&#xff0c;代表当…

森林火灾数据集

野外火灾是全球范围内最致命和危险的天然灾害之一。它不仅对人类的生命安全构成严重威胁&#xff0c;还对动植物的生存环境造成巨大的破坏。预测火灾行为不仅可以帮助消防员更好地应对火情&#xff0c;还可以为未来的火灾预防和应对策略提供有力支持。 随着航空图像技术的不断…

Windows可以ping通ubuntu,但ubuntu无法ping通windows

使用了NAT网卡和桥接网卡&#xff0c;电脑连了WiFi&#xff0c;桥接网卡桥接到WLAN上&#xff0c;Windows可以ping通Ubuntu但反过来不行&#xff01; 1.可能是防火墙的问题&#xff0c;按照如下设置&#xff0c;无果 考虑是不是使用了两个网卡冲突了&#xff0c;取消NAT的链接 …

【笔记】书生·浦语大模型实战营——第一课

群公告 1月3日*更新 第一次课程视频链接&#xff1a;https://www.bilibili.com/video/BV1Rc411b7ns/&#xff0c;第一次课程只需要记笔记&#xff0c;没有作业。第一次课程(1月3日)和第二次课程(1月5日)到本周末(1月7日)截止&#xff0c;笔记记录在 知乎/CSDN/Github 或者任何你…

Mysql数据库:select from语句详解

Mysql数据库&#xff1a;select from语句详解 一、select from语句概述二、select from语句的基本用法三、select from语句的示例1、查询所有列2、查询特定列3、查询带有条件的数据&#xff08;过滤&#xff09;4、查询结果排序5、查询结果限制6、查询结果去重7、查询结果分组8…

【操作系统xv6】学习记录--实验1 Lab: Xv6 and Unix utilities--未完

ref:https://pdos.csail.mit.edu/6.828/2020/xv6.html 实验&#xff1a;Lab: Xv6 and Unix utilities 环境搭建 实验环境搭建&#xff1a;https://blog.csdn.net/qq_45512097/article/details/126741793 搭建了1天&#xff0c;大家自求多福吧&#xff0c;哎。~搞环境真是折磨…

QProgressDialog用法及结合QThread用法,四种线程使用

1 QProgressDialog概述 QProgressDialog类提供耗时操作的进度条。 进度对话框用于向用户指示操作将花费多长时间&#xff0c;并演示应用程序没有冻结。此外&#xff0c;QPorgressDialog还可以给用户一个中止操作的机会。 进度对话框的一个常见问题是很难知道何时使用它们;操作…

Document对象详解

前言 在前端开发中&#xff0c;DOM&#xff08;文档对象模型&#xff09;扮演着重要的角色。它允许我们使用JavaScript来与网页文档进行交互&#xff0c;实现动态的网页效果。DOM的核心部分之一就是Document对象&#xff0c;它代表了整个HTML文档。在本篇博客中&#xff0c;我们…