继承与派生(Part Ⅱ)——派生类的构造函数/析构函数

派生类的构造函数和析构函数

  • 构造函数的主要作用是对数据成员初始化。基类的构造函数是不能继承的,在声明派生类时,派生类并没有把基类的构造函数继承过来,因此,对继承过来的基类成员初始化的工作也要由派生类的构造函数承担。所以在设计派生类的构造函数时,不仅要考虑派生类所增加的数据成员的初始化,还应当考虑基类的数据成员初始化。也就是说,希望在执行派生类的构造函数时,使派生类的数据成员和基类的数据成员同时都被初始化。解决这个问题的思路是:在执行派生类的构造函数时,调用基类的构造函数。

派生类构造函数一般形式为:

派生类构造函数名(总参数表):基类构造函数名(参数表){派生类中新增数据成员初始化语句}

简单的派生类的构造函数

例:定义简单的派生类的构造函数

#include <iostream>
#include<string>
using namespace std;
class Student//声明基类Student
{
public:Student(int n, string nam, char s) //定义基类构造函数{num = n;name = nam;sex = s;}~Student() {} //基类析构函数
protected: //保护部分int num;string name;char sex;
};class Student1 : public Student //声明派生类Student1
{
public: //派生类的公用部分Student1(int n, string nam, char s, int a, string ad) :Student(n, nam, s) //派生类构造函数{age = a; //在函数体中只对派生类新增的数据成员初始化addr = ad;}void show(){cout << "num: " << num << endl;cout << "name: " << name << endl;cout << "sex: " << sex << endl;cout << "age: " << age << endl;cout << "address: " << addr << endl << endl;}~Student1() {} //派生类析构函数
private: //派生类的私有部分int age;string addr;
};int main() 
{Student1 stud1(10010, "Wang-li ", ' f', 19, "115 Beijing Road,Shanghai"); Student1 stud2(10011, "Zhang-fun ", ' m', 21, "213 Shanghai Road,Beijing"); stud1.show(); //输出第一个学生的数据stud2.show(); //输出第二个学生的数据return 0;
}

程序分析:

  • 从上面列出的派生类Student1构造函数首行中可以看到,派生类构造函数名(Student1)后面括号内的参数表中包含参数的类型和参数名(如:int n),而基类构造函数名后面括号内的参数表列只有参数名而不包括参数类型(如:n,nam,s),因为在这里不是定义基类构造函数,而是调用基类构造函数,因此这些参数是实参而不是形参。它们可以是常量、全局变量和派生类构造函数总参数表中的参数。
  • 在上例中也可以将派生类构造函数在类外面定义,而在类体中只写该函数的声明:Student1(int n, string nam, char s, int a, string ad);

在类的外面定义派生类构造函数:

Student1::Student1(int n, string nam, char s, int a, string ad) :Student(n, nam, s)
{age = a; //在函数体中只对派生类新增的数据成员初始化addr = ad;
}
  • 注意:在类中对派生类构造函数作声明时,不包括上面给出的一般形式的"基类构造函数名(参数表)"部分,即Student(n,nam,s)。只在定义函数时才将它列出。
  • 不仅可以利用初始化表对构造函数的数据成员初始化,而且可以利用初始化表调用派生类的基类构造函数,实现对基类数据成员的初始化。也可以在同一个构造函数的定义中同时实现这两种功能。例如:将派生类的基类构造函数的定义采用了下面的形式:
Student1(int n, string nam, char s, int a, string ad) :Student(n, nam, s) //派生类构造函数
{age = a; //在函数体中只对派生类新增的数据成员初始化addr = ad;
}

可以将对age和addr的初始化也用初始化表处理,将构造函数改写为以下形式:Student1(int n, string nam, char s, int a, string ad) :Student(n, nam, s), age(a), addr(ad) {}

  • 在建立一个对象时,执行构造函数的顺序是:①派生类构造函数先调用基类构造函数;②再执行派生类构造函数本身(即派生类构造函数的函数体)。
  • 在派生类对象释放时,先执行派生类析构函数~Student1(),再执行其基类析构函数~Student。

