day44——面向对象特征

news2024/11/13 11:15:37

一、封装

1.1 面向对象的三大特质

封装、继承、多态,如果问有四大特征,可以外加一个抽象

封装:将实现同一事物的所有的属性(成员变量)和行为(成员函数)封装到一个整体,我们称之为类(class)。类对外部信息有一个屏障作用。

1.2 C++中的类(class)

C++中的类,是由C++中的结构体演化而来的,只需要将struct改成关键字class,就定义了一个类

C++中类和结构体的区别:默认的权限不同,结构体中默认权限为public,类中默认权限为private

默认的继承方式不同,结构体的默认继承方式为public,类的默认继承方式为private

1.3 定义格式

class 类名
{
    public:
        功能的成员属性、函数
    protected:
        受保护的成员属性、函数
    private:
        私有的成员属性、函数
};

1> 类中的成员属性和成员函数分为不同的权限

public:该权限下的成员,可以在类内、子类中、类外被访问

protected:该权限下的成员,可以在类内、子类中直接被访问,类外不允许被访问

private:该权限下的成员,只能在类内被访问,子类、类外不允许被访问

2> 如果没有指定权限,则默认为私有权限

3> 一个类中,访问权限可以出现多次,也可以出现在任意地方,一般情况下,我们将同一权限下的成员写到一个关键字下面

4> 一个访问权限的范围,是从当前关键字开始到下一个关键字或者整个类的定义结束为止

5> 一般情况下,成员属性定义成私有的,成员函数定义成公有的

6> 类的访问权限是针对于类体而言的,不是针对于类对象的

#include <iostream>
 
 
using namespace std;
 
 
//将实现人的所有属性和行为都封装到一个整体,
//后期如果需要一个人,只需要使用该类实例化对象后,通过对象为整个程序服务
class Person
{
    string skill = "C++";          //技能
 
 
public:
    string name = "zhangsan";        //姓名    功能的属性
 
 
protected:
    int pwd = 123456;           //银行卡密码
 
 
private:
    int money = 1000000;         //私房钱
 
 
public:
    void show()
    {
        cout<<"  name = "<<name<<endl;        //公共权限下的成员,类内可以直接访问
        cout<<"  pwd = "<<pwd<<endl;          //受保护权限下的成员,类内可以直接访问
        cout<<"  money = "<<money<<endl;      //私有成员,类内可以直接访问
        cout<<"  skill = "<<skill<<endl;      //默认为私有成员,类内可以直接访问
    }
 
 
};
 
 
/******************************************主程序***************************/
int main()
{
    Person p1;          //使用类定义变量的过程,称为实例化对象,p1就是Person类的一个对象
 
 
    //通过p1使用成员
    cout<<"name = "<<p1.name<<endl;          //公共权限下的成员,类外可以直接访问
    //cout<<"pwd = "<<p1.pwd<<endl;            //收保护成员,类外无法直接访问
    //cout<<"money = "<<p1.money<<endl;      //私有成员,类内可以直接访问,类外无法访问
    //cout<<"skill = "<<p1.skill<<endl;      //默认为私有成员,类内可以直接访问,类外无法访问
    p1.show();                                 //类中公共权限下的成员,类外可以直接访问
 
 
    return 0;
}

练习:

自定义一个矩形类,包含私有成员属性 高(height)和宽(width),

公共成员函数:初始化宽、高函数

设置宽度函数

设置高度函数

获取宽度函数

获取高度函数

求矩形的周长(Perimeter)函数

求矩形的面积(Area)函数

