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

【逐步剖C++】-第二章-C++类和对象(中)

前言:本章继【逐步剖C++】-第二章-C++类和对象(上)介绍有关类和对象更深层次的知识点,这里是文章导图:

在这里插入图片描述

本文较长,内容较多,大家可以根据需求跳转到自己感兴趣的部分,希望能对读者有一些帮助
那么本文也主要以导图为思路进行分享,话不多说,让我们开始吧。

一、默认成员函数

1、定义

默认成员函数指的是,用户没有显示定义时,编译器会自动生成的成员函数称为默认成员函数。

2、种类

默认成员函数一共有六个:

(1)构造函数
(2)析构函数
(3)拷贝构造函数
(4)赋值运算符重载
(5)const成员函数
(6)取地址操作符重载

上面六个默认成员函数重点在于前四个,那么本文主要侧重于对前四个进行介绍,后面两个仅进行简单的说明。

二、构造函数

1、定义及作用

构造函数用于初始化类的成员变量,在实例化对象时由编译器自动调用,以保证每个成员变量都有 一个合适的初始值。(PS:需要注意的是:其仅给类的成员变量赋予初始值,并不涉及相关的开空间问题

2、默认构造函数

准确来说,编译在对象实例化时自动调用的其实是类的默认构造函数,默认构造函数一共可分为三种:

  • 编译器自动生成的构造函数
  • 无参的默认构造函数
class A
{
public:A(){_a = 0;}
private:int _a;
}
  • 全缺省的构造函数
class A
{
public:A(int a = 0){_a = a;}
private:int _a;
}

需要注意的是,默认构造函数有且仅能有一个,否则在调用时会出现歧义。

3、特性

构造函数主要有以下几点特性:

(1)构造函数的函数名与类名相同

(2)构造函数无返回值
(3)对象实例化时编译器将自动调用默认构造函数,且在对象整个生命周期内只调用一次
(4)构造函数可以重载
(5)在类中若没有显示定义一个无参的默认构造函数编译器会自动生成,一旦显示定义编译不再生成
(6)构造函数对不同类型的成员变量处理不同:对于内置类型(如int等),编译器一般不做处理;对于自定义类型(即我们自己定义的类),编译器会再去调它的构造函数,若该自定义类型的成员无默认构造,则编译器会报错

下面是对于第六点特性的简单验证,请看:
代码:

class A
{
public:A(){cout << "A()" << endl;_a = 0;}
private:int _a;
};class Test
{
public:Test(){cout << "Test()" << endl;}
private:A _a;int _t;
};int main()
{Test t;return 0;
}

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

可以看到,对于类Test中的自定义类型A的成员_a,编译器去调用了它的默认构造函数A(),对于内置类型不做处理。

4、易错点

(1)注意区分默认构造函数默认成员函数
(2)构造函数一般为public
(3)多个默认构造函数语法上虽然可以构成重载而同时存在,但调用时会出现歧义,所以规定默认构造函数有且仅能有一个
(4)在显示定义构造函数时,若不是默认构造函数中的其中一个,最好再多定义一个构成重载,因为显示定义构造后编译器不再自动生成。即最好保证一个类中有默认构造函数,以防如上特性(6)所述的报错情况。如:

class A
{
public:A(int a)	//显示定义的构造,但不是默认构造{_a = a;}A()		//再显示定义一个默认构造{cout << "A()" << endl;_a = 0;}
private:int _a;
};class AA
{private:int _aa;A a;
};

类AA的成员a为自定义类型,那么在类AA自动生成的构造函数中,对成员a会去调用它对应类的默认构造即A(),若在A类中没有默认构造函数,则编译器会报错。

(5)调用无参构造函数的方法,应该为:A a; 而不能是A a();后者会和函数声明的形式冲突,编译器不容易识别。

三、析构函数

1、定义及作用

与构造函数功能相反,析构函数用于对象销毁时的资源清理工作。在对象生命周期结束时由编译器自动调用。(PS:需要注意的是,对象本身的销毁还是由编译器完成,析构函数主要用于对类中的成员变量做一些资源清理工作,主要体现在空间的释放等

2、特性

(1)析构函数名是在类名前加上字符 ~
(2)无返回值类型无参数
(3)对象生命周期结束时,编译器自动调用析构函数
(4)一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。
(5)析构函数不能重载
(6)构造函数对不同类型的成员变量处理不同:对于内置类型(如int等),编译器一般不做处理;对于自定义类型(即我们自己定义的类),编译器会再去调它的析构函数

3、注意点

(1)析构函数没有构造函数所谓 “默认” 的概念,也就是说一个类一定会有析构函数,自动调用时不会报错。
(2)若设计的类中涉及到动态空间的申请,那么一定要显示定义析构函数来进行空间的释放,避免内存泄漏问题;除此之外,一般可以使用系统自动生成的。

三、拷贝构造函数

1、定义与作用

拷贝构造是构造函数的一种重载形式,用于对象之间的数据拷贝工作,在用已存在的类的对象来创建(初始化)该类的新对象时,编译器会自动调用。如:

A a1;
A a2 = a1;	//编译器自动调用A类的拷贝构造

2、特性

(1)拷贝构造函数是构造函数的一种重载形式
(2)拷贝构造函数的参数有且只有一个,且必须是该类的类型的对象的引用形式(即传引用调用);否则编译器直接报错,如:

//正确的拷贝构造(传引用调用):
A(const A& a)		//加const可以保证被拷贝对象数据的安全性(不被修改)
{//..资源拷贝
}//错误的拷贝构造(传值调用):
A(const A a)
{//..资源拷贝
}

对于第二种错误的说明:
第二种写法会造成拷贝构造的无穷递归。我们知道,对于传值调用,函数调用时形参的本质是对实参的拷贝,而自定义类型的拷贝工作规定必须调用拷贝构造完成,所以每传一次参数就会调用一次拷贝构造,而每次调用还没等进入函数体,又会因为形参拷贝实参进行下一次拷贝构造的调用。
(3)若用户未显示定义,编译器会自动生成默认的拷贝构造函数,以**浅拷贝(值拷贝)**的方式对对象进行拷贝。
对于这一点特性,涉及到一个可以说贯穿我们编程学习的问题:深浅拷贝问题
下面通过一个例子来说明,请看:

class B
{private:int _b;
};class C
{private:int size;int* _c;
};
  • 对于B类
    其成员变量只有一个整型_b,在拷贝时直接进行值拷贝没问题,可以直接利用编译器自动生成的拷贝构造,自动生成拷贝构造函数具体内容即为:
B(const B& b)
{_b = b._b;	//将对象b的成员变量内容拷贝给当前对象
}
  • 对于A类
    其成员除了一个整型size外,还有一个指针_c,表示动态开辟的一块空间。若此时进行浅拷贝:
C(const C& c)
{size = c.size;_c = c._c;
}

那么会直接将被拷贝对象中已开辟好的空间的地址直接赋值给了拷贝对象的_c成员,这样会使两个不同对象的_c成员指向同一块空间。示意图如下:
在这里插入图片描述
此时会有两个问题:修改其中一个空间中的内容会影响另外一个;后创建的那个对象会先调用析构,到被拷贝对象时会再调用一次析构,即对同一块空间进行了两次清理,会报错

所以此时要进行的拷贝就为深拷贝,即编译器自动生成的拷贝构造已经无法满足我们的需求。那么所谓深拷贝,其实就是再开一块和被拷贝对象中相应成员变量一样的空间,接着再把原空间中的数据逐一拷贝到新空间中。代码及示意图如下:
在这里插入图片描述

C(const C& c)
{size = c.size;_c = new int[size];		//size表示空间大小for(int i = 0; i < size; i++){_c[i] = c._c[i];}
}

总结
类中若涉及到资源的申请,则需自己实现拷贝构造(主要是深拷贝);若不涉及,则可直接利用编译器生成的拷贝构造(浅拷贝)

3、典型的调用场景

(1)使用已存在的对象创建新的对象

A a1;
A a2 = a1;

注意:若是使用已存在对象给另一已存在对象赋值就需要通过另一个默认成员函数——赋值运算符重载了(接下来介绍)。
(2)函数参数为类类型的对象

Test(A a){}

(3)函数返回值类型为类类型

A Test()

关于(2)(3)场景的补充
这两个场景本质其实和内置类型一样:内置类型对象在传值调用时传参的本质是:形参对实参的临时拷贝;值返回时同理,先拷贝给一个临时对象,再经由临时对象将值拷贝给创建的新对象。可以看到,需要拷贝的地方还是比较多的。如果此时是深拷贝,拷贝的开销将会大大提高,所以对于场景(2),一般会采用传引用调用的方式;对于场景(3),符合传引用返回的要求,就用传引用返回

五、赋值运算符重载

1、运算符重载

在了解赋值运算符重载前,先简单了解一下运算符重载
(1)概念
C++为了增强代码的可读性引入了运算符重载,运算符重载本质上是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
函数原型:返回值类型 operator操作符(参数列表)
如:重载+号实现两个A类对象相加可写为:

class A
{
public:A operator+(const &A a)	{return _a + a._a;}//实现类的对象之间的运算一般定义为成员函数
private:int _a;
};

(2)注意事项

  • 不能创建新的操作符而实现运算符重载,如@
  • 重载操作符的操作数中必须有一个是自定义类型
  • 作为类成员函数重载时,函数形参会比实际操作数少一个,因为第一个参数隐藏的this指针
  • 有如下五个特殊的运算符不能重载.* :: sizeof ?: .

2、赋值运算符重载

一般固定格式:

//这里用T表示类类型T& operator=(const T& x)
{//..赋值操作return *this;
}

主要是如下三点:

  • 参数类型:const T&,传递引用可以提高传参效率
  • 返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是支持连续赋值
  • 返回*this :即返回对象本身,符合引用返回的场景(this指针是形参出了作用域会销毁,但对象本身不会),也符合连续赋值的含义

3、赋值运算符重载的特性

(1)赋值运算符只能重载为类的成员函数而不能重载为全局函数。因为赋值运算符重载为类的默认成员函数,定义为全局的可能会和编译器在类中自动生成的发生冲突。(PS:只有赋值运算符重载需要遵守这个规定,其他运算符不用)
(2)若用户未显示定义,编译器会自动生成,赋值运算符重载对不同类型的成员变量处理不同:对于内置类型(如int等),可直接进行值拷贝;对于自定义类型(即我们自己定义的类),编译器会再去调它的赋值运算符重载完成赋值
关于这一点特性同样也涉及了深浅拷贝的问题,若成员变量涉及到资源的管理,就一定要显示定义,如上面拷贝构造中的例子:

class C
{//构造函数
C()
{size = 4;_c = new int[size];		//创建对象时为对象开辟一定大小的空间
}//赋值运算符重载
C& operator=(const C& c)
{size = c.size;//_c = c._c; //浅拷贝,错误,会导致二者指向同一块空间,且被赋值对象原空间丢失,造成内存泄漏delete[] _c;	//先释放原空间_c = new int[size];		//再根据赋值对象的空间大小开新空间for(int i = 0; i < size; i++)	//对赋值对象空间内容进行逐一拷贝{_c[i] = c._c[i];}return *this;	//返回对象本身
}private:int size;int* _c;
};

补充:这里有个易混淆的问题:C c2 = c1;调的是拷贝构造还是赋值运算符重载
答案是拷贝构造,其实只要清楚二者的作用即可正确判断。拷贝构造用于已存在的对象去初始化一个新创建的对象;而赋值运算符重载用于两个已存在对象间的赋值。

六、const成员函数

1、定义及作用:

const修饰的成员函数称之为const成员函数。const修饰类成员函数,本质上修饰该成员函数
隐含的this指针
,表明在该成员函数中不能对类的任何成员进行修改。我们知道this指针的类型为类类型*const,那么经由const修饰的成员函数的this指针类型就变为了const 类类型* const

2、特性:

(1)const和非const的对象都可以调用const成员函数(分别对应权限的平移和缩小);
(2)const成员函数不能在函数中调用非const的成员函数(权限放大),而非const的成员函数可以在函数中调用const的成员函数(权限缩小)。

七、取地址运算符重载

1、定义及作用

可分为对普通对象的取地址和对const对象的取地址,用于返回类对象的地址,即this指针。一般情况下不需重载,直接使用编译器自动生成的即可。特殊情况下,可以重载而让取地址的人获取我们想让他们获取的内容。

八、实际运用——日期类的实现

经过上面的介绍,我们可以利用上面的知识编写一个简单的日期类。那么下面是编写的过程思路及部分的代码,请看:

1、成员变量

成员变量其实就是简单的年、月、日,则日期类我们可以定义为:

class Date
{private:int _year;int _month;int _day;
};

2、构造函数、析构函数、拷贝构造

(1)对于构造函数,我们可以实现一个全缺省的构造函数,这样既满足了类中最好有默认构造函数的需求,又可以手动对对象进行初始化。下面是实现过程:
其中主要是对参数的合法性进行判断,如1月32号就是一个非法的日期,那么为了便利日期的判断,我们需要单独写一个函数int GetMonthDay(int year, int month) ;来判断某年某月有多少天。该函数的实现如下:

  • 先判断是否为闰年(这个过程也可以封装成函数);
  • 用一个数组把每月对应天数存起来,除二月需要特殊判断一下,其他直接根据下标索引返回即可
  • 代码如下:
bool IsLeapYear(int year)
{return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0));
}int Date::GetMonthDay(int year, int month) const
{int ArrDays[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30 ,31, 30 ,31 };if (IsLeapYear(year)){ArrDays[2] = 29;}return ArrDays[month];
}

