大话C++:第18篇 类继承与派生

news2024/11/29 18:35:40

1 类继承的概述

类继承(Class Inheritance)是面向对象编程(Object-Oriented Programming,OOP)中的一个核心概念。它允许我们创建一个新的类(子类或派生类),该类继承了另一个已存在的类(父类或基类)的属性和方法。这样,子类可以重用父类的代码,而无需重新编写。

为什么会有类的继承呢?包括以下原因:

  • 代码重用: 继承允许我们创建一个新的类,这个新类继承自一个已存在的类,从而重用那个类的代码。这意味着我们不需要从头开始编写所有代码,而是可以继承已有的代码,并在此基础上进行扩展或修改。这大大提高了代码的可重用性和开发效率。

  • 扩展性: 通过继承,我们可以创建更具体的子类,这些子类不仅包含父类的功能,还可以添加新的功能或覆盖父类的功能。这使得我们能够创建更灵活、更适应特定需求的类。例如,我们可以有一个表示一般形状的基类(如Shape),然后创建继承自Shape的子类来表示特定的形状(如CircleRectangle等)。

  • 多态性: 继承是多态性的一个关键组件。多态性意味着允许不同类型的对象对同一消息做出不同的响应。通过子类覆盖父类的方法,我们可以实现多态,这样当使用父类引用指向子类对象时,将调用子类的方法而不是父类的方法。这提供了更大的灵活性和可扩展性。

  • 组织代码: 继承有助于组织代码,使其更加清晰和易于理解。通过将相似的功能或行为封装在基类中,并在需要时进行扩展或特化,我们可以创建一个结构良好、易于维护的代码库。

  • 构建复杂的层次结构: 在现实世界中,很多事物都有层次结构关系。例如,动物是一个基类,而狗、猫等是动物类的子类。通过使用继承,我们可以模拟这种层次结构,并在代码中反映出来。这有助于创建更复杂、更逼真的模型。

  • 促进软件设计原则: 继承是面向对象设计原则(如单一职责原则、开放封闭原则、里氏替换原则等)的重要实现手段。通过合理地使用继承,我们可以遵循这些原则,从而创建出更加健壮、可扩展和可维护的软件系统。

2 基类和派生类定义

2.1 基类定义

基类(Base Class)是一个被其他类继承的类。在C++中,基类的定义与其他类的定义非常相似,但它被设计为被其他类继承。基类通常包含一些公共的(public)和保护的(protected)成员变量和成员函数,这些成员可以被派生类访问和使用。基类提供了一种代码重用和扩展的机制,允许派生类继承基类的属性和行为,并添加或覆盖自己的特定实现。

基类的定义语法格式如下:

class BaseClass 
{
public:
    // 公共构造函数
    BaseClass() 
    {
        // 初始化代码
    }

    // 公共析构函数(通常声明为虚函数)
    virtual ~BaseClass() 
    {
        // 清理代码
    }

    // 公共成员函数
    void publicFunction() 
    {
        // 公共成员函数的实现
    }

protected:
    // 受保护的成员变量
    int protectedVariable;

    // 受保护的成员函数
    void protectedFunction() 
    {
        // 受保护成员函数的实现
    }

private:
    // 私有成员变量
    int privateVariable;

    // 私有成员函数
    void privateFunction() 
    {
        // 私有成员函数的实现
    }
};

其中,

  • virtual 关键字用于声明析构函数为虚函数。这允许在删除指向派生类对象的基类指针时,调用正确的析构函数(派生类的析构函数),从而正确释放资源。

  • public 部分声明了公共构造函数 BaseClass() 和公共成员函数 publicFunction()。这些成员可以被任何对象(包括派生类对象)访问。

  • protected 部分声明了一个受保护的成员变量 protectedVariable 和一个受保护的成员函数 protectedFunction()。这些成员可以被派生类访问,但不能被派生类对象或基类对象之外的其他代码访问。

  • private 部分声明了一个私有成员变量 privateVariable 和一个私有成员函数 privateFunction()。这些成员只能被基类自身访问,不能被派生类或其他代码访问。