#include <iostream>
 
 
using namespace std;
class rectangle
{
public:
    void init(int w, int h);       //初始化一个矩形
    bool set_width(int w);       //设置宽度
    bool set_height(int h);      //设置高度
    int get_width();          //获取宽度
    int get_height();          //获取高度
    int perimeter();           //获取周长
    int area();                 //获取面积
private:
    int width=0;             //矩形宽度
    int height=0;             //矩形高度
};
bool rectangle::set_width(int w)
{
    if(w<=0)
    {
        cout<<"提供的宽度不合法"<<endl;
        return 0;
    }
    width=w;
    return 1;
}
 
 
bool rectangle::set_height(int h)
{
    if(h<=0)
    {
        cout<<"提供的高度不合法"<<endl;
        return 0;
    }
    height=h;
    return 1;
}
 
 
int rectangle::get_width()
{
    return width;
}
 
 
int rectangle::get_height()
{
    return height;
}
 
 
int rectangle::perimeter()
{
    return 2*(height+width);
}
 
 
int rectangle::area()
{
    return height*width;
}
 
 
void rectangle::init(int w, int h)
{
    if(w<=0 || h<=0)
    {
        cout<<"初始化失败"<<endl;
    }
    width = w;
    height = h;
}
 
 
int main()
{
    //使用矩形类实例化一个矩形
    rectangle r1;            //实例化一个对象
    r1.init(3,5);          //初始化一个矩形
    cout<<r1.perimeter()<<endl;
    cout<<r1.area()<<endl;
 
 
 
 
    return 0;
}

练习:

在上面练习的基础上,写一个函数,可以比较两个矩形框是否相等

相等条件:宽==宽 高==高

#include <iostream>
 
 
using namespace std;
class rectangle
{
public:
    void init(int w, int h);       //初始化一个矩形
    bool set_width(int w);       //设置宽度
    bool set_height(int h);      //设置高度
    int get_width();          //获取宽度
    int get_height();          //获取高度
    int perimeter();           //获取周长
    int area();                 //获取面积
    bool judge_rect(rectangle &r);        //定义判断两个矩形框是否相对
private:
    int width=0;             //矩形宽度
    int height=0;             //矩形高度
};
bool rectangle::set_width(int w)
{
    if(w<=0)
    {
        cout<<"提供的宽度不合法"<<endl;
        return 0;
    }
    width=w;
    return 1;
}
 
 
bool rectangle::set_height(int h)
{
    if(h<=0)
    {
        cout<<"提供的高度不合法"<<endl;
        return 0;
    }
    height=h;
    return 1;
}
 
 
int rectangle::get_width()
{
    return width;
}
 
 
int rectangle::get_height()
{
    return height;
}
 
 
int rectangle::perimeter()
{
    return 2*(height+width);
}
 
 
int rectangle::area()
{
    return height*width;
}
 
 
//判断两个矩形框是否相等,成员函数版
bool rectangle::judge_rect(rectangle &r)
{
    if(r.width==width && r.height==height)
    {
        return true;
    }
 
 
    return false;
}
 
 
void rectangle::init(int w, int h)
{
    if(w<=0 || h<=0)
    {
        cout<<"初始化失败"<<endl;
    }
    width = w;
    height = h;
}
 
 
//定义全局函数版本
bool judge_rect(rectangle &r1, rectangle &r2)
{
    //判断两个矩形是否相等
    if(r1.get_width()==r2.get_width() && r1.get_height()==r2.get_height())
    {
        return true;
    }
 
 
    return false;      //不相等
}
 
 
 
 
 
 
int main()
{
    //使用矩形类实例化一个矩形
    rectangle r1;            //实例化一个对象
    r1.init(3,5);          //初始化一个矩形
    cout<<r1.perimeter()<<endl;
    cout<<r1.area()<<endl;
 
 
    //定义第二个矩形
    rectangle r2;
    r2.init(3,6);
 
 
    //if(judge_rect(r1, r2))
    if(r1.judge_rect(r2))            //r2.judge_rect(r1)
    {
        cout<<"两个矩形框相等"<<endl;
    }else
    {
        cout<<"两个矩形框不相等"<<endl;
    }
 
 
 
 
    return 0;
}

1.4 分文件编译

1> 头文件

#ifndef RECTANGLE_H
#define RECTANGLE_H
#include <iostream>
 
 
using namespace std;
 
 
 
 
//头文件中主要放:类的声明、全局函数的声明、全局变量的定义、类型重命名、宏定义
class rectangle
{
public:
    void init(int w, int h);       //初始化一个矩形
    bool set_width(int w);       //设置宽度
    bool set_height(int h);      //设置高度
    int get_width();          //获取宽度
    int get_height();          //获取高度
    int perimeter();           //获取周长
    int area();                 //获取面积
    bool judge_rect(rectangle &r);        //定义判断两个矩形框是否相对
private:
    int width=0;             //矩形宽度
    int height=0;             //矩形高度
};
 
 
 
 
bool judge_rect(rectangle &r1, rectangle &r2);        //全局函数的声明
 
 
#endif // RECTANGLE_H

