当前位置: 首页 > news >正文

类和对象|六个默认成员函数|const成员函数|运算符重载

文章目录

  • 默认成员构造函数
    • 1. 构造函数
      • 1.1 概念
      • 1.2 特性
    • 2. 析构函数
      • 2.1 概念
      • 2.2 特性
    • 3. 拷贝构造函数
      • 3.1 概念
      • 3.2 特性
    • 4. 运算符重载
      • 4.1 赋值重载
      • 4.2 自增自减重载
      • 4.3 取地址操作符重载
    • 5. const成员函数
    • 6. 取地址重载

默认成员构造函数

上一节我们说过,空类的大小是1字节用来占位,那空类是不是真的什么都没有呢?

并不是,C++中的任何一个类都具有6个默认成员函数在这里插入图片描述

即使它是空类,它也拥有这6个默认成员函数,下面我们依次介绍这些默认成员函数~

1. 构造函数

1.1 概念

构造函数是当对象定义时编译器默认调用的,用来完成对对象属性初始化的工作。

我们一开始写的class Date是这样

class Date
{private:int _year;int _month;int _day;public:void Init(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << _year << " " << _month << " " << _day << endl;}
};int main()
{Date d1,d2;d1.Init(2023, 7, 21);d2.Init(2023, 7, 22);d1.Print();d2.Print();
}

每定义一个对象都需要调用初始化函数初始化对象的属性,如果我们哪一次忘记了初始化,那么再访问该属性时便会访问随机值,因此有没有一种办法定义对象时直接初始化呢?这样就我们就不会忘记初始化了

我们可以定义构造函数帮我们完成这件事:
构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,以保证每个数据成员都有 一个合适的初始值,并且在对象整个生命周期内只调用一次

1.2 特性

构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任务并不是开空间创建对象,而是初始化对象

特征如下

  1. 函数名与类名相同
  2. 无返回值类型
  3. 对象实例化时编译器自动调用对应的构造函数
  4. 构造函数可以重载(本质就是我们可以写多个构造函数,提供多种初始化方式)

class Date的构造函数

class Date
{private:int _year;int _month;int _day;public:Date(){_year = 1;_month = 1;_day = 1;}void Init(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << _year << " " << _month << " " << _day << endl;}
};int main()
{Date d1;d1.Print();
}

运行结果:在这里插入图片描述

构造函数在对象创建的时候自动调用(对象是编译器创建的,不是构造函数创建的,构造函数只负责对创建对象的属性进行初始化操作)

带参数的构造函数

//带参数的构造函数
Date(int year, int month, int day)
{_year = year;_month = month;_day = day;
}
int main()
{Date d1;//调用无参构造函数Date d2(2023, 7, 21);//想要调用带参数的构造函数必须将括号写在对象名后面而不是类名后面d1.Print();d2.Print();// 注意:如果通过无参构造函数创建对象时,对象后面不用跟括号,否则就成了函数声明// 以下代码的函数:声明了d3函数,该函数无参,返回一个日期类型的对象// warning C4930: “Date d3(void)”: 未调用原型函数(是否是有意用变量定义的?)Date d3();
}

**注意:**语法规定:调用带参数的构造函数必须将括号写在对象名后面

将带参构造函数和不带参构造函数合并为全缺省构造函数

	//全缺省构造函数Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}

运行结果:在这里插入图片描述

若定义了全缺省构造函数,也定义了无参构造函数,调用对象时没有指定构造函数的参数编译器不知道调用哪一个构造函数(全缺省还是无参),因而会报错(报错仅仅是因为编译器不知道调用哪一个而不是语法错误)

在这里插入图片描述

class Stack

class Stack
{
private:int* _a;int _top;int _capacity;
public://带缺省参数的构造函数Stack(int capacity = 4){_capacity = capacity;_top = 0;_a = (int*)malloc(sizeof(int) * _capacity);assert(_a);}void Push(int val){if (_capacity == _top){_capacity *= 2;int* tmp = (int*)realloc(_a, sizeof(int) * _capacity);if (tmp)_a = tmp;}_a[_top] = val;_top++;}int& Top(){return _a[_top - 1];}void Pop(){assert(_top > 0);_top--;}
};int main()
{Stack st;st.Push(1);st.Push(2);st.Push(3);st.Push(4);st.Push(5);cout << st.Top() << endl;st.Pop();cout << st.Top() << endl;
}

运行结果在这里插入图片描述