2.2 派生类定义

派生类(Derived Class)继承自一个或多个已有的类(称为基类或父类)。派生类继承了基类的所有公有(public)和保护(protected)成员(包括属性和方法),并可以添加新的成员或重写(override)基类的成员。

派生类的主要目的是实现代码的重用和扩展性。通过继承基类,派生类可以自动拥有基类中的所有非私有成员,这意味着派生类不需要重新实现这些成员,从而减少了代码量。同时,派生类还可以添加自己的新成员,以满足特定的需求。

派生类定义的语法格式如下:

// 基类定义
class BaseClass 
{
public:
    // 基类的构造函数
    BaseClass();
    
    // 基类的析构函数
    virtual ~BaseClass();    
    
    // 基类的公有成员
    void publicFunction();
    
protected:
    // 基类的受保护成员
    int protectedVariable;
    
private:
    // 基类的私有成员
    int privateVariable;
};

// 派生类定义
class DerivedClass : access_modifier BaseClass 
{
public:
    // 派生类的构造函数
    DerivedClass();
    
    // 派生类的析构函数
    virtual ~DerivedClass();
    
    // 派生类的公有成员
    void anotherPublicFunction();
    
protected:
    // 派生类的受保护成员
    int anotherProtectedVariable;
    
private:
    // 派生类的私有成员
    int anotherPrivateVariable;
    
    // 如果需要,可以在这里初始化基类成员
    using BaseClass::baseMemberFunction; // 访问基类中的成员
    
    // 重写基类中的虚函数
    void virtualFunction() override;
};

// 派生类的构造函数实现
DerivedClass::DerivedClass() : BaseClass() 
{
    // 派生类构造函数的初始化列表,可以调用基类的构造函数
    // 初始化派生类特有的成员
}

// 派生类的析构函数实现
DerivedClass::~DerivedClass()
{
    // 清理派生类特有的资源
}

// 派生类成员函数的实现
void DerivedClass::anotherPublicFunction() 
{
    // 实现派生类的另一个公有成员函数
}

// 重写基类虚函数的实现
void DerivedClass::virtualFunction() 
{
    // 实现重写的虚函数
}

其中, access_modifier指定继承方式,包括publicprotectedprivate三种方式。

 2.3 综合案例

我们先定义一个形状的Shape基类,它包含一些通用的属性和方法。然后,将从这个基类派生出CircleRectangle类,它们分别表示圆形和矩形,并添加各自特有的属性和方法。

#include <iostream>
#include <string>

// 基类Shape定义
class Shape 
{
public:
    // 构造函数
    Shape(const std::string& color) : color(color)
    {
    }
    
    // 析构函数
    virtual ~Shape()
    {
    }
    
    // 公有成员函数
    virtual void Draw() const 
    {
        std::cout << "Drawing a shape of color " << color << std::endl;
    }
    
    virtual double GetArea() const 
    {
        return 0.0; // 基类中的默认实现,可能会被派生类重写
    }
    
protected:
    // 受保护成员变量
    std::string color;
};

// 派生类圆形类Circle定义
class Circle : public Shape 
{
public:
    // 构造函数
    Circle(double r, const std::string& color) :Shape(color), radius(r)
    {
    }
    
    // 析构函数
    virtual ~Circle()
    {
    }

    // 重写基类的draw函数
    void Draw() const override 
    {
        std::cout << "Drawing a circle with radius " << radius 
            		<< " and color " << color << std::endl;
    }

    // 重写基类的getArea函数
    double GetArea() const override
    {
        return 3.14 * radius * radius; // 近似计算圆的面积
    }
    
private:
    // 私有成员变量
    double radius;    
};

// 派生类矩形类Rectangle定义
class Rectangle : public Shape 
{
public:
    // 构造函数
    Rectangle(double w, double h, const std::string& color) 
        : Shape(color), width(w), height(h) 
    {
    }