2>源文件

#include"rectangle.h"
 
 
bool rectangle::set_width(int w)
{
    if(w<=0)
    {
        cout<<"提供的宽度不合法"<<endl;
        return 0;
    }
    width=w;
    return 1;
}
 
 
bool rectangle::set_height(int h)
{
    if(h<=0)
    {
        cout<<"提供的高度不合法"<<endl;
        return 0;
    }
    height=h;
    return 1;
}
 
 
int rectangle::get_width()
{
    return width;
}
 
 
int rectangle::get_height()
{
    return height;
}
 
 
int rectangle::perimeter()
{
    return 2*(height+width);
}
 
 
int rectangle::area()
{
    return height*width;
}
 
 
//判断两个矩形框是否相等,成员函数版
bool rectangle::judge_rect(rectangle &r)
{
    if(r.width==width && r.height==height)
    {
        return true;
    }
 
 
    return false;
}
 
 
void rectangle::init(int w, int h)
{
    if(w<=0 || h<=0)
    {
        cout<<"初始化失败"<<endl;
    }
    width = w;
    height = h;
}
 
 
//定义全局函数版本
bool judge_rect(rectangle &r1, rectangle &r2)
{
    //判断两个矩形是否相等
    if(r1.get_width()==r2.get_width() && r1.get_height()==r2.get_height())
    {
        return true;
    }
 
 
    return false;      //不相等
}

3> 主程序

#include"rectangle.h"
 
 
int main()
{
    //使用矩形类实例化一个矩形
    rectangle r1;            //实例化一个对象
    r1.init(3,5);          //初始化一个矩形
    cout<<r1.perimeter()<<endl;
    cout<<r1.area()<<endl;
 
 
    //定义第二个矩形
    rectangle r2;
    r2.init(3,6);
 
 
    //if(judge_rect(r1, r2))
    if(r1.judge_rect(r2))            //r2.judge_rect(r1)
    {
        cout<<"两个矩形框相等"<<endl;
    }else
    {
        cout<<"两个矩形框不相等"<<endl;
    }
 
 
 
 
    return 0;
}

1.5 this指针

1> this的内含:是类的非静态成员函数所拥有的一个隐藏的形参指针,指代该对象本身起始地址,哪个对象使用我,我就表示哪个对象

2> this指针的格式:类名 * const this;

3> 对于this指针而言,如果没有显性使用该指针,仅仅只是使用成员,那也是默认使用了this指针

3> this指针的使用场景

场景1:当成员函数的形参名和成员变量同名时,可以使用this指针进行区分

场景2:在拷贝复制函数中,需要返回自身引用时,也必须使用this指针(后面讲)

#include <iostream>
 
 
using namespace std;
class rectangle
{
public:
    void init(int width, int height);       //初始化一个矩形
 
    void show()
    {
        cout<<"width = "<<width<<"  height = "<<height<<endl;
    }
private:
    int width=0;             //矩形宽度
    int height=0;             //矩形高度
};
 
 
void rectangle::init(int width, int height)
{
    if(width<=0 || height<=0)
    {
        cout<<"初始化失败"<<endl;
    }
    this->width = width;             //可以通过this指针改变this所指向内存中的值
    this->height = height;
 
 
    cout<<"this = "<<this<<endl;
 
 
    //this = NULL;          //不能更改指针的指向
 
 
}
 
 
int main()
{
    //使用矩形类实例化一个矩形
    rectangle r1;            //实例化一个对象
    r1.init(3,5);          //初始化一个矩形
    cout<<"&r1 = "<<&r1<<endl;         //r1的地址
    r1.show();
 
    //在实例化一个对象
    rectangle r2;
    r2.init(2,2);
    cout<<"&r2 = "<<&r2<<endl;         //r2的地址
 
    return 0;
}

1.6 类的大小

1> 一个空的类的大小为1字节,用于占位使用,如果后期有成员变量的加入,则会将这一字节的空间分配出去

2> 类中的成员函数不占类的空间大小,但是成员属性会占用类的大小

