learn C++ NO.4 ——类和对象(2)

1.类的6个默认成员函数

1.1.默认成员函数的概念

在 C++ 中,如果没有显式定义类的构造函数、析构函数、拷贝构造函数和赋值运算符重载函数,编译器会自动生成这些函数,这些函数被称为默认成员函数。
在这里插入图片描述


class Date
{
};

初步了解了默认成员函数,上面的空类Date,其实在程序运行时,编译器会默认生成它的默认成员函数。

小结

当没有显示实现默认成员函数时,编译器会自动生成默认成员函数。

2.构造函数

2.1.构造函数的概念

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

2.2.为什么类需要构造函数呢?

我们以日期类举例,如果不用构造函数来初始化一个对象会是怎么样的呢?

class Date
{
public:
    void Init(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 d1;
    d1.Init(2023, 5, 11);
    d1.Print();
    Date d2;
    d2.Init(2023, 5, 12);
    d2.Print();
    return 0;
}

每次初始化对象都要调用这个Init函数是不是太麻烦了,这也许就是祖师爷们的年轻时想法。于是便有了构造函数。构造函数就是帮助我们初始化对象用的。下面正式介绍构造函数。

2.3.构造函数的语法及特点

首先,需要注意的是构造函数中的构造二字并不是意味着开辟空间创建对象,而是初始化对象。

语法格式

1、函数名与类名相同。
2、无返回值
3、构造函数可以重栽。

构造函数特点一

对象实例化时,编译器会自动调用对应的构造函数

class Date
{
public:
	Date()//无参构造
	{
	}	
	Date(int year = 2023,int month = 5,int day = 12//带参构造
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2002,11,24);//OK?
	Date d2;//OK?
	Date d3();//OK?
	return 0;
}

可以看到上面的Date类定义两个构造函数,在语法的层面上,两个构造函数构成函数的重载。但是,在初始化调用无参数构造函数时,会产生歧义。编译器不知道调用哪一个函数。所以,d1这样初始化是OK的,d2这样是不行的。而d3也是错误的,因为d3这样调用构造函数会和函数的声明语法上有所冲突。

构造函数特点二

如果类中没有显式定义构造函数,则c++编译器会自动生成一个无参的默认构造函数,一旦用户显示定义编译器便不再生成。

class Date
{
public:

private:
    int _year;
    int _month;
    int _day;
};

int main()
{
    Date d1;//OK?
    return 0;
}

在这里插入图片描述

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 d1;//OK?
    return 0;
}

在这里插入图片描述
通过上面的事例可以验证出,编译器在我们不定义构造函数时,会自动生成一个无参数的默认构造函数。而我们显式定义构造函数后,编译器就不会再生成默认构造函数。

构造函数特点三

这里主要介绍默认构造函数对于类型的处理。首先,先介绍类型的概念。c/c++程序中对于数据类型本质分为两个种。一种是内置类型,即语言自带的数据类型,如int/char/指针等。另一种就是自定义类型,比如struct/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 d1;
	d1.Print();//会做处理吗?
    return 0;
}

在这里插入图片描述
从上图可以看到,xcode编译器对于内置类型是不做处理的。当然在有些编译器下对于内置类型会做特殊处理。补充一点,在c++11标准中,对于这种情况打了补丁。即类的成员变量在声明时,可以给缺省值。这样给编译器生成的默认构造函数提供了参数。

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 = 2023;
    int _month = 5;
    int _day = 12;
};

int main()
{
	Date d1;
	d1.Print();
    return 0;
}

在这里插入图片描述
下面请看自定义类型的处理。

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 d1;
    return 0;
}

在这里插入图片描述
编译器自动生成的默认构造函数对于自定义类型的处理方式为:编译器回去调用自定义类型它本身的默认构造函数。

构造函数特点四

无参的构造函数、全缺省的构造函数以及我们没写编译器默认生成的构造函数都被称为默认构造函数。而默认构造函数有且只能有一个。

class Date
{
public:
    Date()
    {
        _year = 1900;
        _month = 1;
        _day = 1;
    }
    Date(int year = 1900, int month = 1, int day = 1)
    {
        _year = year;
        _month = month;
        _day = day;
}
private:
    int _year;
    int _month;
    int _day;
    
};
// 以下测试函数能通过编译吗?
void Test()
{
    Date d1;
    
}