    // 重写基类的draw函数
    void Draw() const override 
    {
        std::cout << "Drawing a rectangle with width " << width 
            		<< " and height " << height 
            		<< " and color " << color << std::endl;
    }

    // 重写基类的getArea函数
    double GetArea() const override 
    {
        return width * height;
    }
    
private:
    // 私有成员变量
    double width;
    double height;    
};


int main() 
{
    // 创建圆形和矩形的对象
    Circle circle(5, "red");
    Rectangle rectangle(4, 6, "blue");

    // 调用对象的成员函数
    circle.Draw();
    std::cout << "Circle area: " << circle.GetArea() << std::endl;

    rectangle.Draw();
    std::cout << "Rectangle area: " << rectangle.GetArea() << std::endl;

    return 0;
}

其中,

  • Shape类提供了DrawGetArea方法的默认实现。

  • 派生类CircleRectangle通过重写(override关键字)这些方法提供特定的实现。

  • 如果基类Shape中的DrawGetArea不是虚函数(virtual关键字定义),那么,派生类CircleRectangle中使用了override关键字重写这些函数时,编译器会报错。

扩展知识:

在C++11及后续版本中,override关键字用于显式指示一个成员函数打算重写(override)基类中的虚函数。使用override关键字可以帮助编译器检查你的意图是否正确:如果基类中没有你要重写的虚函数,编译器将产生一个错误。

override关键字增加了代码的可读性和安全性,因为它明确表明了你正在重写基类中的某个函数,而不是创建一个新的、可能名称相似的函数。如果基类中的虚函数在未来的某个版本中被删除或更改了签名,使用override关键字的代码将不会编译通过,从而提醒开发者需要更新代码。

3 多态性

多态性(Polymorphism)是面向对象编程的四大基本特性之一, 它允许我们以统一的方式处理不同类型的对象,尽管这些对象在内部可能有不同的实现。

在C++中,多态性通常通过虚函数(virtual functions)和纯虚函数(pure Virtual functions)实现。多态性的类型包括:

  • 静态多态性(Static Polymorphism):也称为编译时多态性或前期绑定。主要通过函数重载和模板实现。

  • 动态多态性(Dynamic Polymorphism):也称为运行时多态性或后期绑定。主要通过虚函数和继承实现。当程序运行时,根据对象的实际类型来确定调用哪个函数。

3.1 虚函数

在C++中,虚函数(virtual function)是一种特殊的成员函数,它允许子类重新定义从父类继承的方法。这样,当通过子类的指针或引用来调用该函数时,将调用子类中的版本,而不是父类中的版本。这种机制称为动态绑定或运行时多态性。

虚函数在面向对象编程中非常有用,特别是当你想要通过基类指针或引用来操作派生类对象,并希望调用派生类中的函数实现时。

#include <iostream>
#include <string>

// 基类Shape定义
class Shape 
{
public:
    // 构造函数
    Shape(const std::string& color) : color(color)
    {
    }
    
    // 析构函数
    virtual ~Shape()
    {
    }
    
    // 公有成员函数
    virtual void Draw() const 
    {
        std::cout << "Drawing a shape of color " << color << std::endl;
    }
    
    virtual double GetArea() const 
    {
        return 0.0; // 基类中的默认实现,可能会被派生类重写
    }
    
protected:
    // 受保护成员变量
    std::string color;
};

// 派生类圆形类Circle定义
class Circle : public Shape 
{
public:
    // 构造函数
    Circle(double r, const std::string& color) :Shape(color), radius(r)
    {
    }
    
    // 析构函数
    virtual ~Circle()
    {
    }

    // 重写基类的draw函数
    void Draw() const override 
    {
        std::cout << "Drawing a circle with radius " << radius 
            		<< " and color " << color << std::endl;
    }