`通过汇编观察定义对象时调用了构造函数在这里插入图片描述

使用了构造函数可以让我们省去和C语言一样手动初始化栈,并且使用默认参数可以让我们设定初始容量,例如我们事先知道栈中要插入1000个元素,我们就可以直接这么定义栈Stack st(1000);这省去了后续扩容的消耗。

  1. 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数(后面皆称为系统默认构造函数),一旦用户显式定义编译器将不再生成。

    class Date

    class Date
    {
    public:/*// 如果用户显式定义了构造函数,编译器将不再生成Date(int year, int month, int day){_year = year;_month = month;_day = day;}*/void Print(){cout << _year << "-" << _month << "-" << _day << endl;}private:int _year;int _month;int _day;
    };int main()
    {// 将Date类中构造函数屏蔽后,代码可以通过编译,因为编译器生成了一个无参的默认构造函数// 将Date类中构造函数放开,代码编译失败,因为一旦显式定义任何构造函数,编译器将不再生成// 无参构造函数,放开后报错:error C2512: “Date”: 没有合适的默认构造函数可用Date d1;d1.Print();return 0;
    }
    

    我们没有定义构造函数,因此定义d1时编译器会调用编译器生成的默认构造函数

    打印结果在这里插入图片描述

    1. 系统默认构造函数作用

      • 系统默认构造函数对类的内置类型不做处理(语言自带的类型),有些编译器可能会进行处理,但是C++标准并没有这么规定

      • 系统默认构造函数会去调用自定义类型变量的构造函数(union,struct,class等)

        class Date

        class Time
        {public:Time(){cout << "Time()" << endl;_hour = 0;_minute = 0;_second = 0;}private:int _hour;int _minute;int _second;
        };
        class Date
        {private:// 基本类型(内置类型)int _year;int _month;int _day;// 自定义类型Time _t;
        };
        int main()
        {Date d;//调用Date类的系统默认构造函数return 0;
        }
        

        运行结果:<在这里插入图片描述在这里插入图片描述

        解释:
        Date类定义对象时我们会自动调用Date类的系统默认构造函数,系统默认构造函数对Date类的内置类型不做处理,调用自定义类型Time默认构造函数,因此_t的_hour,_minute,_second都会被初始化为0.

        来看一段问题代码

        class Time
        {
        public:Time(int hour, int minute, int second){cout << "Time()" << endl;_hour = hour;_minute = minute;_second = second;}
        private:int _hour;int _minute;int _second;
        };
        class Date
        {
        private:// 基本类型(内置类型)int _year;int _month;int _day;// 自定义类型Time _t;
        };
        int main()
        {Date d;//调用Date类的系统默认构造函数return 0;
        }
        

        运行结果:在这里插入图片描述

        **解释:**Date只有系统默认构造函数,定义对象时调用系统默认构造函数,系统默认构造函数调用Time类的默认构造函数,但是我们已经定义了Time带参数的构造函数,因此Time类不具有默认构造函数,因而程序出错。

        注意:C++11针对系统默认构造函数不会对内置类型进行处理做了一个补丁,C++11后允许将内置成员变量在类中声明时给定默认值

        //C++11给定缺省值
        class A
        {
        public:void Print(){cout << _a << " " << _c << endl;}
        private:int _a = 1;char _c = 'a';
        };int main()
        {A a;//调用系统默认构造函数给_a初值1,_c初值'a'a.Print();return 0;
        }
        
        1. 调用时可以不传参的构造函数称为默认构造函数,默认构造函数有3类:系统默认构造函数,自定义的无参构造函数,全缺省的构造函数。

          //默认构造函数
          class A
          {public://自定义无参构造函数A(){cout << "A()\n";}//全缺省构造函数A(int a = 1, int b = 2){_a = a;_b = b;cout << "A(int a, int b)\n";}
          private:int _a;int _b;
          };int main()
          {A a;//无法编译通过,因为不知道调用哪一个默认构造函数return 0;
          }
          

2. 析构函数

2.1 概念

析构函数与构造函数的功能相反。**析构函数的作用是在对象销毁前后执行对象中资源清理工作(**对象销毁不是析构函数完成的就像对象的创建不是构造函数完成的一样)

2.2 特性

  1. 析构函数名是在类名前加上字符~
  2. 无参数无返回值类型。
  3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构

函数不能重载

  1. 对象生命周期结束时,C++编译系统系统自动调用析构函数

    class Stack

typedef int DataType;
class Stack
{
public:Stack(size_t capacity = 3){_array = (DataType*)malloc(sizeof(DataType) * capacity);if (NULL == _array){perror("malloc申请空间失败!!!");return;}_capacity = capacity;_size = 0;}void Push(DataType data){// CheckCapacity();_array[_size] = data;_size++;}// 其他方法...~Stack(){if (_array){free(_array);_array = NULL;_capacity = 0;_size = 0;}}
private:DataType* _array;int _capacity;int _size;
};
void TestStack()
{Stack s;s.Push(1);s.Push(2);
}

有了析构函数就不需要我们自己手动销毁栈了

  1. 编译器生成的默认析构函数作用

    • 对于内置类型不做处理
    • 对于自定义类型成员,调用自定义类型的析构函数
    class Time
    {
    public:Time(){cout << "Time()" << endl;}~Time(){cout << "~Time()" << endl;}
    private:int _hour;int _minute;int _second;
    };
    class Date
    {
    public:Date(){cout << "Date()" << endl;}~Date(){cout << "~Date()" << endl;}
    private:// 基本类型(内置类型)int _year = 1970;int _month = 1;int _day = 1;// 自定义类型Time _t;
    };
    int main()
    {Date d;return 0;
    }
    

    运行结果:在这里插入图片描述

  2. 如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如class Date;有资源申请时,一定要写,否则会造成内存泄漏,比如class Stack

3. 拷贝构造函数

3.1 概念

创建对象时用当前已存在的对象初始化新对象称为拷贝。

拷贝构造函数:只有单个形参,**该形参是对本类类型对象的引用(**一般常用const引用),在用已在的类类型对象创建新对象时由编译器自动调用。

c++规定任何自定义类型的拷贝都会调用拷贝构造函数

calss Stack 和 class Date

void fun1(Date d1)
{}
void fun2(Stack st1)
{}
int main()
{Stack st;Date d;fun1(d);//传参时调用Date类型的默认拷贝构造函数fun2(st);//传参时调用Stack类型的默认拷贝构造函数return 0;
}

运行结果:

在这里插入图片描述

调用Stack拷贝构造函数时会出现问题,原因我们后面解释。

3.2 特性

  1. 拷贝构造函数是构造函数的一个重要重载形式

  2. 拷贝构造函数的参数只有一个必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。

    class Date
    {
    public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}// Date(const Date& d)   // 正确写法Date( Date d)//错误写法---拷贝构造函数的参数不能是Date,否则会发生无穷递归{_year = d._year;_month = d._month;_day = d._day;}
    private:int _year;int _month;int _day;
    };
    int main()
    {Date d1;Date d2(d1);//传参时将d1拷贝给d:Date d(d1),此时会调用拷贝构造函数,拷贝构造函数右会将d1拷贝给d:Date d(d1)引发无穷递归
    }
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5SrIgELR-1690679807038)(images/image-20230723133609228.png)]

    传值拷贝引发的无穷递归:

在这里插入图片描述

  1. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。

    class Time
    {
    public:Time(){_hour = 1;_minute = 1;_second = 1;}Time(const Time& t){_hour = t._hour;_minute = t._minute;_second = t._second;cout << "Time::Time(const Time&)" << endl;}
    private:int _hour;int _minute;int _second;
    };
    class Date
    {
    private:// 基本类型(内置类型)int _year = 1970;int _month = 1;int _day = 1;// 自定义类型Time _t;
    };
    int main()
    {Date d1;Date d2(d1);return 0;
    }
    

    运行结果:在这里插入图片描述

    1. 默认拷贝构造函数的作用

      • 对内置类型实现字节序拷贝
        • 对自定义类型会调用自定义类型的拷贝构造函数
    2. c++拷贝自定义对象时为什么要使用拷贝构造函数,和c语言一样全部按字节序拷贝可以吗?

      不可以,例如上述class Stack,若使用默认拷贝构造函数,则对于内置类型就是字节序拷贝,这就会出现内存问题,我们来回顾一下上述代码

      class Stack
      {
      public:Stack(size_t capacity = 3){_array = (DataType*)malloc(sizeof(DataType) * capacity);if (NULL == _array){perror("malloc申请空间失败!!!");return;}_capacity = capacity;_size = 0;}void Push(DataType data){// CheckCapacity();_array[_size] = data;_size++;}~Stack(){if (_array){free(_array);_array = NULL;_capacity = 0;_size = 0;}}
      private:DataType* _array;int _capacity;int _size;
      };
      void fun1(Date d1)
      {}
      void fun2(Stack st1)
      {}
      int main()
      {Stack st;Date d;fun1(d);//传参时调用Date类型的默认拷贝构造函数fun2(st);//传参时调用Stack类型的默认拷贝构造函数return 0;
      }
      

      如果是值拷贝。那么拷贝后st的成员_a和st1的成员_a都指向同一块空间在这里插入图片描述

      当st1对象销毁时,会调用析构函数,析构函数会将st1对象_a成员指向的空间释放,此时st对象的_a成员就是野指针了,当st对象销毁时调用析构函数释放野指针指向的空间就会引发内存问题。

      因此像Stack的类我们就需要自己重定义拷贝构造函数,实现深拷贝

      	//自定义拷贝构造函数实现深拷贝Stack(const Stack& st){_array = (DataType*)malloc(sizeof(DataType) * st._capacity);if (nullptr == _array){perror("malloc fail");exit(-1);}memcpy(_array, st._array, sizeof(DataType) * st._size);_capacity = st._capacity;_size = st._size;}
      int main()
      {Stack st1;st1.Push(1);st1.Push(2);st1.Push(3);Stack st2(st1);//调用拷贝构造函数完成深拷贝return 0;
      }
      

      运行结果:在这里插入图片描述

      1. 拷贝构造函数调用场景

        • 使用已存在的对象创建新对象
        • 函数参数为类类型对象
        • 函数返回值为类类型对象
        class Date
        {
        public:Date(int year, int minute, int day){cout << "Date(int,int,int):" << this << endl;}Date(const Date& d){cout << "Date(const Date& d):" << this << endl;}~Date(){cout << "~Date():" << this << endl;}
        private:int _year;int _month;int _day;
        };
        Date Test(Date d)
        {Date temp(d);return temp;
        }
        int main()
        {Date d1(2022, 1, 13);//拷贝构造函数Test(d1);return 0;
        }
        

      在这里插入图片描述


4. 运算符重载

C++为了增强代码的可读性新增了运算符重载,运算符重载是具有特殊函数名的函数,也具有返回值类型,函数名字以及参数列表,返回值的类型与普通函数相同。

函数名为:operator操作符
函数原型为:返回值类型 operator操作符(参数列表)

注意:

  1. 不能通过连接其它符号来创建新的操作符:比如operator@
  2. 重载操作符必须有一个参数为自定义类型参数
  3. 用于内置类型的运算符,其含义不能改变,例如:内置类型的+,不能改变其含义
  4. 用于类成员函数重载时,其形参看起来总是比操作数目少1,因为成员函数的第一个参数为隐藏的this指针
  5. .* :: sizeof ?: .这五个操作符不可以重载
//运算符重载
class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}//运算符重载为成员函数可以访问类的私有成员bool operator==(const Date& d2)//实际上(Date* const this, const Date&d2){return _year == d2._year && _month == d2._month && _day == d2._day;}private:int _year;int _month;int _day; 
}; 
//bool operator==(const Date& d1, const Date& d2)
//{
//	return d1._year == d2._year && d1._month == d2._month && d1._day == d2._day;//由于类外部不能直接访问private成员
//	//可以通过友元函数解决,这里先将运算符重载作为成员函数.
//}int main()
{Date d1(2023, 7, 23);Date d2(2023, 7, 21);cout << d1.operator==(d2);

运行结果:

在这里插入图片描述

这种调用和调用普通成员函数的方法一样看不出可读性,因此调用运算符重载时可以像内置类型一样直接使用运算符。

在这里插入图片描述

需要注意的是d1==d2会被编译器转换为d1.operator(d2) d2==d1会被编译器转换为d2.operator(d1),即操作符的左操作数是调用运算符重载的对象,也是his指针指向的对象

4.1 赋值重载

a.赋值运算符重载格式

  • 参数类型:const T&,引用传递可以提高传参效率
  • 返回值类型:T&,有返回值是为了支持连续赋值,返回引用是为了提高返回的效率。
  • 检查是否给自己赋值
  • 返回*this:要符合连续赋值的含义
class Date
{
public:Date(int year = 2023, int month = 7, int day = 28){_year = year;_month = month;_day = day;}Date& operator=(const Date& date){if (this != &date){_year = date._year;_month = date._month;_day = date._day;}return *this;//出了函数后*this还存在,可以返回引用}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;Date d2(2023, 7, 20);d2 = d1;//调用赋值重载,转化为d2.operator=(d1);d2.Print();return 0;
}

运行结果:在这里插入图片描述

b.编译器会默认生成赋值重载成员函数

如果我们没有显示定义赋值重载,则编译器会默认生成一个复制重载函数,并且该函数完成字节序拷贝,类似于默认生成的拷贝构造函数。对于class Stack这种类型,使用默认的赋值重载函数将会出错,需要使用自定义的赋值重载函数和自定义的拷贝构造函数。

c.赋值运算符只能重载为成员函数,不可以重载为全局函数

上面刚说过,每一个类都会有自己的默认赋值重载函数,如果我们将赋值重载写为全局函数,那么该类就会生成一个默认重载函数,调用时不知道调用类的赋值重载还是调用全局的赋值重载。

d.Date d; Date d2 = d属于拷贝构造函数,不会调用赋值重载

**注意:**如果类中未涉及到资源管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必须要实现。

4.2 自增自减重载

自增自减分为前缀自增、后缀自增、前缀自减、后缀自减。前后缀自增都是单目运算符,那么重载时如何区分重载的对应运算符是前缀还是后缀呢?

C++规定,后缀重载时多增加一个int类型的参数,但调用该函数时不需要显示传递参数,编译器会自动传递

class A
{
public:A(){_a = 1;}A operator++()//重载前缀++{_a++;return *this;}A& operator++(int)//重载后缀++{A tmp(*this);_a++;return tmp;}void Print(){cout << _a << endl;}
private:int _a;
};
int main()
{A a;a++;//编译器转换为a.operator++()a.Print();++a;//编译器转换为a.operator++(0);a.Print();
}

可以看见,对于自定义类型,前置++不需要调用拷贝构造函数,后置++需要调用2次拷贝构造函数。因此对于自定义类型来说前置++的效率更高。

总结

  1. 前缀重载运算符效率高
  2. 定义后缀重载时参数列表给出一个int类型参数作为标记

4.3 取地址操作符重载

取地址及const取地址操作符重载

5. const成员函数

调用成员函数时实际上会传递this指针,this指针指向的是当前对象,我们知道,this指针在函数参数中不可以显示传递接受,那么如果我们要求当前对象的相关信息不可以被更改怎么办呢?我们需要用const修饰this指针,但是这里的const应该放在哪里呢?我们规定,const修饰成员函数时const应该放在函数参数列表最后面。

class Date
{
public:Date(int year = 2023, int month = 7, int day = 28){_year = year;_month = month;_day = day;}Date& operator=(const Date& date)//只能重载为成员函数{if (this != &date){_year = date._year;_month = date._month;_day = date._day;}return *this;//出了函数后*this还存在,可以返回引用}void Print()const//const成员函数表明调用的对象信息不可以更改{cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d;d.Print();//权限缩小const Date d1;d1.Print();//权限平移return 0;
}

运行结果:在这里插入图片描述

注意:const成员函数可以和普通成员函数同时存在,调用时优先匹配最合适的

class Date
{
public:Date(int year = 2023, int month = 7, int day = 28){_year = year;_month = month;_day = day;}void Print()const //const成员函数表明调用的对象信息不可以更改--参数为const的成员函数:既可以打印const对象,又可以打印非const对象{cout << _year << "-" << _month << "-" << _day << endl;cout << "void Print()const\n";}//const成员函数重载void Print()//参数为没有被const修饰的成员函数:只能打印非const对象{cout << _year << "-" << _month << "-" << _day << endl;cout << "void Print()\n";}
private:int _year;int _month;int _day;
};
int main()
{Date d1;const Date d2;d1.Print();//void Print()d2.Print();//void Print() constreturn 0;
}

理论上void Print() const可以打印非const对象,但是这里重载了非const的Print函数,因此d1.Print()时会优先调用最佳匹配的,也就是void Print()

关于const成员函数需要知道的几点

  1. const对象不可以调用非const成员函数
  2. 非const对象可以调用const成员函数
  3. const成员函数内部不可以调用非const成员函数
  4. 非const成员函数内部可以调用const成员函数

6. 取地址重载

//取地址重载
class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}//普通取地址重载Date* operator&(){return this;}//const取地址重载const Date* operator&()const{return this;}
private:int _year;int _month;int _day;
};

取地址运算符一般不会重载,使用默认生成的即可,除非你不想让别人获取对象的地址

相关文章:

类和对象|六个默认成员函数|const成员函数|运算符重载

文章目录 默认成员构造函数1. 构造函数1.1 概念1.2 特性 2. 析构函数2.1 概念2.2 特性 3. 拷贝构造函数3.1 概念3.2 特性 4. 运算符重载4.1 赋值重载4.2 自增自减重载4.3 取地址操作符重载 5. const成员函数6. 取地址重载 默认成员构造函数 上一节我们说过&#xff0c;空类的大…...

从源码角度去深入分析关于Spring的异常处理ExceptionHandler的实现原理

ExceptionHandler的作用 ExceptionHandler是Spring框架提供的一个注解&#xff0c;用于处理应用程序中的异常。当应用程序中发生异常时&#xff0c;ExceptionHandler将优先地拦截异常并处理它&#xff0c;然后将处理结果返回到前端。该注解可用于类级别和方法级别&#xff0c;…...

04mysql查询语句之查询与分页02

1. 所有有门派的人员信息 &#xff08; A、B两表共有&#xff09; INSERT INTO t_dept(deptName,address) VALUES(华山,华山); INSERT INTO t_dept(deptName,address) VALUES(丐帮,洛阳); INSERT INTO t_dept(deptName,address) VALUES(峨眉,峨眉山); INSERT INTO t_dept(deptN…...

原型模式——对象的克隆

1、简介 1.1、概述 可以通过一个原型对象克隆出多个一模一样的对象&#xff0c;该模式被称为原型模式。 在使用原型模式时&#xff0c;需要首先创建一个原型对象&#xff0c;再通过复制这个原型对象来创建更多同类型的对象。 1.2、定义 原型模式&#xff08;Prototype Patt…...

[SQL挖掘机] - 多表连接

介绍: 在 SQL 中&#xff0c;多表连接是指将多个表根据某些条件进行联接&#xff0c;以获取相关联的数据。这允许我们跨多个表进行查询&#xff0c;并且根据表之间的关系获取所需的结果。 作用: 当在多个表中存储相关数据时&#xff0c;使用多表连接可以将这些表组合起来以获…...

Day 14 C++ 对象的初始化和清理

目录 为什么要进行对象的初始化和清理 构造函数和析构函数 构造函数&#xff08;Constructor&#xff09; 构造函数语法 调用时机 构造函数的调用方式 括号法 显式法 隐式转换法 构造函数分类 分类方式 按参数分为有参构造和无参构造 按类型分为普通构造和拷贝构造…...

Delphi7最佳登录窗体设计

Delphi7我们这里用登录窗体来做演示。输入正确用户名和密码后&#xff0c;登录窗体释放&#xff0c;显示主窗体。 方法/步骤 1.打开Delphi7集成开发环境&#xff0c;在默认工程的Form1窗体放置一个Label1控件&#xff0c;拖动控件边界调整大小&#xff0c;并将Object Inspect…...

动脑学院Jetpack Compose学习笔记

最近b站学习了一下Compose相关内容&#xff0c;整理了相关笔记&#xff0c;仅供大家参考。 资源链接如下&#xff0c;象征性收取1个积分 https://download.csdn.net/download/juliantem/88125198...

Qt中线程的使用

Qt中线程的使用 在qt中线程的使用有两种方式&#xff0c;第一种就是创建一个类继承QObject类&#xff0c;之后使用moveToThread函数将线程添加到类中。另一种就是创建一个类继承QThread类&#xff0c;在类中实现run函数。 第一种方式&#xff1a; 1、首先创建一个自定义的类…...

基于YOLOv8开发构建蝴蝶目标检测识别系统

在前面的一篇博文中已经很详细地描述了如何基于YOLOv8开发构建自己的个性化目标检测模型&#xff0c;感兴趣的话可以看下&#xff1a; 《基于YOLOv8开发构建目标检测模型超详细教程【以焊缝质量检测数据场景为例】》 本文的主要目的就是基于YOLOv8来开发构建细粒度的蝴蝶目标…...

【已解决】电脑连上网线但无法上网

文章目录 案例情况解决方案必要的解决方法简要概括详细步骤1、打开控制面板2、打开更改适配器设置3、 找Internet协议版本44、修改配置 可能有用的解决方法 问题解决原理Internet 协议版本 4&#xff08;TCP/IPv4&#xff09;确保IP地址和DNS服务器设置为自动获取 案例情况 网…...

Linux 学习记录57(ARM篇)

Linux 学习记录57(ARM篇) 本文目录 Linux 学习记录57(ARM篇)一、外部中断1. 概念2. 流程图框 二、相关寄存器1. GIC CPU Interface (GICC)2. GIC distributor (GICD)3. EXTI registers 三、EXTI 寄存器1. 概述2. 内部框图3. 寄存器功能描述4. EXTI选择框图5. EXTI_EXTICR1 &…...

Doris注意事项,Doris部署在阿里云,写不进去数据

1.Doris官网 Doris官网https://doris.apache.org/ 2.根本原因 本地idea访问FE&#xff0c;FE会返回BE的地址&#xff0c;但是在服务器上通过ip addr查看&#xff0c;发现只有局域网IP&#xff0c;所以FE返回了局域网的IP&#xff0c;导致idea连接不上BE 3.解决办法 重写Ba…...

502 Bad GateWay报错的解决方法

什么是502 bad gateway 报错 简单来说 502 是报错类型代码 bad gateway 错误的网关。是Web服务器作为网关或代理服务器时收到无效的响应。 用我们的口语说就是运行网站的服务器暂时挂了(不响应)。 产生错误的原因 1.连接超时 我们向服务器发送请求 由于服务器当前链接太多&am…...

openpnp - ReferenceStripFeeder 改版零件

文章目录 openpnp - ReferenceStripFeeder 改版零件概述笔记整体效果散料飞达主体磁铁仓盖板飞达编带中间压条飞达编带两边压条装配体用的8mm编带模型END openpnp - ReferenceStripFeeder 改版零件 概述 官方推荐了ReferenceStripFeeder的模型smd_strip_feeders_mod_tray.zip…...

VoxPoser:使用大语言模型(GPT-4)来对机器人操作的可组合三维值图【论文解读】

这是最近斯坦福的李飞飞团队的一篇论文:VoxPoser: Composable 3D Value Maps for Robotic Manipulation with Language Models 主要是通过大语言模型LLM和视觉语言模型VLM结合&#xff0c;来对机器人做各种日常操作&#xff0c;我们可以先来看下实际效果&#xff1a;大语言模型…...

RISC-V公测平台发布 · 第一个WEB Server “Hello RISC-V world!”

RISC-V公测平台Web Server地址&#xff1a;http://175.8.161.253:8081 一、前言 Web Server是互联网应用的基础设施&#xff0c;无论是用户访问网站&#xff0c;还是后端服务提供商和开发者构建各种应用程序&#xff0c;Web Server都在其中扮演着至关重要的角色。 显而易见…...

Linux 发行版 CentOS 于 Ubuntu 软件的安装、卸载、查找

CentOS于Ubuntu 内核都是Linux&#xff0c;是一样的。 CentOS 软件格式 .rpm sudo yum [-y] [ install | remove | search ] 软件名称 install 安装 remove 移除 search 搜索 Ubuntu 软件格式 .deb sudo apt [-y] [ install | remove | search ] 软件名称 install 安装 remove…...

cmd相关操作命令

1.根据端口号查询对应进程的PID netstat -ano | findstr 端口号 例如&#xff1a;netstat -ano | findstr 9080&#xff1b;该端口所属进程的PID为6684 2.根据PID查询对应进程 tasklist | findstr PID 例如&#xff1a;tasklist | findstr 6684&#xff1b;该PID所属进程名为…...

使用EM算法完成聚类任务

EM算法&#xff08;Expectation-Maximization Algorithm&#xff09;是一种基于迭代优化的聚类算法&#xff0c;用于在无监督的情况下将数据集分成几个不同的组或簇。EM算法是一种迭代算法&#xff0c;包含两个主要步骤&#xff1a;期望步骤&#xff08;E-step&#xff09;和最…...

❤️创意网页:创意视觉效果粒子循环的网页动画

✨博主&#xff1a;命运之光 &#x1f338;专栏&#xff1a;Python星辰秘典 &#x1f433;专栏&#xff1a;web开发&#xff08;简单好用又好看&#xff09; ❤️专栏&#xff1a;Java经典程序设计 ☀️博主的其他文章&#xff1a;点击进入博主的主页 前言&#xff1a;欢迎踏入…...

【MTI 6.S081 Lab】thread

【MTI 6.S081 Lab】thread 前言调度Uthread: switching between threads (moderate)实验任务Hints解决方案thread_switchthread_create()thread_schedule() Using threads (moderate)实验任务解决方案 Barrier (moderate)实验任务解决方案 本实验前去看《操作系统导论》第29章基…...

AWS / VPC 云流量监控

由于安全性、数据现代化、增长、灵活性和成本等原因促使更多企业迁移到云&#xff0c;将数据存储在本地的组织正在使用云来存储其重要数据。亚马逊网络服务&#xff08;AWS&#xff09;仍然是最受追捧和需求的服务之一&#xff0c;而亚马逊虚拟私有云&#xff08;VPC&#xff0…...

【C++学习笔记】extern “c“以及如何查看符号表

如何查看符号表 要查看.a文件的内容&#xff0c;可以使用ar命令。下面是一些常见的用法&#xff1a; 列出.a文件中包含的所有文件&#xff1a; ar t <filename.a>提取.a文件中的单个文件&#xff1a; ar x <filename.a> <filename.o>将.a文件中的所有文件提…...

24考研数据结构-数组和特殊矩阵

目录 数据结构&#xff1a;数组与特殊矩阵数组数组的特点数组的用途 特殊矩阵对角矩阵上三角矩阵和下三角矩阵稀疏矩阵特殊矩阵的用途 结论 3.4 数组和特殊矩阵3.4.1数组的存储结构3.4.2普通矩阵的存储3.4.3特殊矩阵的存储1. 对称矩阵(方阵)2. 三角矩阵(方阵)3. 三对角矩阵(方阵…...

服务器后台运行程序

代码运行 要让代码在服务器后台运行&#xff0c;有多种方法。在 Linux 系统中&#xff0c;最常见的有以下几种方式&#xff1a; **1. 使用 & 符号&#xff1a;** 在命令后面添加 & 符号可以让程序在后台运行。例如&#xff1a; bash python myscript.py &但是…...

大数据课程D7——hadoop的YARN

文章作者邮箱&#xff1a;yugongshiyesina.cn 地址&#xff1a;广东惠州 ▲ 本章节目的 ⚪ 了解YARN的概念和结构&#xff1b; ⚪ 掌握YARN的资源调度流程&#xff1b; ⚪ 了解Hadoop支持的资源调度器&#xff1a;FIFO、Capacity、Fair&#xff1b; ⚪ 掌握YA…...

Rust vs Go:常用语法对比(十三)

题图来自 Go vs. Rust: The Ultimate Performance Battle 241. Yield priority to other threads Explicitly decrease the priority of the current process, so that other execution threads have a better chance to execute now. Then resume normal execution and call f…...

【【51单片机DA转换模块】】

爆改直流电机&#xff0c;DA转换器 main.c #include <REGX52.H> #include "Delay.h" #include "Timer0.h"sbit DAP2^1;unsigned char Counter,Compare; //计数值和比较值&#xff0c;用于输出PWM unsigned char i;void main() {Timer0_Init();whil…...

[SQL挖掘机] - 字符串函数 - substring

介绍: substring函数是在mysql中用于提取字符串的一种函数。它接受一个字符串作为输入&#xff0c;并返回从该字符串中指定位置开始的一部分子串。substring函数可以用于获取字符串中的特定字符或子串&#xff0c;以便进行进一步的处理或分析。 用法: 下面是substring函数的…...

2010网站建设管理/优化设计

题目链接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid6396 假设k为5&#xff0c;那么开5个数组用来分别存放每头怪兽对应的五个防御力 用五个指针去从头开始遍历&#xff0c;如果当前值小于对应的攻击力&#xff0c;就判断一下这头怪兽的五个值是不是都小于其对应…...

WordPress建站维护服务/成都网站优化

文章目录 零、写在前面一、概念定义二、题目描述三、算法详解四、源码剖析五、推荐专栏六、习题练习零、写在前面 这是《算法零基础100讲》 专栏打卡学习的第 64 天了。如果觉得本专栏太贵无法承受,在博主主页添加博主好友,获取 付费专栏优惠券。   每天专栏的题,做不出来…...

小吃网站怎么做/友链交换网站

let 和 var 的区别 最近很多前端的朋友去面试被问到let和var的区别&#xff0c;其实阮一峰老师的ES6中已经很详细介绍了let的用法和var的区别。我简单总结一下&#xff0c;以便各位以后面试中使用。 ES6 新增了let命令&#xff0c;用来声明局部变量。它的用法类似于var&#…...

合肥网站建设制作公司/西安百度首页优化

内容&#xff1a;OMV在windows10下的文件共享--NAS基本条件Armbian的IP设置 以太网及WiFitransmission配置遇到的问题OMV在windows10下的文件共享--NAS基本条件看了好几个教程都有一些问题&#xff0c;目前找到可以的&#xff0c;参考链接哔哩哔哩-教你完成一台基于开源系统OMV…...

大学生做网站怎么赚钱/杭州千锋教育地址

作者很直男&#xff0c;兄弟们直接复制代码看效果吧&#xff01;&#xff01;&#xff01; 一些小细节&#xff0c;大家可以自己动手修改。 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"…...

怎么推广自己的微信号/seo是什么意思职业

电商的秒杀功能是现在电商系统的主流功能&#xff1b; 参加过电商秒杀的都知道&#xff0c;有时候会遇到商品明显没有了&#xff0c;用户还可以下单导致秒杀商品的库存时常为负数。 秒杀系统就是典型的、短时间的、大量的、突发访问&#xff1b;这样的短时大并发的系统&#…...