上面的代码肯定是编译不通过的。因为这里定义了两个默认构造函数,产生了歧义。编译器也不知道该调用哪一个构造函数。

3.析构函数

3.1.析构函数的概念

析构函数顾名思义,与构造函数的功能相反,析构函数不是完成对对象本身的销毁,局部对象的销毁工作是由编译器完成的。对象在销毁时,会自动调用析构函数,以完成对于对象中的资源进行清理工作。如动态申请的内存的释放就可以由析构函数来处理。

3.2.语法以及特点

语法

1、析构函数的名称就是在类名前面加上~符号。
2、无参数和无返回值。(析构函数不能重栽)
3、一个类只能有一个析构函数。若未显式定义,系统会自动生成默认析构函数。

特点一

析构函数的工作原理:对象生命周期结束时,c++编译系统自动调用析构函数

typedef int DataType;
class Stack
{
public:
    Stack(int capacity = 3)
    {
        cout<< "Stacl()"<<endl;
        _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()
    {
        cout<<"~Stack()"<<endl;
        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);
}

int main()
{
    TestStack();
    Stack s1;
    
    return 0;
}

在这里插入图片描述

特点二

关于编译器自动生成的析构函数是如何处理自定义类型的呢?

class Time
{
public:
    ~Time()
    {
        cout << "~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 d;
  return 0;
}

在这里插入图片描述
通过上例可以看到,程序运行结束后,输出了~time() 。所以Date类型生成的默认析构函数调用了Time类型的默认析构函数。这也说明了对于内置类型,编译器会调用它的析构函数。这里main函数直接调用了Time函数的析构函数吗?答案是并不是。这里main函数生命周期结束后,局部变量d销毁。因为d的类型是自定义类型,所以编译器调用Date类的析构函数。而Date类型中还有一个自定义类型Time类。这里Date的析构函数会去调用Time的析构函数。以确保类的对象都正确的销毁。

对于都是内置类型的类中,析构函数可以考虑使用编译器默认生成的。如Date类。但是如果这个类中有需要手动释放的资源(例如动态分配的内存、打开的文件等),那么我们就需要自己实现析构函数来确保这些资源能够被正确释放。如Stack类。如果需要释放资源的成员变量都是自定义类型,那么这些成员变量会去调用它们对应类型的析构函数。这样也可以不用自己写析构函数。

特点三

由于函数内部的值通常存放在栈区空间中,而栈的性质决定了后面定义的成员变量先被析构,先定义的成员变量后被析构。

4.拷贝构造函数

4.1.拷贝构造函数的概念

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

4.2.拷贝构造函数语法及特点

//以日期类举例

class Date
{
public:
    Date(int year = 2023,int month = 5,int day = 12)//构造函数
    {
        _year = year;
        _month = month;
        _day = day;
    }
    
    Date(const Date& d)//拷贝构造函数
    {
        _year = d._year;
        _month = d._month;
        _day = d._day;
    }
    
    
    
private:
    int _year;
    int _month;
    int _day;
};

int main()
{
    Date d1;
    Date d2(d1);
    return 0;
    
}

我们就以这个例子展开来讲。首先,拷贝构造函数的形参的部分一定得是该类的同类型引用。否则将会产生无穷递归。这是因为c++规定函数传参,内置类型直接拷贝,而自定义类型需要调用它的拷贝构造函数。
在这里插入图片描述
那么又有一个问题,为什么需要const修饰引用呢?且看下面的案例分析。

//错误事例
class Date
{
public:
    Date(int year = 2023, int month = 5, int day=12)//构造函数
    {
        _year = year;
        _month = month;
        _day = day;
    }
    
    Date(Date& d)//拷贝构造函数
    {
        d._year = _year;
        d._month = _month;
        d._day = _day;
    }
    