    // 重写基类的getArea函数
    double GetArea() const override
    {
        return 3.14 * radius * radius; // 近似计算圆的面积
    }
    
private:
    // 私有成员变量
    double radius;    
};

// 派生类矩形类Rectangle定义
class Rectangle : public Shape 
{
public:
    // 构造函数
    Rectangle(double w, double h, const std::string& color) 
        : Shape(color), width(w), height(h) 
    {
    }

    // 重写基类的draw函数
    void Draw() const override 
    {
        std::cout << "Drawing a rectangle with width " << width 
            		<< " and height " << height 
            		<< " and color " << color << std::endl;
    }

    // 重写基类的getArea函数
    double GetArea() const override 
    {
        return width * height;
    }
    
private:
    // 私有成员变量
    double width;
    double height;    
};


int main() 
{
    // 创建圆形和矩形的对象
    Shape *circle = new Circle(5, "red");
    Shape *rectangle = new Rectangle(4, 6, "blue");

    // 调用对象的成员函数
    circle->Draw();
    std::cout << "Circle area: " << circle->GetArea() << std::endl;

    rectangle->Draw();
    std::cout << "Rectangle area: " << rectangle->GetArea() << std::endl;
    
    // 释放内存
    delete circle;
    circle = nullptr;
    
    delete rectangle;
    rectangle = nullptr;

    return 0;
}

3.2 纯虚函数

纯虚函数(pure virtual function)是C++中一种特殊类型的虚函数,它在基类中没有提供实现(即没有函数体),并且要求所有派生类都提供该函数的实现。纯虚函数在声明时需要在函数声明后添加= 0,以表示它是一个纯虚函数。

由于纯虚函数没有实现,所以包含纯虚函数的类不能被实例化。这样的类通常被用作抽象基类(Abstract Base Class, ABC),其目的是为派生类提供一个公共的接口,而不需要为这个接口提供具体的实现。派生类需要实现所有的纯虚函数,才能成为可实例化的类。

#include <iostream>

// 抽象基类
class Shape 
{
public:
    // 纯虚函数声明
    // = 0 表示这是一个纯虚函数
    virtual void Draw() const = 0; 
};

// 派生类
class Circle : public Shape 
{
public:
    // 实现基类的纯虚函数
    void Draw() const override 
    {
        std::cout << "Drawing a circle" << std::endl;
    }
};

class Rectangle : public Shape 
{
public:
    // 实现基类的纯虚函数
    void Draw() const override 
    {
        std::cout << "Drawing a rectangle" << std::endl;
    }
};

int main() 
{
    // 抽象基类不能被实例化
    // Shape shape; // 编译错误,因为Shape包含纯虚函数

    // 创建派生类对象
    Circle circle;
    Rectangle rectangle;

    // 使用基类指针调用派生类的实现
    Shape* shapePtr;
    shapePtr = &circle;
    shapePtr->Draw(); // 输出 "Drawing a circle"

    shapePtr = &rectangle;
    shapePtr->Draw(); // 输出 "Drawing a rectangle"

    return 0;
}

纯虚函数的主要用途包括:

  • 定义接口:纯虚函数允许你定义一个接口,即一组函数签名,这些函数必须在任何派生类中得到实现。这提供了一种定义抽象行为的方式,该行为由派生类根据具体需求来实现。

  • 实现多态性:通过纯虚函数,可以在派生类中实现多态性。当基类指针或引用指向派生类对象时,调用纯虚函数将执行派生类中的实现。

  • 强制派生:纯虚函数确保任何试图实例化基类的尝试都会失败,从而强制用户创建派生类。

3.3 final修饰符

在C++中,final 是一个关键字,用于指定一个类不能被继承,或者虚函数不能被重写(override)。

注意final 关键字是在C++11中引入的,所以如果使用一个较旧的C++标准,可能需要更新编译器或使用一个更新的C++标准来使用 final 关键字。

3.3.1 不可继承的类

当在一个类声明中使用 final 关键字时,表示该类不能被其他类继承。

