类,这一篇文章你就懂了!

提示:本文主要介绍C++中类相关知识及基础概念总结
在这里插入图片描述
渺渺何所似,天地一沙鸥

文章目录

  • 一、面向对象与面向过程
  • 二、类的框架知识
    • 2.1 类的定义
    • 2.2 类的封装性
      • 2.2.1 访问限定符
      • 2.2.2 封装的概念以及实现
    • 2.3 类的作用域及实例化
    • 2.4 类中this指针
  • 三、六大默认成员函数
    • 3.1 构造函数
    • 3.2 拷贝构造函数
    • 3.3 析构函数
    • 3.4 赋值运算符重载
  • 四、类中const成员与static成员
  • 五、破坏封装性的友元函数


一、面向对象与面向过程

类是C++一切功能实现的载体,繁华的功能实现都依托于类这颗苍天大树之上。
而C++于C语言最根本的不同就在于C++是面向对象的,C++将一件繁杂的业务拆分成不同的对象,靠一个个精密的对象之间交互完成这个业务,而C语言确实关于问题的过程,分析出求解问题的步骤,通过一个个函数逐步的刨析,调用最终得以解决问题。

二、类的框架知识

2.1 类的定义

在C++中使用关键字class来定义类:

class kind
{
//共有成员
public:
//保护成员
protected:
//私有成员
private:
}

不同于C语言中的struct 在类中可以通过访问限定符的修饰来定义不同权限的函数,这也是C++中一个很大的改变,那什么才是访问限定符呢,它又有什么样的作用?

2.2 类的封装性

2.2.1 访问限定符

C++是一个面向对象的语言,那么他就存在权限的说法,不然人人都可以访问,那和C语言又有什么区别呢?
所以C++的类中引入了三种访问限定符:
public: 成员可以在类的外部通过对象访问。
protected: 成员可以在类的派生类中访问(这个主要在继承体系中使用)因为被它所修饰的成员不能再类外访问,但是可以在类的派生类中通过成员函数来访问基类的保护类成员。
private: 成员只能在类内访问。
而当我们在创建类时,不进行访问限定符的修饰时,默认的访问限定符为private类型,在C++中struct也可以当作class来使用,且struct的默认访问限定符为public类型,这个主要是为了兼容C语言。
所以在C++中我们可以理解为,class与struct在默认访问限定符有区别外,其他方面没有任何区别!

2.2.2 封装的概念以及实现

封装就是将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,进对外公开接口来和对象进行交互。
当然封装一方面是为了安全性,另一方面也是为了简化我们操作的难度,降低我们看到的代码的冗余性,不然若是暴漏所有的实现细节,那么在文档的查询阅读等方面可能要花费更多的时间与精力,这几乎是不可完成的。
C++中如何实现封装呢
先通过类将对象的属性和方法包装成一个整体,表明包装类实现的是什么功能,然后在内部通过访问限定符,选择性的将接口暴漏给使用者,然后完成交互,比如常见的视频平台会员机制 (普通用户与VIP的界面都是不同的)

#include <iostream>
#include <string>class Car
{
private:std::string brand;std::string model;
public:Car(const std::string& carBrand, const std::string& carmodel) :brand(carBrand), model(carmodel) {}void getbrand(){std::cout << "车型:" << brand << std::endl;std::cout << "车类:" << model << std::endl;}
};int main()
{Car mycar("benchi", "365");mycar.getbrand();return 0;
}

在这里插入图片描述
Car内部的两个私有接口,不可以直接访问到,然后通过类内共有接口访问,输出汽车信息。较为简单,主要为了体现出类的封装性,类内调用。

2.3 类的作用域及实例化

类有自己独立作用域,类的所有成员都在类的作用域中,通俗的讲类的作用域指定类定义在哪个范围内是可见的,一般可以是全局范围、命名空间、函数内部、或者其他类成员函数内部。
全局作用域及其实例化:

// muclass.h内
class MyClass
{//类功能
}
#include ”MyClass.h“
int main()
{MyClass myobject; // 在全局作用域内都可以使用// ... return 0;
}

这种就是不加以任何的修饰,以.h头文件的方式定义,然后直接在主函数中定义展开使用,是全局的。
命名空间作用域及其实例化:

// test.h文件
namespace Myname
{class MyClass{// 具体的类定义}
}
// test.cc 文件
#include "test.h"
int main()
{// 使用命名空间限定符实例化对象Myname::MyClass class; // 必须展开.h文件// ... 具体的操作
}

在命名空间内定义的类可以在该命名空间及其子命名空间中访问。
函数作用域内及其实例化:

void Myfunc()
{class MyClass{// 具体的类定义 ...}MyClass myobject; // 仅可以在函数内实例化对象// ... 具体的操作
}

在函数内定义的局部类只能在该函数内部定义
类的成员函数作用域及其实例化:

// 通俗易懂 类的成员函数作用域肯定是被类中访问限定符所修饰的
class MyClass 
{
public:void mytest(){// 类内调用类的其他成员变量以及函数int x = mytest;Myfunc();}
private:int mytest;void Myfunc();// ... 	
}

上边分别展示了四种作用域以及作用域中实例化的方式。
类在我看来就是一类具有公共属性的集合体。是一种集合的对象,使用多种单个对象结合起来,而我们在对类进行具体的实例化时,可以看作同时实例化了一批我们所需要用到的对象,同样会占用空间,同样要受到访问权限的约束,类就像一个巨大的模板,而对象便是组成这个模板的个体,最终变成了一个巨大的个体, 类就是对数据和行为的封装和抽象!
类的实例化中我们要了解到的一些小知识点:

1.一个类的大小如何计算?
2.空类的大小是多少?
3.什么是内存对齐?结构体是如何进行内存对齐的?
4.如何让结构体按照指定的默认对齐数进行对齐?
5.如何知道结构体中某个成员相对于结构体起始位置的偏移量?

2.4 类中this指针

在函数体中所有的成员变量操作,都是通过this指针去访问的。
this指针的特性:

1.this指针不可改变,所以在类类型为 *const 。
2.只能在 “成员函数” 的内部使用。
3.this指针本质上是一个成员函数的形参,在对象调用成员函数时,第一个就是隐藏的this指针参数,将对象的地址作为实参传递给this形参,所以在对象内存中 并不存储 this指针。
4.this指针是 成员函数 第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递。

#include <iostream>
#include <string>class Myclass
{
private:int _x;int y;int z;
public:Myclass(int x, int y,int z){_x = x; // 当命名不冲突时,可以直接使用命名赋值this->y = y; // 当命名冲突时,可以使用this指针显示的调用赋值z = z; // 错误的方式,不会成功}void print(){std::cout << "_x: " << _x << "\ny: " << this->y << z <<std::endl;}
};int main()
{Myclass c(1, 2,3);c.print();return 0;
}

在这里插入图片描述
在这里插入图片描述
可以看到_x,y都成功赋值,但是z却没有,他们都有各自的地址空间,但就是z没有初始化成功。所以当在成员函数中对成员变量进行操作时,可以显示的调用this指针来进行操作。
切记,成员函数调用的时候第一个传递的参数是隐藏的this指针!

三、六大默认成员函数

3.1 构造函数

构造函数是特殊的成员函数,是类中独有的,且构造函数名与类名相同,创建类对象时由编译器自动调用,在对象的生命周期内仅调用一次。
在编写类时,不显式定义构造函数,编译器会提供默认的构造函数,但默认构造函数不接受任何参数,他只是执行一些默认初始化操作。
在函数创建时,构造函数会为成员变量分配内存,设置默认值或者执行一些其他的初始化逻辑。
一个类可以显示的创建多种类的构造函数,他们具有不同的参数列表,称为构造函数的重载,就可以在构造对象时根据不同的参数提供不同的初始化方式。

#include <iostream>
#include <string>class Person
{
private:std::string _name;int _age;
public:Person() // 无参构造{_name = "张三";_age = 18;std::cout << "Person()\n";}Person(const std::string &name,int age):_name(name),_age(age) // 具体参数,且使用初始化列表构造{std::cout << "Person(const std::string &name,int age)" << std::endl;}void print(){std::cout << "name: " << _name << "Age: " << _age << std::endl;}
};int main()
{Person p1;p1.print();Person p2("李四", 19);p2.print();return 0;
}

在这里插入图片描述
上边就是显示多构造函数,然后构造函数重载,两种方法都可以成功创建对象,切初始化成功。
在构造函数中还有个独有的模块: 初始化列表 可以对类的成员变量进行初始化有基类特定成员必须在初始化列表中初始化

1.常量成员变量(const),因为常量成员变量的值无法在构造函数体内修改
2.引用成员变量,引用成员变量必须在创建对象时引用有效的对象
3.类类型对象(该类没有默认构造函数)

#include <iostream>
#include <string>class Myclass
{
private:const int _num;int& _val;
public:Myclass(int num, int& val) :_num(num), _val(val) {// ---}
};
int main()
{int val = 5;// _num只需要传递同类型的常量过去就好,而_val必须传递一个具有实际地址空间的同类型量,因为它实例化的是一个引用,而引用的定义便需要一块实际存在的空间Myclass s(6, val); return 0;
}

而其他的非常量非引用的成员变量看个人习惯,若是直接传入的可以直接在初始化列表进行初始化,且建议在初始化列表初始化,成员变量在类中声明的次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关。
注意!:

1.构造函数不能用const修饰
2.构造函数不能是虚函数
3.无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能由一个。

3.2 拷贝构造函数

什么是拷贝构造函数?
拷贝构造函数的概念是只有单个形参,且该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。
他就好像构造函数的一种重载形式,所以构造函数的特性拷贝构造函数都满足,拷贝构造函数的参数只有一个且必须使用引用传参,使用传值的方式,就会引发无穷递归调用。
他和构造函数一样也是类的默认函数之一,若未显示的定义,系统会自动生成,默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝一般称为浅拷贝,或者值拷贝(只拷贝值过去)。
因为是默认是浅拷贝,那当我们的类中存在指针变量时,两个原本的对象内容都会收到修改,此时就需要我们手动进行深拷贝了。

class Myclass
{
private:int* _data;
public:Myclass(int data){_data = new int;*_data = data;}/*Myclass(const Myclass& data){_data = new int;*_data = *(data._data);}*/void print(){*_data = 2;std::cout << "_data: " << *_data << std::endl;}
};int main()
{Myclass s(1);Myclass ss(s);s.print();return 0;
}

在这里插入图片描述
在这里插入图片描述
当我们运行 void print(); 函数时,仅仅改变s内的data,ss中的也被改变这就是因为他们中私有成员_data指向的是头一块地址。而若是我们实例化拷贝构造函数,就会出现如下图:
在这里插入图片描述
当改变s中值时,对ss中值不影响。
在这里插入图片描述

// 手动进行类的析构函数
~Myclass(){delete _data;}

同样一段代码,若显示的调用虚构函数对s的内容进行delete此时,ss中信息也就被释放这样会造成内存卸扣已经一些未知的安全问题。
总结: 编译器生成的拷贝构造函数是浅拷贝,将对象中内容原封不动的拷贝到新对象中,若是原对象中涉及到了资源管理,那么新对象和原对象共用的就是同一份资源,在进行赋值或者析构时会造成内存泄露问题或者是程序崩溃。

3.3 析构函数

析构函数与构造函数的功能相反,析构函数不是完成对象的销毁,局部对象销毁工作是由编译器完成的,而对象在销毁时会自动调用析构函数,完成类的一些资源清理工作。
析构函数的名称与类名相同,前面加上一个波浪号~作为前缀,并且析构函数不接受任何参数,也无返回值,析构函数在以下情况下会被调用:

1.当对象的生命周期结束时,例如对象超出作用域或被显式的删除。
2.当对象作为另一个对象的成员被销毁时。
3.当对象在类上通过new运算符分配时,然后通过delete运算符删除时。
4.若是类中显示的使用new进行资源申请,那么若是不在析构函数中定义释放,就会造成资源泄露。

若是显示的实例了析构函数,那么就应该在对象销毁之前释放所分配的动态内存、关闭打开的文件、释放占用的其他资源等。
同时建议基类的析构函数最好设置成虚函数。


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* s = new Derived;delete s;return 0;
}

在这里插入图片描述
若是不将基类设置为虚函数那么就会出现以下情况:
在这里插入图片描述
在delete基类指针的派生类对象时,并不会堆派生类进行释放,导致内存泄漏。
在手动释放资源时,可以看出基类与派生类的堆资源都被释放。
之前在多态中我们虚函数的定义是函数名一定要相同才有可能构成虚函数,而析构函数是一种例外,虚函数是一种动态多态,是在运行时实现了,而析构函数的虚函数就是其中的一种例外,所以最好将基类的析构函数声明成虚函数。

3.4 赋值运算符重载

在C++中为了代码的可能性,引入了通过operator关键字来支持运算符重载,运算符重载是针对自定义类型的。
通常的写法为:

operator重载运算符(参数列表)
{然后进行处理
}

赋值运算符也可以当作一种特殊的函数,用于将一个对象的值赋给另一个对象。
注意事项:

1.不能通过连接其他符号来创建系的操作符:例如:operator@
2.重载操作符必须有一个类类型或者枚举类型的操作数
3.用于内置类型的操作符,的含义不能改变,例如:内置的整形+,-;
4.作为类成员的重载函数时,其形参看起来比操作数数目少1,成员函数的操作符有一个默认的形参this,限定为第一个形参。

常见运算符重载:

1.赋值运算符重载
2.++、–重载
3.输出和输出运算符(>> <<)重载
4.[ ]运算符重载
5.*和->重载
6.()重载

下面是这些运算符重载实例:

#include <iostream>
#include <string>class student
{
public:int _chinese;int _math;int _english;int* _data;std::string _name;
public:student(int data,int chinese,int math,int english,std::string name):_chinese(chinese),_math(math),_english(english),_name(name){_data = new int;*_data = data;}void operator=(const int tmp){if (this->_chinese != tmp){_chinese = tmp;}}void operator++(){this->_english++;}void operator--(){this->_math--;}int* operator*(){return this->_data;} void print(){std::cout << *_data<<_chinese << _math << _english << _name << std::endl;}
};int main()
{student stu(66,10, 15, 5, "张三");stu.print();student stu1(66,11, 16, 5, "小徐");stu1.print();stu1 = stu._chinese;stu1._math--;stu1._english++;int* m=stu1.operator*();std::cout << *m << std::endl;return 0;
}

在这里插入图片描述
一部分赋值运算符重载实现案例。

默认赋值运算符重载:

1.如果一个类没有显示定义赋值运算符重载,编译器会生成一个默认的赋值运算符重载。
2.编译器生成的默认赋值运算符重载是按照浅拷贝方式生成的。
3.如果类中涉及到资源管理时,用户必须显示提供赋值运算符重载,否则可能会造成内存泄露或运行时崩溃,用户按照深拷贝方式提供。

四、类中const成员与static成员

在类中成员一般大的可以分为三类:
普通成员变量:
这一般表示该变量是一个常量,并且在编译阶段会进行参数类型检测以及替换,比宏常量更安全,因此可以用其取代宏常量。
const修饰类成员、函数:
首先const变量,const指的是此变量是只读的,不应该被改变。
如果在程序中修改const变量的值,在编译时,编译器将给出错误提示。
而他的不可修改行,就注定了const类变量必须被初始化。

const int val = 10;
const in val;// 编译器报错,未初始化const变量
val=5; // 编译器报错,给只读变量赋值

修饰成员函数时:

// const修饰成员函数的声明
class Myclass
{
public:// 在类中用const修饰成员函数时,是在函数的后面加上constvoid func() const{// 具体的实现}
}

const成员函数的特性:

1.const成员函数可以被const对象调用,但不能被非const对象调用
2.const成员函数可以访问类的成员变量,但不能修改他们
3.const成员函数可以调用其他const成员函数,但不能调用非const成员函数(除非用const_cast进行转换)。

include <iostream>
#include <string>class Myclass
{
private:int _val;
public:Myclass(int val):_val(val){}// const类型成员函数int getval() const {return _val;}// 非const类型成员函数int setval(int val){_val = val;}
};int main()
{const Myclass m(10);std::cout << m.getval() << std::endl;m.setval(20); // 编译失败,因为m是const对象,不能调用非const成员函数return 0;
}

当const修饰成员函数的返回值时:

#include <iostream>
#include <string>class Myclass
{
private:int _val;
public:Myclass(int val):_val(val){}
public:// 在类中const int 和 int const 成员函数返回的是一个常量整数值 //       const int* 和 int const* 返回的是一个常量整数的指针//       const int& 和 int const& 返回的是一个只读的整数引用// 这三组的意义都是相同的const int getval(){return _val;}const int& getval1(){return _val;}
};int main()
{Myclass s(10);std::cout << "_val: " << s.getval() << std::endl;std::cout << "_val: " << s.getval1() << std::endl;return 0;
}

在这里插入图片描述
对于常量值和常量对象的声明,使用const关键字的位置可以放在类型之前或之后,效果是一样的。这是因为const关键字修饰的是类型本身,而不是修饰具体的标识符。
static修饰类成员变量、函数:
在类中被static修饰的成员称为静态成员。
被static修饰的成员变量:
static成员变量知识:

1.静态成员变量不能再初始化列表位置初始化,必须在类外进行初始化,在类外初始化时,必须要加类名::,类中知识声明。
2.静态成员变量是类的属性,不属于某个具体的对象,是类所有对象共享的。
3.不存在在具体的对象中,因此不会影响sizeof的大小
4.可以通过对象.静态成员名,也可以通过类名::静态成员变量名方式访问。
5.在程序启动时,就完成了对静态成员变量的初始化工作。

#include <iostream>
#include <string>class Myclass
{
public:static int _level;Myclass(int val):_val(val){}~Myclass(){}void print(){std::cout << "_level: " << _level << "_level1: " << _level1 << std::endl;}
private:int _val;static int _level1;
};
// 类中共有static变量初始化
int Myclass::_level = 5;
// 类中私有static变量初始化
int Myclass::_level1 = 6;int main()
{Myclass s(5);s.print();// 大小计算无影响std::cout << sizeof(s) << std::endl;// 类名::访问std::cout << "Myclass::_level: " << Myclass::_level << std::endl;int m = s._level;// 对象.访问std::cout << "s._level: " << m << std::endl;return 0;
}

在这里插入图片描述
从输出可以看出,对类的大小static变量不会占用空间,因为无论是类内还是内外静态变量都是存储在静态数据区的,而普通的成员变量是存储在各个对象的内存中(若是通过new开辟的成员变量那就再堆空间上,其他在栈空间上)。

被static修饰的成员函数:
static修饰成员函数知识:

1.静态成员函数没有this指针
2.静态成员函数中不能直接访问非静态成员变量,因为所有非静态成员变量都是通过this指针访问的。
3.静态成员函数不能调用普通成员函数。
4.静态成员函数不能被this修饰。
5.静态成员函数不能是虚函数。
6.既可以通过对象,也可以通过类名::方式访问。

#include <iostream>
#include <string>class Myclass
{
public:Myclass(int val):_val(val){}~Myclass(){}void print(){std::cout << _val << std::endl;}static int add(int a, int b){return a + b + _val1;// 静态成员函数不能直接访问非静态成员变量。非静态成员变量都通过this指针调用// return a + b + _val; // print(); // 静态成员函数不能调用普通成员函数}// virtual static int add1(int a, int b)//{//	// 静态成员函数不可以是虚拟的//}
private:int _val;static int _val1;
};int Myclass::_val1 = 5;
int main()
{Myclass s(3);s.print();// 通过对象调用静态成员函数std::cout << "s.add(1,2): " << s.add(1, 2) << std::endl;// 通过类名调用静态成员函数std::cout << "Myclass::add(1,2): " << Myclass::add(1, 2) << std::endl;return 0;
}

在这里插入图片描述

五、破坏封装性的友元函数

概念:友元提供了一种突破封装的方式,有时提供遍历,但是友元破坏了三大特性中的封装!
友元函数:友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,单需要在类内部声明。
特性:

1.友元函数可访问类的私有和保护成员,但不是类的成员函数。
2.友元函数不能用const修饰
3.友元函数可以在类定义的任何地方声明,不受类访问限定符限制
4.一个函数可以是多个类的友元函数。
5.友元函数的调用与普通函数的调用和原理相同

// 定义
#include <iostream>
class Myclass
{
private:int _val;
public:Myclass(int val):_val(val){}friend void showval(const Myclass& tmp);
}
void showval(const Myclass& tmp)
{
//具体实现
}

注意:

1.友元关系是单向的,不具交换性。
2.友元关系不能传递。
3.友元关系不能继承。

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

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

相关文章

网络分层的真实含义

复杂的程序都要分层&#xff0c;这是程序设计的要求。比如&#xff0c;复杂的电商还会分数据库层、缓存层、Compose 层、Controller 层和接入层&#xff0c;每一层专注做本层的事情。 当一个网络包从一个网口经过的时候&#xff0c;你看到了&#xff0c;首先先看看要不要请进来…

【ALM工具软件】上海道宁与Perforce为您带来用于整个生命周期的应用程序生命周期管理软件

Helix ALM是 用于整个生命周期的 应用程序生命周期管理的ALM软件 具有专用于 需求管理&#xff08;Helix RM&#xff09;、测试用例管理&#xff08;Helix TCM&#xff09; 问题管理&#xff08;Helix IM&#xff09;的功能模块 Helix ALM提供了 无与伦比的可追溯性 您将…

Fiddler如何比较两个接口请求?

进行APP测试时&#xff0c;往往会出现Android和iOS端同一请求&#xff0c;但执行结果不同&#xff0c;这通常是接口请求内容差异所致。 我习惯于用Fiddler抓包&#xff0c;那此时应该如何定位问题呢&#xff1f; 分别把Android和iOS的接口请求另存为TXT文件&#xff0c;然后用…

BMS电池管理系统——电芯需求数据(三)

BMS电池管理系统 文章目录 BMS电池管理系统前言一、有什么基础数据二、基础数据分析1.充放电的截至电压2.SOC-OCV关系表3.充放电电流限制表4.充放电容量特性5.自放电率 总结 前言 在新能源产业中电芯的开发也占有很大部分&#xff0c;下面我们就来看一下电芯的需求数据有哪些 …

JavaEE初阶(1)(冯诺依曼体系、CPU、CPU基本原理、如何衡量CPU的好坏?指令、操作系统、操作系统“内核”)

目录 冯诺依曼体系&#xff08;Von Neumann Architecture&#xff09; CPU CPU基本原理&#xff1a; 如何衡量CPU的好坏&#xff1f; 1、主频&#xff08;时钟速度&#xff09;&#xff1a; 2、核心数&#xff1a; 指令 操作系统 操作系统“内核” 冯诺依曼体系&#x…

运动耳机哪种好、运动戴的蓝牙耳机推荐

作为一名运动爱好者&#xff0c;自然要有一款专业的运动耳机&#xff0c;运动耳机的重要作用就是它能帮我们缓解枯燥运动时的乏味&#xff0c;还能提高运动锻炼的效果。热爱运动的我&#xff0c;最喜欢就是运动音乐随行了&#xff0c;在用过众多蓝牙耳机之后&#xff0c;才明白…

海外ASO优化之如何优化游戏应用

如果我们发布了一款手机游戏或者管理了一款手机游戏&#xff0c;那么需要确保我们的手机游戏对合适的人可见&#xff0c;目的是增加应用的下载量。 1、优化游戏元数据的关键词。 Apple和Google在应用商店中为我们提供有限的空间&#xff0c;来描述手机游戏及其优势。我们需要使…

基于YOLOv8和WiderFace数据集的人脸目标检测系统(PyTorch+Pyside6+YOLOv8模型)

摘要&#xff1a;基于YOLOv8和WiderFace数据集的人脸目标检测系统可用于日常生活中检测与定位人脸目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的目标检测&#xff0c;另外本系统还支持图片、视频等格式的结果可视化与结果导出。本系统采用YOLOv8目标检测算…

【KRouter】一个简单且轻量级的Kotlin Routing框架

【KRouter】一个简单且轻量级的Kotlin Routing框架 KRouter&#xff08;Kotlin-Router&#xff09;是一个简单而轻量级的Kotlin路由框架。 具体来说&#xff0c;KRouter是一个通过URI来发现接口实现类的框架。它的使用方式如下&#xff1a; val homeScreen KRouter.route&l…

OpenCV(三十二):轮廓检测

1.轮廓概念介绍 在计算机视觉和图像处理领域中&#xff0c;轮廓是指在图像中表示对象边界的连续曲线。它是由一系列相邻的点构成的&#xff0c;这些点在边界上连接起来形成一个封闭的路径。 轮廓层级&#xff1a; 轮廓层级&#xff08;Contour Hierarchy&#xff09;是指在包含…

雅思 《九分达人》阅读练习(二)

目录 雅思阅读练习 《九分达人》test3 paragraph3 1.单词含义要记准确&#xff0c;敏感度要上来。 2.找准定位&#xff0c;之后理解句子大致含义。 说说关于判断题的做题方法 关于“承认”有哪些单词 同替词汇 think 可以用什么其他单词来替换 单词 一些疑问 I have…

win10 sourcetree打开一闪就退出

参考文档: 解决方案参考文档一: Solved: cant install Sourcetree on Windows 10Solved: when I double-click the installation file or run as administrator,I can see a splash screen and disappear in 10 seconds,then I open thehttps://community.atlassian.com/t5…

【C++】vector的模拟实现【完整版】

目录 一、vector的默认成员函数 1、vector类的大体结构 2、无参构造函数 3、拷贝构造函数 4、Swap(operator需要用) 5、赋值重载operator 6、析构函数 二、vector的三种遍历方式 1、size和capacity(大小和容量) 2、 operator[]遍历 3、迭代器iterator遍历和范围for 三…

php常用算法

许多人都说 算法是程序的核心&#xff0c;一个程序的好于差,关键是这个程序算法的优劣。作为一个初级phper&#xff0c;虽然很少接触到算法方面的东西 。但是对于冒泡排序&#xff0c;插入排序&#xff0c;选择排序&#xff0c;快速排序四种基本算法&#xff0c;我想还是要掌握…

Oracle数据库环境变量配置以及可能遇到的问题解决

一、如何配置Oracle数据库环境变量&#xff08;以win10为例&#xff09; 1、找到此电脑&#xff0c;鼠标右键&#xff0c;点击属性。 2、点击属性成功后&#xff0c;进入如下页面&#xff0c;找到“高级系统设置”&#xff0c;点击进入。 3、找到环境变量&#xff0c;点击进入…

STM32F4X RTC

STM32F4X RTC 什么是RTCSTM32F4X RTCSTM32F4X RTC框图STM32F4X RTC计数频率STM32F4X RTC日历STM32F4X RTC闹钟 STM32F4X RTC例程 什么是RTC RTC全程叫Real-Time Clock实时时钟&#xff0c;是MCU中一个用来计时的模块。RTC的一个主要作用是用来显示实时时间&#xff0c;就像日常…

pip安装skimage的方法

在安装skimage时&#xff0c;可能会报错误&#xff1a; 可以尝试&#xff1a;pip install scikit-image进行安装&#xff0c;使用时只需要&#xff1a;import skimage

《消息队列》专栏介绍

《消息队列》专栏介绍 目录 《消息队列》专栏介绍专栏导言什么是消息队列呢&#xff1f;应用场景&#xff08;作用&#xff09; 为什么要用消息队列呢&#xff1f;异步处理削峰填谷 举个例子 分布式消息队列的优势 应用解耦优点发布订阅优点 分布式消息队列应用场景不同消息队列…

武警三维数字沙盘电子沙盘虚拟现实模拟推演大数据人工智能开发教程第15课

部队三维数字沙盘电子沙盘虚拟现实模拟推演大数据人工智能开发教程第15课 现在不管什么GIS平台首先要解决的就是数据来源问题&#xff0c;因为没有数据的GIS就是一个空壳&#xff0c;下面我就目前一些主流的数据获取 方式了解做如下之我见&#xff08;主要针对互联网上的一些…

Linux之Shell概述

目录 Linux之Shell概述 学习shell的原因 shell是什么 shell起源 查看当前系统支持的shell 查看当前系统默认shell Shell 概念 Shell 程序设计语言 Shell 也是一种脚本语言 用途 Shell脚本的基本元素 基本元素构成&#xff1a; Shell脚本中的注释和风格 Shell脚本编…