3> 成员属性分配空间的大小遵循字节对齐原则

4> 如果类中有虚函数(后期讲),那么类中就会多一个虚指针的大小

5> 如果该类是虚继承(后期讲)自父类,那么该类中也会增加一个虚指针的大小

#include <iostream>
 
 
using namespace std;
 
 
class Temp
{
public:
    int num;      //整型成员变量
 
 
    void show()
    {
        cout<<"num = "<<num<<endl;
    }
 
 
    //类中有虚函数时,就会多分配一个虚指针的空间
    virtual void display()
    {
        cout<<"我是虚函数"<<endl;
    }
 
 
    virtual void display(int )
    {
        cout<<"我是虚函数"<<endl;
    }
 
 
};
 
 
int main()
{
    cout<<"sizeof(Temp) = "<<sizeof(Temp)<<endl;
 
    return 0;
}

二、类中特殊的成员函数(非常重要)

2.1 类中提供的特殊成员函数

1> 特殊的原因:如果用户不显性定义这些函数,系统也会自动提供这些函数,如果用户显性定义了这些函数,那么系统就不提供了。

无论这些特殊的成员函数,是系统提供的还是用户字节定义的,都无需用户手动调用,特殊的时机,系统会自动调用

2> 构造函数、析构函数、拷贝构造函数、拷贝复制函数、移动构造函数、移动复值函数、取地址运算符重载

2.2 构造函数

1> 功能:

使用类去实例化对象时,为对象进行资源的申请以及初始化使用的

2> 定义格式

1、构造函数没有返回值
2、函数名与类同名
3、访问权限,一般为public
4、 类名(形参列表){函数体内容}

3> 调用时机:

当使用类实例化对象时,系统自动调用,无需手动调用

1、栈区空间:使用类实例化对象时,系统自动调用

类名 变量名(实参); //此时就调用的构造函数

2、堆区空间:只有在使用new申请空间时,自动调用构造函数

类名 *指针名; //此时仅仅只是定义一个指针变量,并没有为对象分配空间

指针名 = new 类名(实参); //此时调用的构造函数

#include <iostream>
 
 
using namespace std;
 
 
class Stu
{
public:
    Stu()
    {
        cout<<"Stu的构造函数"<<endl;
    }
};
 
 
 
 
int main()
{
    //在栈区申请对象空间
    Stu s1;
 
 
    //堆区空间申请对象
    Stu *ptr;          //此时不调用构造函数
    ptr = new Stu;      //此时调用构造函数
 
 
    return 0;
}

4> 构造函数分为有参构造和无参构造函数,有参构造函数可以为成员属性进行初始化,这些构造函数之间构成重载关系

5> 一个类中可以有多个构造函数,每个对象仅仅只会调用一个构造函数

6> 如果类中没有定义构造函数,那么,系统会自动提供一个无参构造函数,用于对对象空间的申请,如果程序员自己定义了构造函数,系统就不再提供那个无参构造了,如果还想使用无参构造,需要自己定义一个无参构造

#include <iostream>
 
 
using namespace std;
 
 
class Stu
{
private:
    string name;
    int age;
    double score;
 
 
public:
    //无参构造
    Stu()
    {
        cout<<"Stu的无参构造函数"<<endl;
    }
    //自定义有参构造
    Stu(string n, int a)
    {
        this->name = n;
        this->age = a;
        cout<<"Stu::有参构造"<<endl;
    }
 
 
    void show()
    {
        cout<<"name = "<<name<<endl;
        cout<<"age = "<<age<<endl;
        cout<<"score = "<<score<<endl;
    }
};
 
 
 
 
int main()
{
    //在栈区申请对象空间
    Stu s1;                       //此时调用了无参构造,只为对象申请了空间,但是没有为对象初始化
    s1.show();
    cout<<"**************************************"<<endl;
 
 
    //申请一个对象,调用有参构造
    Stu s2("zhangsan", 18);          //此时调用了有参构造
    s2.show();
    cout<<"**************************************"<<endl;
 
 
    //堆区空间申请对象
    Stu *ptr;          //此时不调用构造函数
    ptr = new Stu;      //此时调用构造函数
 
 
    return 0;
}