参数合法就进行相应的赋值,不合法直接退出即可。完整的全缺省构造函数代码如下:

Date(int year = 1900, int month = 1, int day = 1)
{if (year > 0&& (month > 0 && month <= 12)&& (day > 0 && day <= GetMonthDay(year, month))){_year = year;_month = month;_day = day;}else{cout << "非法日期" << endl;exit(-1);}
}

(2)结合上面所述和日期类的成员可得,拷贝构造函数析构函数以及赋值运算符都可以直接使用系统默认生成的,不需要自己显示定义。

3、运算符重载

前言:关于运算符重载的实现,最常用的技巧就是复用,即先实现某些运算符,再用已实现完成的运算符去实现其他运算符。如:实现了大于>和大于等于>=之后,小于就是不大于等于! >=(对判断大于等于的结果进行逻辑取反),小于等于就是不大于! >(对判断大于的结果进行逻辑取反),具体实现请继续阅读。

(1)+、+=等运算

关于日期的运算,我们需要明确哪些是有意义的。比如两个日期相减可以得出相差多少天,是有意义的;但相对的两个日期相加就没什么实际意义。那么关于日期有意义的操作运算总结如下:

  • 日期 --= 天数
  • 日期 ++= 天数
  • 日期++
  • 日期- -
  • 日期 - 日期