运行结果:

有子对象的派生类的构造函数

  • 类的数据成员中还可以包含类对象,如可以在声明一个类时包含这样的数据成员:Student s1; //Student是已声明的类名,s1是Student类的对象
    这时,s1就是类对象中的内嵌对象,称为子对象(subobject),即对象中的对象

例:包含子对象的派生类的构造函数

#include <iostream>
#include <string>
using namespace std;
class Student //声明基类
{
public: //公用部分Student(int n, string nam) //基类构造函数{num = n;name = nam;}void display() //成员函数,输出基类数据成员{cout << "num:" << num << endl << "name:" << name << endl;}
protected: //保护部分int num;string name;
};class Student1 : public Student //声明公用派生类Student1
{
public:Student1(int n, string nam, int n1, string nam1, int a, string ad) : Student(n, nam), monitor(n1, nam1)//派生类构造函数{age = a;addr = ad;}void show() {cout << "This student is:" << endl;display(); //输出num和namecout << "age:" << age << endl; //输出agecout << "address:" << addr << endl << endl; //输出addr}void show_monitor() //成员函数,输出子对象{cout << "Class monitor is:" << endl;monitor.display(); //调用基类成员函数}
private: //派生类的私有数据Student monitor; //定义子对象(班长)int age;string addr;
};int main()
{Student1 stud1(10010, " Wang_li", 10001, "Li_sun", 19, "115 BeijingRoad, Shanghai");stud1.show(); //输出学生的数据stud1.show_monitor(); //输出子对象的数据return 0;
}

程序分析:

  • 派生类Student1中有一个数据成员:Student monitor; //定义子对象monitor(班长),"班长"的类型不是简单类型,它是Student类的对象。应当在建立对象时对它的数据成员初始化,显然不能在声明派生类时对它初始化(如:Student monitor(10001,"Li_sun");),因为类是抽象类型,只是一个模型,是不能有具体的数据的,而且每一个派生类对象的子对象一般是不相同的。因此子对象的初始化是在建立派生类时通过调用派生类构造函数来实现的。
  • 程序中派生类构造函数首部是:Student1(int n, string nam, int n1, string nam1, int a, string ad) : Student(n, nam), monitor(n1, nam1)

运行结果:

  • 派生类构造函数的任务应该包括3个部分:
  1. 对基类数据成员初始化
  2. 对子对象数据成员初始化
  3. 对派生类数据成员初始化
  • 定义派生类构造函数的一般形式为:
派生类构造函数名(总参数表):基类构造函数名(参数表),子对象名(参数表){派生类中新增数据成员初始化语句}
  • 执行派生类构造函数的顺序是:
  1. 调用基类构造函数,对基类数据成员初始化
  2. 调用子对象构造函数,对子对象数据成员初始化
  3. 再执行派生类构造函数本身,对派生类数据成员初始化
  • 派生类构造函数的总参数表列中的参数,应当包括基类构造函数和子对象的参数表列中的参数。基类构造函数和子对象的次序可以是任意的,如上面的派生类构造函数首部可以写成Student1(int n, string nam, int n1, string nam1, int a, string ad) :monitor(n1, nam1), Student(n, nam)。编译系统是根据相同的参数名(而不是根据参数的顺序)来确立它们的传递关系的。

多层派生时的构造函数

  • 一个类不仅可以派生出一个派生类,派生类还可以继续派生,形成派生的层次结构。

例:多级派生情况下派生类的构造函数