    void Print()
    {
        cout << _year << '-' << _month << "-" << _day << endl;
    }
    
private:
    int _year;
    int _month;
    int _day;
};

int main()
{
    Date d1;
    d1.Print();
    Date d2(d1);
    d2.Print();
    d1.Print();
    return 0;
    
}

在这里插入图片描述
如果加了const修饰之后,上面的拷贝构造函数的问题就一目了然。
在这里插入图片描述
这是因为const缩小了权限,这样就保护了this指针指向的内容不被修改。我将上面的代码再写的更加详细一些,以便理解

//错误事例
    Date(const Date& d)//拷贝构造函数
    {
        d._year = this->_year;
        d._month = this->_month;
        d._day = this->_day;
    }

可以看到我们的函数两个具体的参数,一个是this指针,一个是实参的引用d。我们的本意是希望将d的值拷贝给this指针指向的成员变量。如果没有const修饰缩小权限,那岂不是赔了夫人又折兵。

4.3.系统自动生成的拷贝构造函数

如果我们不自己写拷贝构造函数,编译器也会自动生成一个拷贝构造函数。那么对于内置类型,编译器生成的默认拷贝构造函数会按照对象在内存中的数据按照字节序拷贝,这也就是通常说的浅拷贝。所以对于Date类这种成员变量都是内置类型的对象来说,编译器默认生成的拷贝构造函数可以完成对对象的拷贝。

class Date
{
public:
    Date(int year = 2023, int month = 5, int day=12)//构造函数
    {
        _year = year;
        _month = month;
        _day = day;
    }
    
    void Print()
    {
        cout << _year << '-' << _month << "-" << _day << endl;
    }
    
private:
    int _year;
    int _month;
    int _day;
};

int main()
{
    Date d1;
    d1.Print();
    Date d2(d1);
    d2.Print();
    d1.Print();
    return 0;
}

在这里插入图片描述
如果是想栈这样的类对象,编译器生成的拷贝构造函数还能否解决拷贝问题呢?

typedef int DataType;
class Stack
{
public:
    Stack(size_t capacity = 10)
    {
        _array = (DataType*)malloc(capacity * sizeof(DataType));
        if (nullptr == _array)
        {
            perror("malloc申请空间失败");
            return;
        }
        _size = 0;
        _capacity = capacity;
    }
    
    void Push(const DataType& data)
    {
        // CheckCapacity();
        _array[_size] = data;
        _size++;
    }
    
    ~Stack()
    {
        if (_array)
        {
          free(_array);
          _array = nullptr;
          _capacity = 0;
          _size = 0;
        }
    }
    
private:
  DataType *_array;
  size_t _size;
  size_t _capacity;
};
int main()
{
  Stack s1;
  s1.Push(1);
  s1.Push(2);
  s1.Push(3);
  s1.Push(4);
  Stack s2(s1);
  return 0;
    
}

在这里插入图片描述
可以看到程序直接崩溃了,这是因为同一块内存空间被释放了两次。
在这里插入图片描述
而析构函数又对这一块动态申请的内存释放了两次,导致了程序的崩溃。对于这种指向有动态申请内存的类对象时,就需要使用深拷贝。由于编译器默认生成的默认拷贝构造只能实现浅拷贝,所以需要我们自己写拷贝构造函数。
在这里插入图片描述

//深拷贝的拷贝构造函数
    Stack(const Stack& s)
    {
        _array = (int*)malloc(sizeof(int) *_capacity);
        if (nullptr == _array)
        {
            perror("malloc申请空间失败");
            return;
        }
        
        _size = s._size;
        _capacity = s._capacity;
        memcpy(_array, s._array, sizeof(int) * _capacity);
        
    }

4.4 拷贝构造函数的经典调用场景

1、使用已存在的对象拷贝创建新对象
2、函数参数可为自定义类型的类对象
3、函数返回值为自定义类型的类对象

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;
}

在这里插入图片描述
在这里插入图片描述

5.运算符重载

5.1.运算符重载的概念

C++运算符重载是指在类中重载运算符,使得这些运算符能够适用于类的对象。C++支持重载的运算符包括算术运算符、比较运算符、逻辑运算符、位运算符、赋值运算符等等。运算符重载可以提升代码的可读性。

5.2.运算符重载的语法

返回值类型 + operator关键字 + 运算符(参数列表)

注意:
1、不能通过链接其他的符号来创建新的操作符,比如operator @
2、重载的操作符必须有一个类的类型
3、用于内置的运算符,其含义不能改变,例如:加法操作符+,不能改变其原有的含义。
4、作为类成员函数重载是,主要注意的是成员函数的第一个参数为隐藏的this指针。
5、[.*],[::],[sizeof],[?:],[.] 注意以上5个运算符是不能重载的

5.3.赋值符号的运算符重载举例

同过赋值符重载完成上面介绍的拷贝构造函数的功能。首先,我们需要了解赋值符的特性,如赋值符可以支持连续的赋值操作。注意的是,赋值符重载只能在类域内部声明定义,重载到全局域中会和编译器默认生成的赋值符重载造成冲突。

class Date
{
public:
    Date(int year = 2023, int month = 5, int day = 12)//构造函数
    {
        _year = year;
        _month = month;
        _day = day;
    }