关于++ 和 - - 运算符的重载的补充:我们知道,在内置类型的操作中,++分为前置和后置;那么在运算符重载中,前置++的形式为:T& operator++();而后置++为T& operator++(int)定义时需要在参数中添加一个int型参数作为标志进行区分,在实际调用后置++时按其特性使用即可不需要另外传int型参数,编译器会自动传一个参数0。

  • 日期 --= 天数
    日期 -= 天数:
    这里先实现日期 -= 天数,因为日期 - 天数可以对其进行复用(PS:当然先实现-再复用-实现-=也可以,但这样在进行-=操作时会比用-=实现-多调用一次拷贝构造

    实现逻辑为:可以先让当前的成员_day减去参数day,结果若为负,则说明结果需要往上一个月去找,若_day加上了上一个月的天数认为负,则需再往上一个月找,直至_day为正,由此构成循环。

    日期 - 天数:
    先创建一个日期类对象,再用该对象-=(复用-=)对应的天数,然后返回该对象即可。

    如上两个操作的代码为:

// 日期 -= 天数
Date& Date :: operator-=(int day)
{if (day < 0)	//减等一个负的天数其实就是加等上对应正的天数,复用+={*this += -day;return *this;}_day -= day;while (_day <= 0){_month--;			//month先减减,保证不会出现0号if (_month == 0){_year--;_month = 12;}_day += GetMonthDay(_year, _month);		}return *this;
}// 日期-天数
Date Date :: operator-(int day) const
{Date tmp(*this);tmp -= day;return tmp;
}
  • 日期 ++= 天数
    日期 += 天数:实现思路和-=类似,先让_day加上对应的天数,如果_day大于了这个月的天数,那么就先减掉当前月的天数然后到下一个月去找(可以理解为**“先过完这个月”**),由此构成循环。
    日期 + 天数:复用+=的方法和-复用-=相同,这里不再赘述。

    如上两个操作的具体代码为:

Date& Date::operator+=(int day) 
{if (day < 0)	//+=一个负的天数其实就是减等一个正的天数,可以复用减等{*this -= -day;return *this;}_day += day;while (_day > GetMonthDay(_year, _month)){_day -= GetMonthDay(_year, _month);	_month++;if (_month == 13){_year++;_month = 1;}}return *this;
}Date Date::operator+(int day) const
{Date tmp(*this);tmp += day;return tmp;
}
  • 日期++
    前置++
    实现逻辑:让成员变量_day+1后,判断是否到下一个月,若到了下一个月,同样在月+1后需判断是否到了下一年,但其实这个判断我们在+=的实现中已经做过了,所以可以直接复用

    后置++
    可以直接复用前置++,先创建一个变量,再让this解引用++,然后再返回创建的变量即可。
    如上两个操作的具体代码为:

// 前置++
Date& Date :: operator++()
{(*this) += 1;return *this;
}// 后置++
Date Date :: operator++(int)
{Date tmp = *this;(*this) += 1;return tmp;
}
  • 日期- -:实现同++理。下面直接给出具体代码
// 后置--
Date Date :: operator--(int)
{Date tmp = *this;(*this) -= 1;return tmp;
}// 前置--
Date& Date :: operator--()
{(*this) -= 1;return *this;
}
  • 日期 - 日期:
    实现逻辑复用++,让小的日期一直++至到大的日期,统计++的次数即可。具体代码如下:
// 日期-日期 返回天数
int Date :: operator - (const Date& d) const
{//假设法找出大日期和小日期Date max = d;Date min = *this;if (*this > d){max = *this;min = d;}int count = 0;while (max != min){++min;count++;}return count;
}

(2)比较运算

比较运算符主要分为以下几种:>、>=、<、<=、==、!=
其实我们只需实现 >== ,然后可通过复用实现所有的比较运算

  • 大于>
    实现逻辑:进行年月日的逐一对比即可,其中一个大于就返回true,具体代码如下:
bool Date :: operator>(const Date& d) const
{if (_year > d._year )	{return true;}else if (_year ==d._year && _month > d._month)		{return true;}else if (_year == d._year && _month == d._month && _day > d._day){return true;}return false;
}
  • 判等==
    实现逻辑:进行年月日的逐一对比,全相等就返回true,具体代码如下:
bool Date :: operator==(const Date& d) const
{if (_year == d._year && _month == d._month && _day == d._day){return true;}return false;
}
  • 大于等于>=
    实现逻辑:即大于或等等于,具体代码如下:
bool Date :: operator >= (const Date& d) const
{if (*this > d || *this == d){return true;}return false;
}
  • 不等于!=
    实现逻辑:对判等结果进行逻辑取反即可,具体代码如下:
bool Date :: operator != (const Date& d) const
{return !(*this == d);
}
  • 小于<
    实现逻辑:对大于等于的结果进行逻辑取反即可,具体代码如下:
bool Date :: operator < (const Date& d) const
{return (!(*this >= d));
}
  • 小于等于<=
    实现逻辑:对小于的结果进行逻辑取反即可,具体代码如下:
bool Date :: operator <= (const Date& d) const
{return (!(*this > d));
}

(3)输入输出运算符重载

这里主要是对流插入>>流提取<<运算符进行重载,因为对于这两个操作符而言,本质也是有两个操作数的,如:

int a;
cin >> a;	//第一个操作数为istream类的对象cin,第二个操作数为int类对象a
cout << a;	//第一个操作数为ostream类的对象cout,第二个操作数为int类对象a

PS:关于流插入和流提取的相关细节知识,大家可以查阅相关文档进行学习,本文就进行重点说明
重载之后就能像打印一个整型一样,按照指定的方式打印日期类对象。
实现有两个要点

  • 为了实现连续流插入和流提取要返回一个对应流插入类和流提取类的引用PS:流插入类和流提取类的定义包含在文件iostream中);
  • 将这两个函数定义为全局的函数,如果定义为成员函数,由于第一个参数规定了是this指针,所以在实际使用起来就会是这样的:
Date d;
d << cout;

和我们平常用于输出整型等变量的方式相比有点别扭。
但定义为全局函数后,函数的声明为:ostream& operator<<(ostream& out, const Date& d) ,这样传参的顺序就和我们平常使用的一样了。还有一点需要注意,由于函数内部需访问类的私有成员,但函数又是全局的,所以需在类内部对这两个函数进行友元声明

	friend ostream& operator<<(ostream& out, const Date& d);friend istream& operator>>(istream& in, Date& d);

PS:正常使用时,参数out传的其实就是cout;参数in传的其实就是cin
下面是具体代码:

  • 流提取运算符<<
//日期输出
inline ostream& operator<<(ostream& out, const Date& d)		//o流中内容会改变,不加const
{out << d._year << "年" << d._month << "月"  << d._day<< "日" << endl;return out;
}
  • 流插入运算符>>
//日期输入
inline istream& operator>>(istream& in, Date& d)
{in >> d._year>> d._month>> d._day;//非法日期判断if (d._year > 0&& (d._month > 0 && d._month <= 12)&& (d._day > 0 && d._day <= d.GetMonthDay(d._year, d._month))){return in;}else{cout << "非法输入" << endl;;exit(-1);}
}

本章完。

看完觉得有觉得帮助的话不妨点赞收藏鼓励一下,有疑问或有误地方的地方还请过路的朋友们留个评论,多多指点,谢谢朋友们!🌹🌹🌹