7> 构造函数初始化对象可以使用初始化列表完成

使用方式:类名(形参1,形参2,。。。形参n):成员1(形参1),成员2(形参2),。。。成员n(形参n)

{函数体内容}

说明:在构造函数的小括号后,由冒号引出初始化列表,括号外时成员变量,括号内是形参

#include <iostream>
 
 
using namespace std;
 
 
class Stu
{
private:
    string name;
    int age;
    double score;
 
 
public:
    //无参构造
    Stu()
    {
        cout<<"Stu的无参构造函数"<<endl;
    }
    //自定义有参构造
    Stu(string n, int a)
    {
        this->name = n;         //对成员的赋值操作
        this->age = a;
        cout<<"Stu::有参构造1"<<endl;
    }
 
 
    //定义有参构造:使用初始化列表完成对成员的初始化工作
    Stu(string n, int a, double s):name(n),age(a),score(s)
    {
        cout<<"Stu::有参构造2"<<endl;
    }
 
 
    void show()
    {
        cout<<"name = "<<name<<endl;
        cout<<"age = "<<age<<endl;
        cout<<"score = "<<score<<endl;
    }
};
 
 
 
 
int main()
{
    //在栈区申请对象空间
    Stu s1;                       //此时调用了无参构造,只为对象申请了空间,但是没有为对象初始化
    s1.show();
    cout<<"**************************************"<<endl;
 
 
    //申请一个对象,调用有参构造
    Stu s2("zhangsan", 18);          //此时调用了有参构造
    s2.show();
    cout<<"**************************************"<<endl;
 
 
 
 
    //申请一个对象,调用有参构造
    Stu s3("lisi", 20, 99.8);
    s3.show();
    cout<<"**************************************"<<endl;
 
 
 
 
    //堆区空间申请对象
    Stu *ptr;          //此时不调用构造函数
    ptr = new Stu;      //此时调用构造函数
 
 
    return 0;
}

8> 必须使用初始化列表的情况

1、当构造函数的形参名和成员变量名同名时,可以使用初始化列表来解决

2、当类中有const修饰的成员变量时,对该变量也必须进行初始化,使用初始化列表解决

3、当类中有引用成员时,对该成员的操作也必须使用初始化列表完成

4、当类中有其他类的成员子对象时,对该成员的操作也必须使用初始化列表完成,如果没有使用初始化列表调用有参构造,则系统会自动调用成员子对象的无参构造

#include <iostream>
 
 
using namespace std;
 
 
class Toy
{
public:
    Toy() {cout<<"Toy::无参构造"<<endl;}
    Toy(string n):name(n) {cout<<"Toy::有参构造"<<endl;}
 
 
private:
    string name;
 
 
};
 
 
 
 
 
 
class Stu
{
private:
    string name;
    int age;
    double score;
    const int value;        //类中有const类型的成员
    int &key;             //类中有引用成员
    Toy t;               //类中有其他类的成员子对象
 
 
public:
    //无参构造
    Stu():value(1314), key(*(new int(520))), t("hello kity")
    {
 
 
        cout<<"Stu的无参构造函数"<<endl;
    }
    //自定义有参构造
    Stu(string n, int a, int &k):value(1314), key(k)
    {
        this->name = n;         //对成员的赋值操作
        this->age = a;
        cout<<"Stu::有参构造1"<<endl;
    }
 
 
    //定义有参构造:使用初始化列表完成对成员的初始化工作
    Stu(string name, int age, double score, int &k):name(name),age(age),score(score),value(1314),key(k)
    {
        cout<<"Stu::有参构造2"<<endl;
    }
 
 
    void show()
    {
        cout<<"name = "<<name<<endl;
        cout<<"age = "<<age<<endl;
        cout<<"score = "<<score<<endl;
    }
};
 
 
int main()
{
    //在栈区申请对象空间
    Stu s1;                       //此时调用了无参构造,只为对象申请了空间,但是没有为对象初始化
    s1.show();
    cout<<"**************************************"<<endl;
 
    //堆区空间申请对象
    Stu *ptr;          //此时不调用构造函数
    ptr = new Stu;      //此时调用构造函数
 
    return 0;
}

2.3 析构函数