#include <iostream>
#include <string>
using namespace std;
class Student //声明基类
{
public: //公用部分Student(int n, string nam) //基类构造函数{num = n;name = nam;}void display() //成员函数,输出基类数据成员{cout << "num:" << num << endl;cout << "name:" << name << endl;}
protected: //保护部分int num; //基类有两个数据成员string name;
};class Student1:public Student //声明公用派生类Student1
{
public:Student1(int n, string nam, int a) :Student(n, nam) //派生类构造函数{age = a; //在此处只对派生类新增的数据成员初始化}void show() //输出num,name和age{display(); //输出num和namecout << "age:" << age << endl; //输出age}
private: //派生类的私有数据int age; //增加一个数据成员
};class Student2:public Student1 //声明间接派生类Student2
{
public: //下面是间接派生类构造函数Student2(int n,string nam,int a,int s):Student1(n,nam,a){score = s;}void show_all() //输出全部数据成员{show(); //输出num,name和agecout << "score:" << score << endl; //输出score}
private:int score; //增加一个数据成员
};int main()
{Student2 stud(10010, "Li", 17, 89);stud.show_all(); //输出学生的全部数据return 0;
}

程序分析:

注意基类和两个派生类的构造函数的写法

  • 基类的构造函数首部:Student(int n, string nam)
  • 派生类Student1的构造函数首部:Student1(int n, string nam, int a) :Student(n, nam)
  • 派生类Student1的构造函数首部:Student2(int n,string nam,int a,int s):Student1(n,nam,a)
    注意:不要写成Student2(int n,string nam,int a,int s):Student(n, nam),Student1(n,nam,a)。不要列出每一层派生类的构造函数,只须写出其上一层派生类(即它的直接基类)的构造函数即可。

运行结果:

  • 在声明Student2类对象时,调用Student2构造函数;在执行Student2构造函数时,先调用Student1构造函数;在执行Student1构造函数时,先调用基类Student构造函数。

派生类构造函数的特殊形式

在使用派生类构造函数时,可以有以下两种特殊的形式:

  1. 当不需要对派生类新增的成员进行任何初始操作时,派生类构造函数的函数体可以为空,即构造函数是空函数
    如:Student1(int n,string nam,int n1,string nam1):Student(n,nam),monitor(n1,nam1){ }
    此时,派生类构造函数的参数个数等于基类构造函数和子对象的参数个数之和,派生类构造函数的全部参数都传递给基类构造函数和子对象,在调用派生类构造函数时不对派生类的数据成员初始化。此派生类构造函数的作用只是为了将参数传递给基类构造函数和子对象,并在执行派生类构造函数时调用基类构造函数和子对象构造函数。在实际工作中常见这种用法。
  2. 如果在基类中没有定义构造函数,或定义了没有参数的构造函数,那么,在定义派生类构造函数时可以不写基类构造函数。因为此时派生类构造函数没有向基类构造函数传递参数的任务。在调用派生类构造函数时,系统会自动首先调用基类的默认构造函数。
  • 如果在基类和子对象类型的声明中都没有定义带参数的构造函数,而且也不需对派生类自己的数据成员初始化,则可以不必显式地定义派生类构造函数。因为此时派生类构造函数既没有向基类构造函数和子对象构造函数传递参数的任务,也没有对派生类数据成员初始化的任务。在建立派生类对象时系统会自动调用系统提供的派生类的默认构造函数,并在执行派生类默认构造函数的过程中,调用基类的默认构造函数和子对象类型默认构造函数。
  • 如果在基类或子对象类型的声明中定义了带参数的构造函数,那么就必须显式地定义派生类构造函数,并在派生类构造函数中写出基类或子对象类型的构造函数及其参数表。
  • 如果在基类中既定义无参的构造函数,又定义了有参的构造函数(构造函数重载),则在定义派生类构造函数时既可以包含基类构造函数及其参数,也可以不包含基类构造函数。在调用派生类构造函数时,根据构造函数的内容决定调用基类的有参的构造函数还是无参的构造函数。

派生类的析构函数

  • 析构函数的作用是在对象撤销之前,进行必要的清理工作。当对象被删除时,系统会自动调用析构函数。析构函数比构造函数简单,没有类型也没有参数。
  • 在派生时,派生类是不能继承基类的析构函数的,也需要通过派生类的析构函数去调用基类的析构函数。在派生类中可以根据需要定义自己的析构函数,用来对派生类中所增加的成员进行清理工作。基类的清理工作仍然由基类的析构函数负责。在执行派生类的析构函数时,系统会自动调用基类的析构函数和子对象的析构函数对基类和子对象进行清理。
  • 调用的顺序与构造函数正好相反:先执行派生类自己的析构函数,对派生类新增加的成员进行清理,然后调用子对象的析构函数对子对象进行清理最后调用基类的析构函数,对基类进行清理。