#include <iostream>
#include <string>

// 基类Shape定义
// 基类声明为final,不能被继承
class Shape final
{
public:
    // 构造函数
    Shape(const std::string& color) : color(color)
    {
    }
    
    // 析构函数
    virtual ~Shape()
    {
    }
    
    // 公有成员函数
    virtual void Draw() const 
    {
        std::cout << "Drawing a shape of color " << color << std::endl;
    }
    
    virtual double GetArea() const 
    {
        return 0.0; // 基类中的默认实现,可能会被派生类重写
    }
    
protected:
    // 受保护成员变量
    std::string color;
};

// 派生类圆形类Circle定义
// 由于基类不能被继承,任何继承编译直接报错
class Circle : public Shape 
{
public:
    // 构造函数
    Circle(double r, const std::string& color) :Shape(color), radius(r)
    {
    }
    
    // 析构函数
    virtual ~Circle()
    {
    }

    // 重写基类的draw函数
    void Draw() const override 
    {
        std::cout << "Drawing a circle with radius " << radius 
            		<< " and color " << color << std::endl;
    }

    // 重写基类的getArea函数
    double GetArea() const override
    {
        return 3.14 * radius * radius; // 近似计算圆的面积
    }
    
private:
    // 私有成员变量
    double radius;    
};

// 派生类矩形类Rectangle定义
// 由于基类不能被继承,任何继承编译直接报错
class Rectangle : public Shape 
{
public:
    // 构造函数
    Rectangle(double w, double h, const std::string& color) 
        : Shape(color), width(w), height(h) 
    {
    }

    // 重写基类的draw函数
    void Draw() const override 
    {
        std::cout << "Drawing a rectangle with width " << width 
            		<< " and height " << height 
            		<< " and color " << color << std::endl;
    }

    // 重写基类的getArea函数
    double GetArea() const override 
    {
        return width * height;
    }
    
private:
    // 私有成员变量
    double width;
    double height;    
};


int main() 
{
    // 创建圆形和矩形的对象
    Circle circle(5, "red");
    Rectangle rectangle(4, 6, "blue");

    // 调用对象的成员函数
    circle.Draw();
    std::cout << "Circle area: " << circle.GetArea() << std::endl;

    rectangle.Draw();
    std::cout << "Rectangle area: " << rectangle.GetArea() << std::endl;

    return 0;
}

 注意,由于 Shape 类被声明为 final,任何尝试继承自 Shape 的类都会导致编译错误。这就确保了 Shape 类的设计不会被意外地修改或扩展。

3.3.2 不可重写的虚函数

当一个虚函数在声明时使用 final 关键字时,表示它不能被任何派生类重写。

#include <iostream>

// 基类 Shape
class Shape {
public:
    Shape() = default;
    virtual ~Shape() = default;

    // 不可重写的虚函数
    virtual void DrawDefault() const final 
    {
        std::cout << "函数声明final,不可重写!" << std::endl;
    }

    // 可重写的虚函数
    virtual void Draw() const 
    {
        DrawDefault(); // 默认绘制实现
    }
};

// 派生类 Circle
class Circle : public Shape
{
public:
    // 基类中DrawDefault声明为了final,派生类尝试重写,会导致编译问题
    // void DrawDefault() const override
    // {
    //     std::cout << "Circle类尝试重写基类的中DrawDefault" << std::endl;
    // }
    
    void Draw() const override 
    {
        std::cout << "画一个圆形" << std::endl;
    }
};

// 派生类 Rectangle
class Rectangle : public Shape 
{
public:
    // 基类中DrawDefault声明为了final,派生类尝试重写,会导致编译问题
    // void DrawDefault() const override
    // {
    //     std::cout << "Rectangle类尝试重写基类的中DrawDefault" << std::endl;
    // }    
    
    void Draw() const override 
    {
        std::cout << "画一个方形" << std::endl;
    }
};