1> 功能:在对象消亡时,用于给对象回收空间使用的

2> 定义格式

1、没有返回值
2、函数名:类名前加个波浪线  ~类名
3、权限:一般为public
4、没有参数,所以,一个类中只有一个析构函数,不能进行重载
5、格式:   ~类名()

3> 调用时机:当对象的生命周期结束后,用于回收内存空间

栈区:当栈空间释放后,系统会自动调用该类的析构函数

堆区:当使用delete关键字释放对象空间时,系统自动调用

4> 如果没有手动定义析构函数,系统会提供一个析构函数,用于回收类对象的空间,如果手动定义了析构函数,那么,系统就不再提供默认的析构函数了。

#include <iostream>
 
 
using namespace std;
 
 
class Toy
{
public:
    Toy() {cout<<"Toy::无参构造"<<endl;}
    Toy(string n):name(n) {cout<<"Toy::有参构造"<<endl;}
 
 
private:
    string name;
 
 
};
 
 
 
 
 
 
class Stu
{
private:
    string name;
    int age;
    double score;
    const int value;        //类中有const类型的成员
    int &key;             //类中有引用成员
    Toy t;               //类中有其他类的成员子对象
    int *ptr;         //指针成员
 
 
public:
    //无参构造
    Stu():value(1314), key(*(new int(520))), t("hello kity"), ptr(new int(666))
    {
 
 
        cout<<"Stu的无参构造函数"<<endl;
    }
    //自定义有参构造
    Stu(string n, int a, int &k):value(1314), key(k)
    {
        this->name = n;         //对成员的赋值操作
        this->age = a;
        cout<<"Stu::有参构造1"<<endl;
    }
 
 
    //定义有参构造:使用初始化列表完成对成员的初始化工作
    Stu(string name, int age, double score, int &k):name(name),age(age),score(score),value(1314),key(k)
    {
        cout<<"Stu::有参构造2"<<endl;
    }
 
 
    void show()
    {
        cout<<"name = "<<name<<endl;
        cout<<"age = "<<age<<endl;
        cout<<"score = "<<score<<endl;
    }
 
 
    //定义析构函数
    ~Stu()
    {
        delete ptr;          //释放指针的空间
        cout<<"STU::析构函数"<<endl;
    }
};
 
 
 
 
int main()
{
    //在栈区申请对象空间
    Stu s1;                       //此时调用了无参构造,只为对象申请了空间,但是没有为对象初始化
    s1.show();
    cout<<"**************************************"<<endl;
 
 
 
 
    //堆区空间申请对象
    Stu *ptr;          //此时不调用构造函数
    ptr = new Stu;      //此时调用构造函数
 
 
    //释放ptr的空间
    delete ptr;       //此时会调用析构函数
 
 
    return 0;
}

作业

仿照string类,实现myString

#include <iostream>
#include <cstring>

class myString
{
private:
    char *str;          //记录c风格的字符串
    int size;            //记录字符串的实际长度

public:
    //无参构造
    myString():size(10)
    {
        str = new char[size];         //构造出一个长度为10的字符串
        str[0] = '\0';                // 初始化为空字符串
    }

    //有参构造
    myString(const char *s)
    {
        size = strlen(s);             // 计算传入字符串的长度
        str = new char[size + 1];     // 分配足够的内存空间,加1是为了存储结束符'\0'
        strcpy(str, s);               // 复制传入的字符串到新分配的内存空间
    }

    //判空函数
    bool empty() const
    {
        return str[0] == '\0';
    }

    //size函数
    int length() const
    {
        return size;
    }

    //c_str函数
    const char* c_str() const
    {
        return str;
    }

    //at函数
    char at(int index) const
    {
        if (index >= 0 && index < size)
        {
            return str[index];
        }
        else
        {
            throw std::out_of_range("Index out of range");
        }
    }

    //二倍扩容
    void doubleCapacity()
    {
        int newSize = size * 2;
        char *newStr = new char[newSize + 1]; // 分配新的内存空间,加1是为了存储结束符'\0'
        strcpy(newStr, str);                  // 复制原字符串到新内存空间
        delete[] str;                          // 释放原内存空间
        str = newStr;                          // 更新指针指向新的内存空间
        size = newSize;                        // 更新字符串长度
    }
};