    Date(const Date& d)//拷贝构造函数
    {
        _year = d._year;
        _month = d._month;
        _day = d._day;
    }
	
	//运算符重载
    Date& operator=(const Date& d)
    {
        _year = d._year;
        _month = d._month;
        _day = d._day;
        return *this;
    }

    void Print()
    {
        cout << _year << '-' << _month << "-" << _day << endl;
    }

private:
    int _year;
    int _month;
    int _day;
};

int main()
{
    Date d1(2022, 1, 4);
    Date d2 = d1;
    Date d3(2002, 11, 24);
    d1.Print();
    d2.Print();

    d1 = d2 = d3;
    d1.Print();
    d2.Print();
    d3.Print();

    d1 = d1;
    d1.Print();

    return 0;
}

运算符重载的参数和原来操作符的参数是必须一样多的。不过this指针是作为隐含的参数传递的。
在这里插入图片描述

在这里插入图片描述
对于这个赋值符重载还有没有可以优化的地方呢?答案是有的。不难发现其实当两个类对象的成员变量值完全一样时,这里还有进行赋值拷贝。所以在一开始就判断一下两个类的成员变量值是否完全相等是比较合适的。所以下面介绍的就是逻辑等运算符的重载。

	//运算符重载
    Date& operator=(const Date& d)
    {
    	//if(*this != d)//两个类对象比较效率差
    	if(this != &d)//判断地址效率更高
    	{
	        _year = d._year;
	        _month = d._month;
	        _day = d._day;
        }
        return *this;
    }

5.4.逻辑等运算符的重载举例

bool operator==(const Date& d)const
    {
        if (_year != d._year)
            return false;
        else if (_month != d._month)
            return false;
        else if (_day != d._day)
            return false;
        else
            return true;
    }

也许你会好奇这个()后面跟的const是什么意思,我将下面告诉你。这里一个逻辑等运算符的重载就写好了,但是我们需要的是一个逻辑不等运算符。其实这里只要对这个逻辑等于进行一下复用即可

    bool operator!=(const Date& d)const
    {
        if (*this == d)
        {
            return false;
        }
        else
        {
            return true;
        }
    }

下面我们就可以通过上面重载的逻辑不等运算符来完善一下我们的赋值操作符了。

  Date& operator=(const Date& d)
    {
        if (*this != d)
        {
            _year = d._year;
            _month = d._month;
            _day = d._day;
        }
        return *this;
    }

6.const修饰成员函数

将const属性修饰成员函数,则会赋予该成员函数的this指针const属性。使该成员函数不能对任何类的成员进行修改。

6.1.语法形式

返回类型 成员函数名()const

6.2.const对象传参调用非const成员函数

class Date
{
public:
    Date(int year = 2023, int month = 5, int day = 12)//构造函数
    {
        _year = year;
        _month = month;
        _day = day;
    }


    void Print()
    {
        cout << _year << '-' << _month << "-" << _day << endl;
    }

private:
    int _year;
    int _month;
    int _day;
};

int main()
{
    Date d1(2023, 5, 14);
    const Date d2(2023, 5, 13);
    d1.Print();
    d2.Print();//error

    return 0;
}

这里d2无法调用Print函数,因为const修饰的成员对象调用非const修饰的成员函数,会造成权限的放大。d1是非const修饰的成员对象,调用非const修饰的成员函数,权限是平移的。所以可以调用。
在这里插入图片描述
若加上const修饰成员函数,d1还可以调用吗?答案是可以的。因为d1虽然没有被const修饰,但是并不妨碍它被成员函数中的const影响。权限是可以缩小的,但是权限不能被放大。
在这里插入图片描述

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

这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,比
如想让别人获取到指定的内容!

// 设计一个类,在类外面只能在栈上创建对象
// 设计一个类,在类外面只能在堆上创建对象
class A
{
public:
	static A GetStackObj()
	{
		A aa;
		return aa;
	}