int main() 
{
    Shape* shapePtr = nullptr;

    // 创建 Circle 对象并通过基类指针调用 draw
    shapePtr = new Circle();
    shapePtr->Draw();
    delete shapePtr;
    shapePtr = nullptr;

    // 创建 Rectangle 对象并通过基类指针调用 draw
    shapePtr = new Rectangle();
    shapePtr->Draw();
    delete shapePtr;
    shapePtr = nullptr;

    return 0;
}


欢迎您同步关注我们的微信公众号!!!

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

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

相关文章

深度学习模型量化方法-【文末含实战】主流深度学习框架

目录 一&#xff0c;深度学习模型量化概述 1.1 模型量化定义 1.2 模型量化的方案 1.3&#xff0c;量化的分类 1.4 模型量化好处 总结&#xff1a; 二&#xff0c;常用量化框架 2.1 OpenVINO NCCF OpenVINO NCCF量化流程 OpenVINO NCCF量化优势 2.2 TensorRT量化框架…

如何向两个不同 MySQL 数据源的相同数据库与表写入数据

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…

AcWing 3188:Manacher 算法 → 最长回文子串

【题目来源】https://www.acwing.com/problem/content/3190/【题目描述】 给定一个长度为 n 的由小写字母构成的字符串&#xff0c;求它的最长回文子串的长度是多少。【输入格式】 一个由小写字母构成的字符串。【输出格式】 输出一个整数&#xff0c;表示最长回文子串的长度。…

VSCode创建插件HelloWorld找不到指令解决办法

按照网上的教程执行yo code并且生成成功 但是F5打开调试新窗口后&#xff0c;ctrl shift P&#xff0c;输入helloworld并没有指令提示 原因&#xff1a;当前电脑安装的VSCode版本过低&#xff0c;不支持当前插件的使用&#xff08;因为自动生成的插件总是默认使用最新版VSC…

00 springboot项目创建

我们创建SpringBoot项目有两种方式: Spring Initializr spring initerzie 方式创建: 启动类, 依赖 生成,但是需要网络maven的方式 maven方式创建: 启动类, 依赖, 这些都需要手动编写,但是不需要网络 如果你觉得我分享的内容或者我的努力对你有帮助&#xff0c;或者你只是想表…

可看见车辆行人的高清实时视频第5辑

我们在《看见车辆行人的高清实时视频第4辑》分享了10处可看见车辆行人的实时动态高清视频。 现在我们又整理10处为你分享可看见车辆行人的实时动态高清视频&#xff0c;一共有50个摄像头数据&#xff0c;这些视频来自公开的高清摄像头实时直播画面。 我们在文末为你分享了这些…

制造业如何从0-1实现信息化建设?

深度长文&#xff0c;4000 字&#xff0c;融合了众多企业的实践经验和行业观点&#xff0c;一文讲清制造业信息化建设的路径&#xff0c;心急的小伙伴可以先看目录&#xff1a; 关于定义 —— 制造业信息化建设是什么&#xff1f;关于价值 —— 为什么制造业要进行信息化建设…

【C++】精妙的哈希算法

&#x1f680;个人主页&#xff1a;小羊 &#x1f680;所属专栏&#xff1a;C 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 一、哈希结构1、哈希概念2、哈希函数3、哈希冲突3.1 闭散列3.2 开散列 4、完整代码 一、哈希结构 1、哈希概念 A…

漏扫工具Appscan使用(非常详细)从零基础入门到精通,看完这一篇就够了。

1、简介 AppScan是一款商业化的web安全扫描工具&#xff0c;web扫描领域十分受欢迎 2、具体使用规则 1、常用界面 新建扫描文件 选择扫描 对于第一种扫描方式&#xff1a; 设置url和服务器 登录管理&#xff1a;对于需要登陆的页面&#xff08;这种方法不允许有验证码&#…

人工智能AI与机器学习ML基础入门