多重继承

  • 单继承:一个类是从一个基类派生而来的
  • 多重继承:一个派生类有两个或多个基类,派生类从两个或多个基类中继承所需的属性

声明多重继承的方法

  • 如果已声明了类A、类B和类C,可以声明多重继承的派生类D:
class D:public A,private B,protected C{类D新增加的成员}

D是多重继承的派生类,它以公用继承方式继承A类,以私有继承方式继承B类,以保护继承方式继承C类。D按不同的继承方式的规则继承A、B、C的属性,确定各基类的成员在派生类中的访问权限。

多重继承派生类的构造函数

  • 多重继承派生类的构造函数形式与单继承时的构造函数形式基本相同,只是在初始表中包含多个基类构造函数。如:
派生类构造函数名(总参数表列):基类1构造函数(参数表列),基类2构造函数(参数表列),基类3构造函数(参数表列)
{派生类中新增数成员据成员初始化语句
}

各基类的排列顺序任意。派生类构造函数的执行顺序同样为先调用基类的构造函数,再执行派生类构造函数的函数体。调用基类构造函数的顺序是按照声明派生类时基类出现的顺序。

例:声明一个教师(Teacher)类和一个学生(Student)类,用多重继承的方式声明一个在职研究生(Graduate)派生类(在职教师攻读研究生)。

#include <iostream>
#include <string>
using namespace std;
class Teacher //声明类Teacher(教师)类
{
public: //公用部分Teacher(string nam, int a, string t) //构造函数{name = nam;age = a;title = t;}void display(){cout << "name:" << name << endl;cout << "age:" << age << endl;cout << "title:" << title << endl;}
protected: //保护部分string name;int age;string title; //职称
};class Student //定义类Student(学生)
{
public:Student(string nam, char s, float sco) //构造函数{name1 = nam;sex = s;score = sco;}void display1(){cout << "name:" << name1 << endl;cout << "sex:" << sex << endl;cout << "score:" << score << endl;}
protected: //保护部分string name1;char sex;float score; //成绩
};class Graduate :public Teacher, public Student
{
public:Graduate(string nam,int a,char s,string t,float sco,float w):Teacher(nam,a,t),Student(nam,s,sco),wage(w){}void show() //输出研究生的有关数据{cout << "name:" << name1 << endl;cout << "age:" << age << endl;cout << "sex:" << sex << endl;cout << "score:" << score << endl;cout << "title:" << title << endl;cout << "wages:" << wage << endl;}
private:float wage; //津贴
};int main()
{Graduate grad1("Wang_li", 24, 'f', "assistance", 89.5, 1200);grad1.show();return 0;
}

程序分析:

  • 由于在两个基类中把数据成员声明为protected,因此可以通过派生类的成员函数引用基类的成员。如果在基类中把数据成员声明为private,则派生类成员函数不能引用这些数据。
  • 在两个基类中分别用name和name1来代表姓名,其实这是同一个人的名字,从Graduate类的构造函数中可以看到总参数表中的参数nam分别传递给两个基类的构造函数,作为基类构造函数的实参。现在两个基类都需要有姓名这一项,能否用同一个名字name来代表?——在本程序中只作这样的修改是不行的,因为在同一个派生类中存在着两个同名的数据成员,在派生类的成员函数show中引用name时就会出现二义性,编译系统无法判定应该选择哪一个基类中的name。解决这个问题有一个好方法:在两个基类中可以都使用同一个数据成员名name,而在show函数中引用数据成员时指明其作用域,如:cout<<"name:”<<Teacher : : name<<endl;,这就是唯一的,不致引起二义性,能通过编译,正常运行。

运行结果:

多重继承引起的二义性问题

  • 多重继承能够有效地处理一些较复杂的问题,使编写程序具有灵活性,但是多重继承也增加了程序的复杂度,使程序的编写和维护变得相对困难,容易出错。其中最常见的问题就是继承的成员同名而产生的二义性(ambiguous)问题。

类A和类B中都有成员函数display和数据成员a,类C是类A和类B的直接派生类。分别讨论下列3种情况:

  1. 两个基类有同名成员(如图1所示)
class A
{
public:int a;void display();
};class B
{
public:int a;void display();
};class C :public A, public B //公用继承
{
public:int b;void show();
};

程序分析:

  • 如果在main函数中定义C类对象c1,并调用数据成员a和成员函数display:
C c1; //定义C类对象c1
c1.a = 3; //引用c1的数据成员a
c1.display(); //调用c1的成员函数display
  • 由于基类A和基类B都有数据成员a和成员函数display,编译系统无法判定要访问的是哪一个基类的成员,因此,程序编译出错。解决此问题,可以用基类名来限定:
c1.A::a = 3; //引用c1对象中的基类A的数据成员a
c1.A::display(); //调用c1对象中的基类A的成员函数display
  • 如果派生类C中的成员函数show访问基类A的display和a,可以不必写对象名而直接写
A::a = 3; //指当前对象
A::display();
  • 为清楚起见,图1应改为图2或图3形式表示
  1. 两个基类和派生类三者都有同名成员(如图4)
class A
{
public:int a;void display();
};class B
{
public:int a;void display();
};class C :public A, public B //公用继承
{int a;void display();
};

程序分析:

  • 如果在main函数中定义C类对象c1,并调用数据成员a和成员函数display:
C c1;
c1.a = 3;
c1.display();
  • 执行时访问的是派生类C中的成员。
    规则是:基类的同名成员在派生类中被屏蔽,成为"不可见"的,或者说,派生类新增加的同名成员覆盖了基类中的同名成员。因此如果在定义派生类对象的模块中通过对象名访问同名的成员,则访问的是派生类的成员。请注意:不同的成员函数,只有在函数名和参数个数相同、类型相匹配的情况下才发生同名覆盖,如果只有函数名相同而参数不同,不会发生同名覆盖,而属于函数重载
  • 即有3个a,3个display函数
  • 同样,要在派生类外访问基类A中的成员,应指明作用域A,写成以下形式:
c1.A::a = 3; //表示派生类对象c1中的基类A中的数据成员a
c1.A::display(); //表示派生类对象c1中的基类A中的成员函数display

3.如果类A和类B是从同一个基类派生的(如图5)

class N
{
public:int a;void display() { cout << "A::a=" << a << endl; }
};class A :public N
{
public:int a1;
};class B :public N
{
public:int a2;
};class  C :public A, public B
{
public:int a3;void show() { cout << "a3=" << a3 << endl; }
};int main()
{C c1; //定义C类对象c1...
}

程序分析:

  • 在类A和类B中虽然没有定义数据成员a和成员函数display,但是它们分别从类N继承了数据成员a和成员函数display,这样在类A和类B中同时存在着两个同名的数据成员a和成员函数display。它们是类N成员的拷贝。类A和类B中的数据成员a代表两个不同的存储单元,可以分别存放不同的数据。在程序中可以通过类A和类B的构造函数去调用基类N的构造函数,分别对类A和类B的数据成员a初始化。
  • 访问类A中基类N继承下来的成员,显然不能用c1.a = 3; c1.display();c1.N::a = 3; c1.N::display();。因为这样依然无法区别是类A中从基类N继承下来的成员,还是类B中从基类N继承下来的成员。应当通过类N的直接派生类名来指出要访问的是类N的哪一个派生类中的基类成员。如c1.A::a = 3; c1.A::display(); //要访问的是类N的派生类A中的基类成员

    派生类C中成员的情况:

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

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

相关文章

6.12C++:继承基类的构造函数、单继承的构造函数、多继承的构造函数、派生类复制构造函数、派生类的析构函数