相关文章:

【逐步剖C++】-第二章-C++类和对象(中)

前言&#xff1a;本章继【逐步剖C】-第二章-C类和对象&#xff08;上&#xff09;介绍有关类和对象更深层次的知识点&#xff0c;这里是文章导图&#xff1a; 本文较长&#xff0c;内容较多&#xff0c;大家可以根据需求跳转到自己感兴趣的部分&#xff0c;希望能对读者有一些帮…...

PL/SQL动态SQL

目录 1. 动态 sql 2. 带参数的动态 sql -- 不使用 USING 传参 1. 动态 sql -- 在 PL/SQL 程序开发中,可以使用 DML 语句,但是很多语句(如 DDL),不能直接在 PL/SQL中执行,这些语句可以使用动态 sql 来实现. 语法格式: EXECUTE IMMEDIATE --动态语句的字符串 [into 变量…...

Python绘图系统24:添加辅助坐标轴

文章目录 辅助坐标增减坐标轴时间轴**代码优化源代码 Python绘图系统&#xff1a; 前置源码&#xff1a; Python打造动态绘图系统&#x1f4c8;一 三维绘图系统 &#x1f4c8;二 多图绘制系统&#x1f4c8;三 坐 标 轴 定 制&#x1f4c8;四 定制绘图风格 &#x1f4c8;五 数据…...

Java自学网站--十几个网站的分析与评测

原文网址&#xff1a;Java自学网站--十几个网站的分析与评测_IT利刃出鞘的博客-CSDN博客 简介 很多想学Java的人不知道怎样选教程&#xff0c;本文对Java自学网站进行评测。 本文不带主观倾向&#xff0c;只客观分析各个网站的区别。 第1类&#xff1a;大型培训机构(黑马等…...

java接口怎么写

Java接口是一种定义规范的抽象类型&#xff0c;可以包含常量和方法的声明。接口在Java编程中具有重要的作用&#xff0c;可以实现代码的重用和灵活性。本文将详细介绍Java接口的编写方式和使用方法。 一、什么是Java接口 在Java中&#xff0c;接口&#xff08;Interface&…...

第8章 Spring(二)

8.11 Spring 中哪些情况下,不能解决循环依赖问题 难度:★★ 重点:★★ 白话解析 有一下几种情况,循环依赖是不能解决的: 1、原型模式下的循环依赖没办法解决; 假设Girl中依赖了Boy,Boy中依赖了Girl;在实例化Girl的时候要注入Boy,此时没有Boy,因为是原型模式,每次都…...

从0开始python学习-24.selenium 浏览器常见的操作

1. 浏览器的最大化/最小化&#xff1a;maximize_window () / minimize_window() 2. 设置浏览器的宽高&#xff1a;set_window_size() 3. 设置浏览器的位置&#xff1a;set_window_position(0,0) —》左上角为原点 4. 刷新&#xff1a;refresh() 5. 前进&#xff1a;forward() 6…...

Canal实现数据同步

1、Canal实现数据同步 canal可以用来监控数据库数据的变化&#xff0c;从而获得新增数据&#xff0c;或者修改的数据。 1.1 Canal工作原理 原理相对比较简单&#xff1a; 1、canal模拟mysql slave的交互协议&#xff0c;伪装自己为mysql slave&#xff0c;向mysql master发送…...

数据库学习笔记——DDL

数据库学习笔记——DDL 建立EMPLOYEE数据库&#xff1a; CREATE TABLE employee(employee_ID int not null,employee_name varchar(20) not null,street varchar(20) not null,city varchar(20) not null,PRIMARY KEY(employee_ID) );CREATE TABLE company(company_name varc…...

MATLAB算法实战应用案例精讲-【人工智能】边缘计算(附python代码实现)

目录 前言 几个高频面试题目 边缘计算和云计算的关系 云计算(cloud computing) 边缘计算...

精彩回顾 | 迪捷软件亮相2023世界智能网联汽车大会

2023年9月24日&#xff0c;2023世界智能网联汽车大会&#xff08;以下简称大会&#xff09;在北京市圆满落幕。迪捷软件北京参展之行圆满收官。 本次大会由工业和信息化部、公安部、交通运输部、中国科学技术协会、北京市人民政府联合主办&#xff0c;是我国首个经国务院批准的…...

【ShaderLab PBR 嗜血边缘角色_美式朋克风格_“Niohoggr“_角色渲染(第一篇)】

嗜血边缘角色Cyberpunk style Unity 渲染 《嗜血边缘》截取其中的片段如下:资源分析其中Guitar贴图4张模型:人物细节图:人物模型 Inspector面板这里做一个区域区分:Body贴图1_BC贴图1_BC属性:Body贴图2_NBody贴图3_CMBody贴图4_SRMBody贴图4_RGBReflection Probe第一版Sha…...

python经典百题之围圈报数

题目:有n个人围成一圈&#xff0c;顺序排号。从第一个人开始报数&#xff08;从1到3报数&#xff09;&#xff0c;凡报到3的人退出圈子&#xff0c;问最后留下的是原来第几号的那位。 程序分析 思路1&#xff1a;模拟游戏过程 使用一个循环队列模拟游戏过程&#xff0c;每次循…...

Google Earth Engine(GEE)案例——如何去除和过滤Landsat和sentinel等系列影像集合中的空影像(三种方法)

简介 本文的主要解决的问题是如何去除和过滤Landsat和sentinel等系列影像集合中的空影像?这个主要源于一下的问题: “从图像集中删除空图像”是什么意思?您的脚本将图像集合过滤到没有图像的日期,这会产生包含 0 个图像的图像集合:https: https://code.earthengine.goog…...

Leetcode 69.x的平方根

给你一个非负整数 x &#xff0c;计算并返回 x 的 算术平方根 。 由于返回类型是整数&#xff0c;结果只保留 整数部分 &#xff0c;小数部分将被 舍去 。 注意&#xff1a;不允许使用任何内置指数函数和算符&#xff0c;例如 pow(x, 0.5) 或者 x ** 0.5 。 示例 1&#xff1…...

Node18.x基础使用总结(二)

Node18.x基础使用总结 1、Node.js模块化1.1、模块暴露数据1.2、引入模块 2、包管理工具2.1、npm2.2、npm的安装2.3、npm基本使用2.4、搜索包2.5、下载安装包2.6、生产环境与开发环境2.7、生产依赖与开发依赖2.8、全局安装2.9、修改windows执行策略2.10、安装包依赖2.11、安装指…...

LCD 的RGB接口(SYNC Mode/ SYNC-DE Mode/ DE Mode)

1、 SYNC Mode Timing Diagram 2、 SYNC-DE Mode Timing Diagram 3、 DE Mode Timing Diagram RGB接口&#xff08;SYNC Mode/ SYNC-DE Mode/ DE Mode&#xff09;-CSDN博客...

flink生成水位线记录方式--周期性水位线生成器

背景 在flink基于事件的时间处理中&#xff0c;水位线记录的生成是一个很重要的环节&#xff0c;本文就来记录下几种水位线记录的生成方式的其中一种&#xff1a;周期性水位线生成器 周期性水位线生成器 1.1 BoundedOutOfOrdernessTimeStampExtractor 他会接收一个表示最大延…...

百度资源搜索平台出现:You do not have the proper credential to access this page.怎么办?

Forbidden site not allowed You do not have the proper credential to access this page. If you think this is a server error, please contact the webmaster. 如果你的百度资源平台&#xff0c;点进去出现这个提示&#xff0c;说明您的网站已经被百度清退了。如果你的网站…...

树莓派CM4开启I2C与UART串口登录同时serial0映射到ttyS0 开启多串口

文章目录 前言1. 树莓派开启I2C与UART串口登录2. 开启多串口总结&#xff1a; 前言 最近用CM4的时候使用到了I2C以及多个UART的情况。 同时配置端口映射也存在部分问题。 这里集中记录一下。 1. 树莓派开启I2C与UART串口登录 输入指令sudo raspi-config 跳转到如下界面&#…...

【租车骑绿道】python实现-附ChatGPT解析

1.题目 租车骑绿道 时间限制:1s 空间限制:256MB 限定语言:不限 题目描述: 部门组织绿道骑行团建活动。租用公共双人自行车骑行,每辆自行车最多坐两人、做大载重M。 给出部门每个人的体重,请问最多需要租用多少双人自行车 输入描述 第一行两个数字m、n,自行车限重m,代表部门总…...

【ONE·Linux || 多线程(一)】

总言 多线程&#xff1a;进程线程基本概念、线程控制、互斥与同步。 文章目录 总言1、基本概念1.1、补充知识1.1.1、堆区细粒度划分1.1.2、虚拟地址到物理空间的转化 1.2、如何理解线程、进程1.2.1、如何理解线程&#xff1f;1.2.2、如何理解进程&#xff1f; 1.3、实践操作1.…...

华为智能企业上网行为管理安全解决方案(1)

华为智能企业上网行为管理安全解决方案&#xff08;1&#xff09; 课程地址方案背景需求分析企业上网行为概述企业上网行为安全风险分析企业上网行为管理需求分析 方案设计组网架构设备选型设备简介行为管理要点分析方案功能概述 课程地址 本方案相关课程资源已在华为O3社区发…...

Acwing 240. 食物链

Acwing 240. 食物链 题目描述思路讲解代码展示 题目描述 思路讲解 代码展示 #include <iostream>using namespace std;const int N 50010;int n, m; int p[N], d[N]; //p[]是并查集的father,d[]是距离int find(int x) {if (p[x] ! x) { //如果说x不是树根的话int t f…...

c++ 容器适配器

Container //创建一个命名空间&#xff0c;避免和库里的冲突 namespace chen {//写一个模版template<class T, class Container deque<T>>//开始写我们的类class stack{public:void push(const T& x){_con.push_back(x);}void pop(){_con.pop_back();}const …...

正则表达式的应用领域及基本语法解析

目录 一、正则表达式的应用领域 1. 文本搜索和替换 2. 表单验证 3. 数据提取和分析 4. 数据清洗和处理 5. URL路由和路由匹配 二、正则表达式的基本语法 1. 字符匹配 2. 元字符和字符类 3. 量词和边界 4. 分组和捕获 5. 转义字符 三、常见正则表达式示例 1. 邮箱…...

CIP或者EtherNET/IP中的PATH是什么含义?

目录 SegmentPATH举例 最近在学习EtherNET/IP&#xff0c;PATH不太明白&#xff0c;翻了翻规范&#xff0c;在这里记个笔记。下面的叙述可能是中英混合&#xff0c;有一些是规范中的原文我直接搬过来的。我翻译的不准确。 Segment PATH是CIP Segment中的一个分类。要了解PATH…...

使用lombok进行bulider之后调取HashMap的自定义方法进行对象操作报空指针异常(pojo也适用)

概论 这主要的问题就是bulider的特性的问题&#xff0c;就是他只能给你搭建了一个脚手架&#xff0c;里面的东西其实他没动你的&#xff0c;你得自己去给他实体化&#xff0c;如果你使用了类似HashMap等集合的话&#xff0c;你得自己去bulid一个在那个里面作为初始化对象你才可…...

矩阵-day14

...

上古神器:十六位应用程序 Debug 的基本使用

文章目录 参考环境上古神器 DebugBug 与 DebuggingDebugDebug 应用程序淘汰原因使用限制 DOSBox学习 Debug 的必要性DOSBox-X Debug 的基本使用命令 R查看寄存器的状态修改寄存器的内容 命令 D显示内存中的数据指定起始内存空间地址指定内存空间的范围 命令 A使用命令语法错误查…...

server2012做网站/武汉百度网站优化公司

2022年终总结 回忆录 2022年焦虑和快乐是这一年中最大的两种情绪了。焦虑主要是因为心里的三块石头&#xff0c;从年初就开始悬着。第一块石头&#xff0c;科研论文录用&#xff0c;第二个石头&#xff0c;拿到国奖&#xff0c;第三个石头是拿到满意的offer。目前只剩下最后一…...

网站建设费用预算表、/电商运营公司排名

人脸识别贴纸 整个处理过程大致分为3个步骤&#xff1a;1、使用AVFoundation调用摄像头采集视频流获得图像信息2、使用CoreImage库判断采集到的图像信息中是否包含有人脸3、将结果使用OpenGL渲染显示到屏幕上 一、调用摄像头采集视频 self.captureSession [[AVCaptureSession …...

制作网站首先做的是/游戏推广员怎么做

HTML 标签Internet Explorer 10, Firefox, Opera, Chrome 以及 Safari 6 支持 标签。注释&#xff1a;Internet Explorer 9 以及更早的版本不支持 标签。 ( 推荐学习&#xff1a;html教程 )定义和用法标签标示任务的进度(进程)。HTML 4.01 与 HTML 5 之间的差异标签是 HTML 5 中…...

wordpress 刷评论数量/网络推广公司收费标准

http://www.cnblogs.com/12go/archive/2011/12/28/2304502.html转载于:https://www.cnblogs.com/cjy1993/p/3927140.html...

流媒体视频网站建设/百度网络推广营销

address 使用了requests库以及lxml作为数据提取库 这个网站似乎没有做前后端分离&#xff0c;但是没有做数据加密以及反爬措施&#xff0c;所以可以很简单的爬取 #!usr/bin/python # -*- coding:utf8 -*- """ http://wz.sun0769.com/political/index/politicsNe…...

公司让我做网站负责人/如何建网站

首先咱们还是先看看javascript中一个常用的运算符——typeof。typeof应该算是咱们的老朋友&#xff0c;还有谁没用过它&#xff1f; typeof函数输出的一共有几种类型&#xff0c;在此列出&#xff1a; function show(x) {console.log(typeof x); // undefinedconsole.log(ty…...