int main()
{
    myString s1;
    myString s2("Hello, world!");

    std::cout << "s1是" << (s1.empty() ? "空" : "非空") << std::endl;
    std::cout << "s2是" << (s2.empty() ? "空" : "非空") << std::endl;

    std::cout << "s1的长度:" << s1.length() << std::endl;
    std::cout << "s2的长度:" << s2.length() << std::endl;

    std::cout << "s2的内容:" << s2.c_str() << std::endl;

    std::cout << s2.at(7) << std::endl;

    return 0;
}

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

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

相关文章

【Datawhale AI夏令营】从零上手CV竞赛Task2

文章目录 前言一、YOLO是什么&#xff1f;二、YOLO的历史三、性能指标四、 性能指标计算公式五、性能优化总结 前言 本文的Task2是对Task1的baseline代码进行优化的过程。 一、YOLO是什么&#xff1f; 首先简单介绍一下YOLO模型&#xff1a; 物体检测算法主要分为两类&#…

MSTP多实例生成树的配置

SW1配置&#xff1a; vlan batch 1 to 100 interface GigabitEthernet0/0/1 port link-type trunk port trunk allow-pass vlan 2 to 4094 interface GigabitEthernet0/0/2 port link-type trunk port trunk allow-pass vlan 2 to 4094 stp mode mstp //修改生成树的模式为…

【多线程】创建线程到底是多少种方法?

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 文章目录 1. 创建线程的两种方式总结(最官方)1.1 继承 Thread 类1.2 实现 Runnable 接口1.3 优先考虑使用第二种 —— …

三. Spring Boot 当中的“容器功能” 和 “配置绑定” 的详细剖析(附+源代码流程)

三. Spring Boot 当中的“容器功能” 和 “配置绑定” 的详细剖析(附源代码流程) 文章目录 三. Spring Boot 当中的“容器功能” 和 “配置绑定” 的详细剖析(附源代码流程)1. Spring Boot 是继续支持了 Spring 当中的注解的1.2 Spring 当中的 Component&#xff0c;Controller…

通过visual studio进行dump文件调试和分析

0、前言 很多时候程序crash之后需要分析原因。对于C/C程序&#xff0c;一般最常见的场景和方法就是根据dump文件进行分析。 1、分析的前提条件 进行dump文件分析&#xff0c;需要以下文件&#xff1a; 进程crash时产生的dump文件程序源码进程对应的程序exe文件编译exe文件时产…

QT Quick QML 添加海康威视SDK云台控制模块

文章目录 1. 配置海康威视 SDK 下载SDK文件移植工程文件添加 2. 函数调用流程接口参考代码 3. 代码后端核心代码前端核心代码 GitHub 源码: QmlLearningPro &#xff0c;选择子工程 HkwsDemo.pro &#xff08;暂未上传&#xff09; QML 其它文章请点击这里: QT QUICK …

Monibuca实战:如何用Go语言打造高效的直播后端

简介 Monibuca&#xff08;简称&#xff1a;m7s&#xff09; 是一个开源的实时流媒体服务器开发框架&#xff0c;使用 Go 语言编写。 它的设计目标是提供一个高性能、可扩展、易于定制的实时流媒体服务器解决方案。 Monibuca 的核心理念是模块化&#xff0c;允许开发者根据需…

文件禁止外发的方法有哪些?企业如何禁止文件外发:六个控制文件外发的小窍门!

想象一下&#xff0c;企业信息如同珍贵的宝藏&#xff0c;而文件外发就像不经意间打开的后门&#xff0c;让宝藏暴露在风雨之中&#xff01;今天&#xff0c;我们就来聊聊如何给这扇后门加上六道坚实的锁&#xff0c;确保企业信息的安全无虞。让我们一起探索六个控制文件外发的…

Mask R-CNN论文原理讲解

论文:arxiv.org/pdf/1703.06870 代码&#xff1a;maskrcnn-benchmark:Fast, modular reference implementation of Instance Segmentation and Object Detection algorithms in PyTorch. - GitCode Mask R-CNN简介 Mask R-CNN是何凯明大神的新作。Mask R-CNN是一种在有效检测…