1 继承基类的构造函数 class A{ public:A(){}; // A的构造函数 }; class B : public A{ public:using A:A&#xff1b; }2 单继承的构造函数 class A{ public:A(int i){}; }; class B : public A{ public:B(int i, int j): A(i), bb(j); /i传递给A的构造函数&#xff0c;j初始…

JavaScript构造函数继承

首先介绍对象的call()函数和apply()函数&#xff0c;这两个函数的作用相同、用法不同。它们的作用均是指定当前调用函数的this对象是谁。 call()函数&#xff1a;在第一个传递的参数为一个对象&#xff0c;该对象为该函数的this对象&#xff0c;后面依次传递函数的实参。 apply…

c++继承构造函数

【1】为什么需要继承构造函数&#xff1f; 首先&#xff0c;看看如下代码片段&#xff1a; 1 struct A2 { 3 A(int i)4 {} 5 }; 6 7 struct B : A8 { 9 B(int i) : A(i) 10 {} 11 }; 在C中非常常见&#xff1a;B派生于A&#xff0c;B在构造函数中调用A的构造函…

openAI注册/登录 报错汇总

目录 报错类型问题原因及解决**access denied**<br />**提示An error occurred**<br />**Not available**<br />**同一IP地址频繁注册**<br />**cloudflare死循环验证**<br /> 最后 报错类型 access denied You do not have access to chat.op…

【Java面试题】真实的二面面试题(参考答案为纯个人理解)

1. 你掌握前端的哪些知识&#xff1f; vue2element-ui了解一些css,js 2. 那你说一下vue中的路由吧&#xff1f; vue中的路由是用来设定访问路径的,将路径映射到组件页面上 3. 说一下前端vue页面之间传参的方式&#xff1f; 路由查询字符串(我用的) // 路由定义 { path: /a…

yolo

目标检测 导言&#xff1a;目标检测的任务表述 如何从图像中解析出可供计算机理解的信息&#xff0c;是机器视觉的中心问题。深度学习模型由于其强大的表示能力&#xff0c;加之数据量的积累和计算力的进步&#xff0c;成为机器视觉的热点研究方向。 那么&#xff0c;如何理解…

神经网络与深度学习-学习笔记(5)

1.目标检测与YOLO 目标检测问题 目标检测是在给定的图片中精确找到物体所在位置&#xff0c;并标注出物体的类别。物体的尺寸变化范围很大&#xff0c;摆放物体的角度&#xff0c;姿态不定&#xff0c;而且可以出现在图片的任何地方&#xff0c;并且物体还可以是多个类别。 目…

可见光遥感目标检测(一)任务概要介绍

前言 本篇开始对遥感图像的目标检测进行介绍&#xff0c;介绍了其目标前景、数据集以及评价指标。 本教程禁止转载。同时&#xff0c;本教程来自知识星球【CV技术指南】更多技术教程&#xff0c;可加入星球学习。 Transformer、目标检测、语义分割交流群 欢迎关注公众号CV技…

YOLOv5全面解析教程①:网络结构逐行代码解读

撰文 | Fengwen, BBuf 本教程涉及的代码在&#xff1a; https://github.com/Oneflow-Inc/one-yolov5 教程也同样适用于 Ultralytics/YOLOv5&#xff0c;因为 One-YOLOv5 仅仅是换了一个运行时后端而已&#xff0c;计算逻辑和代码相比 Ultralytics/YOLOv5 没有做任何改变&#x…

可见光遥感图像目标检测(三)文字场景检测之Arbitrary

前言 前面介绍了关于可见光遥感图像目标检测任务主要面临的问题&#xff0c;现在对旋转目标的问题进行优化&#xff0c;为了便于大家理解与之前通用目标检测区别&#xff0c;采用Faster-Rcnn网络模型的架构对旋转目标的检测进行改进。 本教程禁止转载。同时&#xff0c;本教程来…

yolov5的简单使用

yolov5是什么 来自chatGPT的描述如下 YOLOv5是一种目标检测算法&#xff0c;它是YOLO系列算法的最新版本&#xff0c;由Joseph Redmon和Alexey Bochkovskiy等人开发。与之前的版本相比&#xff0c;YOLOv5在准确性和速度方面都有所提高。YOLOv5使用一种名为“Bag of Freebies”…

yolov3_spp项目中的各种配置文件读取

目录 1. open 函数 2. cfg文件夹下文档解析 2.1 hyp.yaml 2.2 my_yolov_3.cfg 3. data文件夹下文档解析 3.1 my_data.data 3.2 其它 后缀名 .ymal .txt .json .cfg .data .names .shapes 可以自定义后缀名&#xff1f;&#xff1f; pyhon文件操作大…

目标检测算法——YOLOv5/YOLOv7改进之结合CBAM注意力机制

&#x1f496;&#x1f496;>>>加勒比海带&#xff0c;QQ2479200884<<<&#x1f496;&#x1f496; &#x1f340;&#x1f340;>>>【YOLO魔法搭配&论文投稿咨询】<<<&#x1f340;&#x1f340; ✨✨>>>学习交流 | 温澜潮…

​目标检测算法——YOLOv5/YOLOv7改进之结合Criss-Cross Attention

&#xff08;一&#xff09;前沿介绍 论文题目&#xff1a;CCNet: Criss-Cross Attention for Semantic Segmentation 论文地址&#xff1a;https://arxiv.org/pdf/1811.11721.pdf 代码地址&#xff1a;https://github.com/shanglianlm0525/CvPytorch 本文是ICCV2019的语义分…

目标检测算法——YOLOv5/YOLOv7改进之GSConv+Slim Neck(优化成本)

>>>深度学习Tricks&#xff0c;第一时间送达<<< 目录 &#xff08;一&#xff09;前言 1.GSConv模块 2.Slim Neck&#xff08;GSBottleneckVoVGSCSP&#xff09; &#xff08;二&#xff09;YOLOv5改进之GSConvSlim Neck 1.配置common.py文件 2.配置yo…

目标检测算法——YOLOv5改进|增加小目标检测层

&#x1f496;&#x1f496;>>>加勒比海带&#xff0c;QQ2479200884<<<&#x1f496;&#x1f496; &#x1f340;&#x1f340;>>>【YOLO魔法搭配&论文投稿咨询】<<<&#x1f340;&#x1f340; ✨✨>>>学习交流 | 温澜潮…

【学习笔记】YOLOv5训练自己的数据集

训练自己的数据集进行总结&#xff0c;方便接下来的学习 目录 1.设置文件夹 2.标记自己的数据集 2.1在百度图片上找到自己想要的图片并批量下载 2.2labelimg软件的使用 3.修改配置文件 3.1AOCAO parameter.yaml 3.2AOCAO model.yaml 4.开始训练 4.1改代码 4.2训练过…

Tips and tricks for Neural Networks 深度学习训练神经网络的技巧总结(不定期更新)

文章目录 本文说明Debug 技巧Overfit一个简单的Batch无法复现之前的结果 数据处理平衡数据数据增强&#xff08;Data Augmentation&#xff09;图片增强 使用Embedding数据压缩数据标准化&#xff08;Normalization&#xff09;标签平滑&#xff08;LabelSmoothing&#xff09;…

官方正品 | Ultralytics YOLOv8算法来啦(尖端SOTA模型)

&#x1f496;&#x1f496;>>>加勒比海带&#xff0c;QQ2479200884<<<&#x1f496;&#x1f496; &#x1f340;&#x1f340;>>>【YOLO魔法搭配&论文投稿咨询】<<<&#x1f340;&#x1f340; ✨✨>>>学习交流 | 温澜潮…

暑期学习杂记

7月6日 粗略复习51&#xff08;问了学长后&#xff0c;我打算直接看小车视频&#xff0c;遇到不会的再回去看江科大&#xff09; 51单片机 LED灯共阳 数码管共阴 7月7日 定时器时间计算 [参考(1条消息) 51单片机定时器使用与计算-----day3_单片机定时器定时时间计算_电子笔记…