	static A* GetHeapObj()
	{
		return new A;
	}
private:
	A()
	{}

private:
	int _a1 = 1;
	int _a2 = 2;
};

int main()
{
	//static A aa1;   //  静态区
	//A aa2;          //  栈 
	//A* ptr = new A; //  堆
	A::GetStackObj();
	A::GetHeapObj();

	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STL-常用算法(二.拷贝 替换 算术 集合)

开篇先附上STL-常用算法(一)的链接 STL-常用算法&#xff08;一.遍历 查找 排序&#xff09;_小梁今天敲代码了吗的博客-CSDN博客 目录 常用拷贝和替换算法&#xff1a; copy函数示例&#xff1a;&#xff08;将v1容器中的元素复制给v2&#xff09; replace函数示例&#…

Java 9 - 18 各个版本新特性总结

【 Java 9 - 18 各个版本新特性总结&#xff0c;B站视频介绍】https://www.bilibili.com/video/BV1PT411P7Wn?vd_source5a3a58ca0e99223ffb58cddf2f3a7282 一、模块化引入 模块是 Java 9 中新增的一个组件&#xff0c;可以简单理解为是package的上级容器&#xff0c;是多个pa…

gitlab建立新分支提交,cherry-pick部分更新

gitlab介绍 GitLab是一个基于Git的在线代码托管和协作平台&#xff0c;提供源代码管理、单元测试、CI/CD构建、代码审查等功能。它是一个开放源代码的Git仓库管理系统&#xff0c;使用 Ruby on Rails 构建GitLab 不仅具有自己的 Git 仓库管理系统&#xff0c;还具有很多其他的…

网络协议与攻击模拟-11-DHCP协议原理

DHCP 协议 1、掌握 DHCP 的工作原理 2、会在 Windows server 上去部署 DHCP 服务 3、抓流量 &#xff0e;正常 收到攻击后 一、 DHCP 1、 DHCP 基本概念 dhcp &#xff08;动态主机配置协议&#xff09;&#xff1a;主要就是给客户机提供 TCP / IP 参数&#xff08; IP 地…

App外包开发上线Google Play流程

完成App开发后需要在各大应用市场上线&#xff0c;国内的应用市场比较多&#xff0c;各自的规则也不相同&#xff0c;上线审核也比较复杂&#xff1b;国外上线主要是Google Play市场&#xff0c;它更重视隐私的保护&#xff0c;必须严格按照规范来保护个人隐私&#xff0c;因此…

【C++】模板的一点简单介绍

模板 前言泛型编程函数模板概念格式函数模板的原理函数模板的实例化 类模板类模板的定义格式类模板的实例化 前言 这篇博客讲的是模板的一些基本知识&#xff0c;并没有那么深入&#xff0c;但是如果你是为了过期末考试而搜的这篇博客&#xff0c;我觉得下面讲的是够了的。 之…

阿里云、腾讯云、移动云飙“价”:智能普惠成新风向?

经过过去一年的“低迷”境况之后&#xff0c;2023年云服务商因为AI大模型的爆发&#xff0c;重新燃起了斗志。站在当下的时间节点&#xff0c;云服务商们也在重新思考如何在新形势下&#xff0c;让自己占据更大的优势&#xff0c;于是一场围绕“技术竞争与市场争夺”的新战争打…

【总结】Numpy2

Numpy 1. 数组和数的运算 array1 np.arange(1,10) array1 # array([1, 2, 3, 4, 5, 6, 7, 8, 9]) array1 10 # array([11, 12, 13, 14, 15, 16, 17, 18, 19]) array1 - 10 # array([-9, -8, -7, -6, -5, -4, -3, -2, -1]) array1 * 10 # array([10, 20, 30, 40, 50, 60, 70…

3-《安卓基础》

3-《安卓基础》 一.Android系统架构二.四大组件1. Activity1.1 生命周期1.2. Activity四种启动模式1.3.Activity任务栈的概念1.4 面试题面试题1&#xff1a;onSaveInstanceState(Bundle outState)&#xff0c;onRestoreInstanceState(Bundle savedInstanceState) 的调用时机&am…

小黑子—Java从入门到入土过程:第十一章 - 网络编程、反射及动态代理

Java零基础入门11.0 网络编程1. 初识网络编程2. 网络编程三要素3.IP三要素3.1 IPV4的细节3.1.1特殊的IP地址3.1.2 常用的CMD命令 3.2 InetAddress 的使用3.3 端口号3.4 协议3.4.1 UDP协议3.4.1 - I UDP 发送数据3.4.1 - II UDP 接收数据3.4.1 - III UDP 练习&#xff08;聊天室…

前端列表页+element-puls实现列表数据弹窗功能

效果图&#xff1a; 这是一个修改的弹窗&#xff0c;我们要实现的功能是&#xff0c;在列表&#xff0c;点击修改按钮时&#xff0c;将数据带入到弹窗里面&#xff0c;点击保存时关闭弹窗。 1&#xff0c;点击修改展开弹窗 使用 eldialog组件&#xff0c;v-model绑定的值为tru…

Godot引擎 4.0 文档 - 入门介绍 - 学习新功能

本文为Google Translate英译中结果&#xff0c;DrGraph在此基础上加了一些校正。英文原版页面&#xff1a; Learning new features — Godot Engine (stable) documentation in English 学习新功能 Godot 是一个功能丰富的游戏引擎。有很多关于它的知识。本页介绍了如何使用…

迪赛智慧数——柱状图(基本柱状图):全球自动化无人机智能支出预测

效果图 全球自动化无人机智能支出及预测分析&#xff0c;2022年机器人流程自动化支出10.4十亿美元&#xff0c;智能流程自动化支出13十亿美元&#xff0c;人工智能业务操作达10.8十亿美元&#xff0c;未来&#xff0c;这些数字将进一步增长&#xff0c;自动化无人机智能也将拥有…

华为OD机试真题 Java 实现【天然蓄水池】【2023Q1 200分】

一、题目描述 公元2919年&#xff0c;人类终于发现了一颗宜居星球——X星。现想在X星一片连绵起伏的山脉间建一个天然蓄水库&#xff0c;如何选取水库边界&#xff0c;使蓄水量最大&#xff1f; 要求&#xff1a; 山脉用正整数数组s表示&#xff0c;每个元素代表山脉的高度。…

Java基础-面向对象总结(3)

本篇文章主要讲解Java面向对象的知识点 面向对象的三大特性类的扩展(抽象类,接口,内部类,枚举) 目录 面向对象和面向过程的区别? 面向对象的五大基本原则 面向对象三大特性 继承 怎么理解继承 ? 继承和聚合的区别&#xff1f; 封装 多态 什么是多态 什么是运行时多…

数字识别问题

文章目录 6.1 MNIST数据处理6.2.1 训练数据6.2.2 变量管理6.3.1 保存模型6.3.1 加载计算图6.3.1 加载模型6.3.2 导出元图 6.1 MNIST数据处理 在直接在第6章的目录下面创建文件 compat.v1.是tensorflow2.x的语法&#xff0c;全部删掉 删除compat.v1.后的代码 # -*- coding: …

基于最新SolVES 模型与多技术融合【QGIS、PostgreSQL、ARCGIS、MAXENT、R】实现生态系统服务功能社会价值评估及拓展案例分析

目录 第一章 理论基础与研究热点 第二章 SolVES 4.0 模型运行环境配置 第三章 SolVES 4.0 模型运行 第四章 数据获取与入库 第五章 环境变量与社会价值的相关分析 第六章 拓展案例分析 SolVES模型&#xff08;Social Values for Ecosystem Services&#xff09;全称为生态…

如何使用SolVES 模型与多技术融合实现生态系统服务功能社会价值评估?

生态系统服务是人类从自然界中获得的直接或间接惠益&#xff0c;可分为供给服务、文化服务、调节服务和支持服务4类&#xff0c;对提升人类福祉具有重大意义&#xff0c;且被视为连接社会与生态系统的桥梁。自从启动千年生态系统评估项目&#xff08;Millennium Ecosystem Asse…

SSL/TLS认证握手过程

一: SSL/TLS介绍 什么是SSL,什么是TLS呢&#xff1f;官话说SSL是安全套接层(secure sockets layer)&#xff0c;TLS是SSL的继任者&#xff0c;叫传输层安全(transport layer security)。说白点&#xff0c;就是在明文的上层和TCP层之间加上一层加密&#xff0c;这样就保证上层信…

Jenkins + docker-compose 在 Centos 上搭建部署

一、前期准备 1. 检查 CentOS上 是否安装 docker 可以使用以下命令&#xff1a; sudo docker version 如果已经安装了Docker&#xff0c;它将显示有关Docker版本和构建信息的输出。如果未安装Docker&#xff0c;将收到有关命令未找到的错误消息。 2. 检查是否安装 docker-…