武器弹药制造5G智能工厂物联数字孪生平台,推进制造业数字化转型

武器弹药制造领域作为国防工业的重要组成部分&#xff0c;其数字化转型更是关乎国家安全与军事实力提升的关键。随着5G、物联网、大数据、云计算及人工智能等先进技术的融合应用&#xff0c;武器弹药制造5G智能工厂物联数字孪生平台应运而生&#xff0c;正逐步成为推进制造业数…

分享5款支持论文写作网站先稿后付的网站!

在当今学术研究和学术写作领域&#xff0c;AI论文写作工具已经成为不可或缺的助手。这些工具不仅能够提高写作效率&#xff0c;还能帮助研究人员生成高质量的论文内容。特别是那些提供“先稿后付”服务模式的网站&#xff0c;更是为用户提供了极大的便利和保障。以下是五款值得…

记录|SPC公式小结

目录 前言一、基本缩写二、Xbar和R的控制线三、相关系数表更新时间 前言 参考文章&#xff1a; 参考视频&#xff1a; SPC公式小结 一、基本缩写 二、Xbar和R的控制线 三、相关系数表 更新时间 2024.08.29&#xff1a;创建

旗帜分田(华为od机考题)

一、题目 1.原题 从前有个村庄&#xff0c;村民们喜欢在各种田地上插上小旗子&#xff0c;旗子上标识了各种不同的数字。 某天集体村民决定将覆盖相同数字的最小矩阵形的土地的分配给为村里做出巨大贡献的村民&#xff0c; 请问&#xff0c;此次分配土地&#xff0c;做出贡献…

DevEco Studio5 新建项目

Deveco Studio安装结束之后&#xff0c;开始新建一个项目&#xff1a; 1.点击Create Project新建项目 2.选择空的项目–>点击next 3.配置项目信息–>点击Finish 4.进入项目 6.右上方目前处于No Devices(无设备)状态–>点击下拉三角–>点击Devide Manager管理设…

Life long learning

现象&#xff1a;一个model进行multi-task learning做的还可以&#xff0c;说明模型是可以同时学会多个任务的&#xff0c;但是如果训练过程是1个task 1个task的顺序进行&#xff0c;模型就会发生灾难性的遗忘现象&#xff0c;只会做刚学完的task。 目标&#xff1a;让模型不要…

94.WEB渗透测试-信息收集-Google语法(8)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;93.WEB渗透测试-信息收集-Google语法&#xff08;7&#xff09; • Filetype • Filetype…

二叉树前序,中序,后序非递归遍历(Java)

1. 思路&#xff1a; 首先创建一个栈和顺序表&#xff0c;按照根左右的前序遍历顺序去遍历这棵树&#xff0c;一直往左孩子方向遍历&#xff0c;每遍历到一个结点就入栈并且加入到顺序表里&#xff0c;如果没有左孩子了&#xff0c;就拿出栈顶元素&#xff0c;看它是否有右孩子…

2024年牛客网最全1000道Java中高级面试题包含答案详解,看完稳了

我相信大多 Java 开发的程序员或多或少经历过 BAT 一些大厂的面试&#xff0c;也清楚一线互联网大厂 Java 面试是有一定难度的&#xff0c;小编经历过多次面试&#xff0c;有满意的也有备受打击的。因此呢小编想把自己这么多次面试经历以及近期的面试真题来个汇总分析&#xff…

JavaScript进阶指南之Event Loop

JavaScript进阶指南之Event Loop 引言 简要介绍主题&#xff1a; 在JavaScript的世界中&#xff0c;Event Loop是一个核心机制&#xff0c;它决定了代码的执行顺序&#xff0c;尤其是在处理异步任务时。对于初学者来说&#xff0c;理解Event Loop的工作原理是迈向JavaScript进…

设计模式篇(DesignPattern - 结构型模式)(持续更新迭代)

目录 模式一&#xff1a;适配器模式 一、简介 二、案例一&#xff08;充电器问题&#xff09; 1. 类适配器 2. 对象适配器 3. 接口适配器 三、应用 1. HandlerAdapter&#xff08;SpringMVC 源码应用&#xff09; 四、总结 模式二&#xff1a;桥接模式 一、简介 1.…