小学生都能看懂的人工智能入门书籍 第一章 入门简介 TensorFlow 入门 如果你想入门人工智能&#xff08;AI&#xff09;&#xff1f;机器学习&#xff08;ML&#xff09;和深度学习是很好的起点。不过&#xff0c;一开始接触这些概念时&#xff0c;可能会被各种选项和新术语搞…

关于Spring Framework路径遍历漏洞(CVE-2024-38816)的预警提示和修复方案

一、漏洞详情 Spring Framework是一个Java应用程序框架&#xff0c;旨在提供高效且可扩展的开发环境。 近日&#xff0c;监测到Spring Framework中修复了一个路径遍历漏洞&#xff08;CVE-2024-38816&#xff09;。Spring Framework受影响版本中&#xff0c;使用WebMvc.fn 或…

MyBatisCodeHelperPro一直用教程

qq群&#xff1a;984518344 不懂请留言&#xff01;&#xff01;&#xff01; &#xff08;有能力请请支持正版&#xff01;&#xff01;&#xff09; &#xff08;仅供学习交流&#xff0c;严禁用于商业用途&#xff0c;请于24小时内删除&#xff01;&#xff01;&#xff09…

使用标注工具并跑通官方yolov8分割segment自己的数据集

1.下载标注工具用于打标签 使用标注工具&#xff0c;后面会用到智能标注 点击 创建AI多边形后命令行就自动下载对应的模型 单机要选中的图像就行&#xff0c;就可以智能选中&#xff0c;双击设置标签 依次标注所有图片 &#xff0c;最后保存成json格式的文件 2.使用labelme2y…

Nuxt.js 应用中的 modules:before 事件钩子详解

title: Nuxt.js 应用中的 modules:before 事件钩子详解 date: 2024/10/15 updated: 2024/10/15 author: cmdragon excerpt: modules:before 是 Nuxt.js 中一个重要的生命周期钩子,在 Nuxt 应用初始化期间被触发。该钩子允许开发者在安装用户定义的模块之前执行某些操作,如…

交通目标识别数据集YOLO 模型 ui界面✓图片数量15000,xml和txt标签都有 11类 交通道路车辆行人红黄绿数据集 红绿灯数据集 交通信号数据集

YOLO交通目标识别 数据集 模型 ui界面 ✓图片数量15000&#xff0c;xml和txt标签都有&#xff1b; ✓class&#xff1a;biker&#xff0c;car&#xff0c;pedestrian&#xff0c;trafficLight&#xff0c;trafficLight-Green&#xff0c;trafficLight-GreenLeft&#xff0c; tr…

WPF中MVVM的应用举例

WPF&#xff08;Windows Presentation Foundation&#xff09;是微软开发的用于创建用户界面的框架&#xff0c;而MVVM&#xff08;Model-View-ViewModel&#xff09;模式是一种分离前端UI逻辑与后台业务逻辑的方法。在WPF中使用MVVM模式可以提高代码的可维护性、可测试性和可扩…

Vant 日期时间组件拓展

基于 "vant": "^4.8.3", 效果图 <template><!-- 弹出层 --><van-popupv-model:show"isPicker"position"bottom"><van-pickerref"picker":title"title"v-model"selectedValues"…

匿名管道和命名管道

目录 管道 pipe创建一个管道 让子进程写入&#xff0c;父进程读取 如何把消息发送/写入给父进程 父进程该怎么读取呢 管道本质 结论&#xff1a;管道的特征&#xff1a; 测试管道大小 写端退了&#xff0c;测试结果 测试子进程一直写&#xff0c;父进程读一会就退出 …

PAT甲级-1076 Forwards on Weibo

题目 题目大意 已知微博上粉丝都可能会转发自己所关注的人的动态&#xff0c;给定总人数n和层数l&#xff0c;和每个id关注的人数及所关注人的id。要求查询一组用户的潜在转发量&#xff0c;粉丝层级不能超过l。 思路 求潜在转发量&#xff0c;就是一层一层的找粉丝数&#…