类与对象(二)

news2024/11/20 8:29:17

类的六个默认构造函数

如果一个类中什么成员都没有,简称为空类。
空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。
默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。

在这里插入图片描述

构造函数

之前我们创建过Date类,通过Init函数初始化Date类创建的对象,但如果每次创建对象时都调用该方法设置信息,未免有点麻烦,那能否在对象创建时,就将信息设置进去呢?
构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,以保证每个数据成员都有 一个合适的初始值,并且在对象整个生命周期内只调用一次

特性

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

  1. 函数名与类名相同。
  2. 无返回值。
  3. 对象实例化时编译器自动调用对应的构造函数。
  4. 构造函数可以重载。

给大家举个例子:

#include<iostream>
using namespace std;

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

public:
	//无参构造函数
	Date() {
		_year = _month = _day = 1;
	}

	//带参构造函数
	Date(int year, int month, int day) {
		_year = year;
		_month = month;
		_day = day;
	}

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

int main()
{
	Date d1;
	Date d2(2, 2, 2);

	d1.Print();
	d2.Print();
	return 0;
}

 // 注意:如果通过无参构造函数创建对象时,对象后面不用跟括号,否则就成了函数声明
 // Date d3():声明了d3函数,该函数无参,返回一个日期类型的对象
 // warning C4930: “Date d3(void)”: 未调用原型函数(是否是有意用变量定义的?)
  1. 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成。
 int main()
 {
 // 将Date类中构造函数屏蔽后,代码可以通过编译,因为编译器生成了一个无参的默认构造函// 将Date类中构造函数放开,代码编译失败,因为一旦显式定义任何构造函数,编译器将不再生成
 // 无参构造函数,放开后报错:error C2512: “Date”: 没有合适的默认构造函数可用
 Date d1;
 return 0;
 }
  1. 关于编译器生成的默认成员函数,很多童鞋会有疑惑:不实现构造函数的情况下,编译器会生成默认的构造函数。但是看起来默认构造函数又没什么用?d对象调用了编译器生成的默认构造函数,但是d对象_year/_month/_day,依旧是随机值。也就说在这里编译器生成的默认构造函数并没有什么用??
    解答:C++把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类型,如:int/char…,自定义类型就是我们使用class/struct/union等自己定义的类型,看看下面的程序,就会发现编译器生成默认的构造函数会对自定类型成员_t调用的它的默认成员函数。

总结就是,构造函数会对自定义类型调用它的默认成员函数,而对内置类型不做处理
而在C++11的规定中,我们实现了可以在声明处写缺省值的功能,如下所示:

class Date{
private:
	int _year=1;//缺省值
	int _month=1;
	int _day=1;
	//这里的缺省值实际上是传递向某处的,只是我们现在还没有学到,后面将为大家讲解为什么这里传缺省值可以初始化
};

总而言之,经过分析,我们发现,绝大多数情况下我们都需要自己写构造函数,且自定义函数如果没有默认构造函数就会报错。因为自定义类型里也是内置类型,即使几个自定义类型套娃,到最后的一个类的成员也会是只有内置类型

  1. 无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。
    注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认构造函数。
    这里我们有三个参数,如果我们只传递其中一个参数或者两个参数,那这里就不是默认构造函数

析构函数

通过前面构造函数的学习,我们知道一个对象是怎么来的,那一个对象又是怎么没呢的?
析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。

特性

析构函数是特殊的成员函数,其特征如下:

  1. 析构函数名是在类名前加上字符 ~。
  2. 无参数无返回值类型。
  3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重载
  4. 对象生命周期结束时,C++编译系统系统自动调用析构函数
//析构函数
	~Date() {
		//这里没有开空间,所以这里的析构函数可以什么都不写,或者使用系统默认生成的析构函数
	}

如果大家想看一下标准的析构函数,可以给大家看一下栈的析构函数

~Stack()
 {
 	if (_array)
 	{
 		free(_array);
 		_array = NULL;
 		_capacity = 0;
 		_size = 0;
 	}
 }
  1. 关于编译器自动生成的析构函数,是否会完成一些事情呢?编译器生成的默认析构函数,对自定类型成员调用它的析构函数。
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()
// 在main方法中根本没有直接创建Time类的对象,为什么最后会调用Time类的析构函数?
// 因为:main方法中创建了Date对象d,而d中包含4个成员变量,其中_year, _month, _day三个是内置类型成员,销毁时不需要资源清理,最后系统直接将其内存回收即可;
//而_t是Time类对象,所以在d销毁时,要将其内部包含的Time类的_t对象销毁,所以要调用Time类的析构函数。
//但是:main函数中不能直接调用Time类的析构函数,实际要释放的是Date类对象,所以编译器会调用Date类的析构函数,而Date没有显式提供,则编译器会给Date类生成一个默认的析构函数,目的是在其内部调用Time类的析构函数,即当Date对象销毁时,要保证其内部每个自定义对象都可以正确销毁
// main函数中并没有直接调用Time类析构函数,而是显式调用编译器为Date类生成的默认析构函数
// 注意:创建哪个类的对象则调用该类的析构函数,销毁那个类的对象则调用该类的析构函数
  1. 如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如Date类;有资源申请时,一定要写,否则会造成资源泄漏,比如Stack类。

需要注意的是,destroy比Init更容易忘记,所以当我们在类里面自动调用析构函数,不容易出错,就比如我们之前在使用栈等需要自己开空间的类型,我们都有可能忘记free掉我们开辟的内存,就拿两个栈实现一个队列来说,我们给大家看一下用C++写和C写的区别

C

typedef int STDataType;
typedef struct Stack {
	STDataType* a;
	int top;
	int capacity;
}Stack;

void StackInit(Stack* ps) {
	assert(ps);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = -1;
}

// 入栈 
void StackPush(Stack* ps, STDataType x) {
	assert(ps);
	if (ps->capacity == ps->top + 1)
	{
		int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		STDataType* node = (STDataType*)realloc(ps->a, newcapacity * sizeof(STDataType));

		if (node == NULL)
		{
			perror("node realloc");
			return;
		}
		ps->a = node;
		ps->capacity = newcapacity;
	}
	ps->top++;
	ps->a[ps->top] = x;
}
// 出栈 
void StackPop(Stack* ps) {
	assert(ps);
	assert(ps->top >= 0);
	ps->top--;
}
// 获取栈顶元素 
STDataType StackTop(Stack* ps) {
	assert(ps);
	assert(ps->top >= 0);
	return ps->a[ps->top];
}
// 获取栈中有效元素个数 
int StackSize(Stack* ps) {
	assert(ps);
	assert(ps->top >= 0);
	return ps->top + 1;
}
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
bool StackEmpty(Stack* ps) {
	assert(ps);
	return ps->top == -1;
}
// 销毁栈 
void StackDestroy(Stack* ps) {
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = -1;
}

void StackPrint(Stack* ps) {
	assert(ps);

	while (ps->top>=0)
	{
		printf("%d ", ps->a[ps->top]);
		StackPop(ps);
	}
	printf("\n");
}

typedef struct {
    Stack pushst;
    Stack popst;
} MyQueue;


MyQueue* myQueueCreate() {
    MyQueue* obj=(MyQueue*)malloc(sizeof(MyQueue));
    StackInit(&obj->pushst);
    StackInit(&obj->popst);
    return obj;
}

void myQueuePush(MyQueue* obj, int x) {
    StackPush(&obj->pushst,x);
}

int myQueuePop(MyQueue* obj) {
    int front=myQueuePeek(obj);
    StackPop(&obj->popst);
    return front;
}

int myQueuePeek(MyQueue* obj) {
    if(StackEmpty(&obj->popst))
    {
        while(!StackEmpty(&obj->pushst))
        {
            StackPush(&obj->popst,StackTop(&obj->pushst));
            StackPop(&obj->pushst);
        }
		}
		return StackTop(&obj->popst);
}

bool myQueueEmpty(MyQueue* obj) {
    return StackEmpty(&obj->popst)&&StackEmpty(&obj->pushst);
}

void myQueueFree(MyQueue* obj) {
    StackDestroy(&obj->pushst);
    StackDestroy(&obj->popst);
    free(obj);
}

C++

class MyQueue {
public:
    MyQueue() {
        // C++里面的栈,其内部容器会自动初始化
    }

    void push(int x) {
        in_Stack.push(x); // 进队列就从in_Stack进
    }

    int pop() {
        if (out_Stack.empty()) {
            while (!in_Stack.empty()) {
                out_Stack.push(in_Stack.top());
                in_Stack.pop();
                // 如果out_Stack是空的,那么就会进入循环,把in_Stack里面的元素全部导入out_Stack
            }
        }

        int x = out_Stack.top(); // 第一个元素就是队头元素
        out_Stack.pop();
        return x;
    }

    int peek() {
        if (out_Stack.empty()) {
            while (!in_Stack.empty()) {
                out_Stack.push(in_Stack.top());
                in_Stack.pop();
            }
        }

        return out_Stack.top(); // 这个跟pop类似
    }

    bool empty() {
        return in_Stack.empty() && out_Stack.empty(); // 两个都不为空就ok
    }

private:
    stack<int> in_Stack;
    stack<int> out_Stack;
};

可以看出,不仅不需要我们来创建Stack,还免去了一堆销毁函数的代码量,谁更简洁一目了然

最后总结一下:
①析构函数并不是所有类都需要,比如Date类就并不需要自己写
②析构函数的调用顺序:局部对象(后定义先析构)-》局部的静态(静态变量生命周期是全局的,所以再main函数结束后才销毁)-》全局对象(后定义先析构)

拷贝构造函数

在现实生活中,可能存在一个与你一样的自己,我们称其为双胞胎
那在创建对象时,可否创建一个与已存在对象一某一样的新对象呢?
拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。

特征

拷贝构造函数也是特殊的成员函数,其特征如下:

  1. 拷贝构造函数是构造函数的一个重载形式。(拷贝构造函数也是构造函数)
  2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用
//拷贝构造函数
Date(const Date& d) {
	_year = d._year;
	_month = d._month;
	_day = d._day;
}

//使用样例
int main()
{
	Date d1(2024, 4, 24);
	Date d2(d1);

	d1.Print();
	d2.Print();
	return 0;
}

上面我们提到了,如果我们直接传值调用,就会引发无限递归,给大家看看:

在这里插入图片描述

这样调用拷贝构造,要先传参,这里传值传参,就会形成一个新的拷贝构造,这样下去,就会无限循环下去,代码崩溃

传值调用和传引用调用
C++规定自定义类型都会调用拷贝构造函数,只有调用完了之后才会再次进入函数体。传参这个过程调用的是拷贝构造,传值传参要调用拷贝构造;引用就不会调用拷贝构造,因为它是变量的别名,直接完成调用

  1. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按(内置类型成员)内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。
    给大家看一下:

在这里插入图片描述

我们注释掉了拷贝构造函数,但是依然成功了,这就是编译器自己生成的拷贝构造函数的作用。
但是浅拷贝会有问题,给大家看一个例子:

在这里插入图片描述

可以看出来,编译器自己生成的拷贝构造函数并不完全是拷贝,而是直接把d2变成了d1,而这并不是我们想看到的,我们只是想要把d1的成员变量都拷贝过来,却直接变成了d1,很明显这是十分错误的。

注意:在编译器生成的默认拷贝构造函数中,内置类型是按照字节方式直接拷贝的,而自定义类型是调用其拷贝构造函数完成拷贝的。系统自己生成的像memcpy一样的,就是把每个字节的数据都拷过去,内置类型完成值拷贝

疑难

1.我们假使删除掉之前写的Date的构造函数,而只保留拷贝构造,那么d1就无法初始化了,因为拷贝构造也是构造,系统不会默认生成。但是我们也可以强制生成,使用Date()=default;(注意要写在类里面)
2.我们刚才用的是浅拷贝,它把指针的值也拷贝过来了,两个对象指向同一个空间,析构的时候对谁置空(地址),那两个都会被置空,同一个空间不能被释放两次。浅拷贝ok,但是需要动态开辟资源的,比如指针这种的都不行。深拷贝:比如这里,就是开一块相同大小的空间,然后让tmp指向自己独立的空间
3.再说用两个栈做一个队列,也就是我们上面写的,构造不用其自己写,析构也不需要,连拷贝构造也不需要,因为Stack就已经把它们全部做好

4.注意:类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请时,则拷贝构造函数是一定要写的,否则就是浅拷贝。

  1. 拷贝构造函数典型调用场景:
    ①使用已存在对象创建新对象
    ②函数参数类型为类类型对象
    ③函数返回值类型为类类型对象
    为了提高程序效率,一般对象传参时,尽量使用引用类型,返回时根据实际场景,能用引用
    尽量使用引用。

运算符重载

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator操作符(参数列表)
注意:

  • 不能通过连接其他符号来创建新的操作符:比如operator@
  • 重载操作符必须有一个类类型参数用于内置类型的运算符,其含义不能改变,例如:内置- 的整型+,不 能改变其含义
  • 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
  • .* :: sizeof ?: . 注意以上5个运算符不能重载。这个经常在笔试选择题中出
    现。

我们写一个公有的operator==出来

在这里插入图片描述

再写一个私有的:
在这里插入图片描述

我们在这里没有给大家展示成员变量的情况,实际上,第一个我们是取消了成员变量的private限制,而改成了public,不然我们无法在其他地方使用d1和d2的成员变量;而第二个,由于我们是在类内部写的,所以可以改成private,这样封装性也更好,不会使权限出问题。并且,这个还有两种写法,大家可以多看看。

大家比较疑问的一个问题应该是为什么传递参数变成了一个,在类外的时候命名参数是两个,实际上,我们在类里面,函数是这个样子的:bool operator==(Date* this, const Date& d2),左操作数是隐含的this指针,指向调用函数的对象

赋值运算符重载

  1. 赋值运算符重载格式
    参数类型:const T&,传递引用可以提高传参效率
    返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
    检测是否自己给自己赋值
    返回*this :要复合连续赋值的含义

首先,我们知道,赋值和拷贝构造是两个意思,给大家写一个例子看看:

Date& operator=(const Date& d) {
	if (this != &d) {
		_year = d._year;
		_month = d._month;
		_day = d._day;//防止自己给自己赋值
	}

	return *this;
}

在这里插入图片描述

d2=d1是赋值吗?不是,因为d2原本是未实例化的对象,而d1则是已经创建过的对象,所以这应该是拷贝构造;而d3=d1是赋值吗?答案很明显是的,两个都是已经创建过的对象,所以是把d1的值赋给d3
而返回*this的原因也很简单,因为我们如果使用void,那么就没有返回值,也就无法做到从右到左的连续赋值;而返回引用的原因,依旧是为了不调用拷贝构造,提高程序效率

给大家看一个表达式,大家可以理解一下是怎么做的:(i=j)=10
意思是j先赋值给i,表达式的返回值是i,所以10再赋值给i

在这里插入图片描述
另外大家需要记住,在类里面声明定义的函数会被认定为内联函数,不需要写inline

2. 赋值运算符只能重载成类的成员函数不能重载成全局函数
原因:赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数

  1. 用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。 注意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。
    注意:如果类中未涉及到资源管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必须要实现

前置++和后置++重载

// 前置++:返回+1之后的结果
 // 注意:this指向的对象函数结束后不会销毁,故以引用方式返回提高效率
Date& operator++() {
	(*this) += 1;
	return *this;
}

// 后置++:
 // 前置++和后置++都是一元运算符,为了让前置++与后置++形成能正确重载
 // C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器
自动传递
 // 注意:后置++是先使用后+1,因此需要返回+1之前的旧值,故需在实现时需要先将this保存一份,然后给this+1
 // 而temp是临时对象,因此只能以值的方式返回,不能返回引用
Date operator++(int) {
	Date tmp(*this);
	*this += 1;
	return tmp;
}

后面我们将从日期类的构建开始讲起,希望大家在看懂这篇文章之后可以继续加油!

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

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

相关文章

2.6设计模式——Flyweight 享元模式(结构型)

意图 运用共享技术有效地支持大量细粒度的对象。 结构 其中 Flyweight描述一个接口&#xff0c;通过这个接口Flyweight可以接受并作用于外部状态。ConcreteFlyweight实现Flyweight接口&#xff0c;并作为内部状态&#xff08;如果有&#xff09;增加存储空间。ConcreteFlywe…

6547网新增信息素养大赛真题及白名单考级真题

打扰大家了&#xff0c;汇报一下最近的更新动态&#xff0c;如果大家有急切需要的白名单真题及试卷留言&#xff0c;我们会优先更新&#xff01; 6547网文库&#xff08;www.6547.cn/wenku&#xff09;&#xff1a;新增信息素养大赛图形化编程真题及Python真题&#xff0c;2024…

STM32单片机C语言模块化编程实战:LED控制详解与示例

一、开发环境 硬件&#xff1a;正点原子探索者 V3 STM32F407 开发板 单片机&#xff1a;STM32F407ZGT6 Keil版本&#xff1a;5.32 STM32CubeMX版本&#xff1a;6.9.2 STM32Cube MCU Packges版本&#xff1a;STM32F4 V1.27.1 之前介绍了很多关于点灯的方法&#xff0c;比如…

不要小看使用说明书,它才是提高成交率的秘诀

在产品推广和销售环节中&#xff0c;许多企业可能忽略了一个非常重要但常被低估的环节——使用说明书的作用。使用说明书&#xff0c;这本附随每件产品的“小书”&#xff0c;往往是用户了解和使用产品的第一步。事实上&#xff0c;一个清晰、详尽、易懂的使用说明书能够显著提…

Blueprints - 鼠标光标判断相关节点

一些以前的学习笔记归档&#xff1b; 俯视角场景中要用鼠标光标判断是否点中物体&#xff0c;或依靠光标引发各种事件&#xff1b; 这些逻辑一般编写在Controller中&#xff0c;Controller类本身就带有相关判断节点&#xff1a; 其中Get Hit Result Under Cursor by Channel是…

OpenFeign微服务调用组件!!!

1.Feign是什么 GitHub - OpenFeign/feign: Feign makes writing java http clients easierFeign makes writing java http clients easier. Contribute to OpenFeign/feign development by creating an account on GitHub.https://github.com/OpenFeign/feignFeign是Netflix开…

第十讲 操作符详解

第十讲 操作符详解 1 操作符的分类 算术操作符&#xff1a; 、- 、* 、/ 、%移位操作符: << >>位操作符: & | ^赋值操作符: 、 、 - 、 * 、 / 、% 、<< 、>> 、& 、| 、^单⽬操作符&#xff1a; &#xff01;、、–、&、*、、-、~ 、…

JavaScript:将input标签中的内容打印到控制台

使用浏览器进行开发时&#xff0c;按F12可以查看网页信息。 目标&#xff1a;实现将input标签中的内容&#xff0c;打印到控制台&#xff08;console&#xff09; HTML页面的关键代码实现&#xff1a; 登录功能&#xff1a; HTML代码&#xff1a; <div class"form-…

个人博客系统的设计与实现

https://download.csdn.net/download/liuhaikang/89222885http://点击下载源码和论文 本 科 毕 业 设 计&#xff08;论文&#xff09; 题 目&#xff1a;个人博客系统的设计与实现 专题题目&#xff1a; 本 科 毕 业 设 计&#xff08;论文&#xff09;任 务 书 题 …

ABTest如何计算最小样本量-工具篇

如果是比例类指标&#xff0c;有一个可以快速计算最小样本量的工具&#xff1a; https://www.evanmiller.org/ab-testing/sample-size.html 计算样本量有4个要输入的参数&#xff1a;①一类错误概率&#xff0c;②二类错误概率 &#xff08;一般是取固定取值&#xff09;&…

设计模式-01 设计模式简介之分类

设计模式-01 设计模式简介之分类 1.分类概述 今天梳理下设计模式的分类学说。按照GoF书籍 《Design Patterns - Elements of Reusable Object-Oriented Software》&#xff08;中文译名&#xff1a;《设计模式 - 可复用的面向对象软件元素》&#xff09; 中所提到的&#xff0c…

牛客NC209 最短无序连续子数组【中等 数组,双指针 C++/Java/Go/PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/d17f4abd1d114617b51e951027be312e 思路 解题思路 1、方法1&#xff0c;排序对比&#xff1a;将数组按升序排序&#xff0c;然后与原数组对照&#xff0c;从哪里开始变化到哪里结束变化的数组就是答案。 2、 方…

初识 Express

目录 1. Express 简介 1.1. 什么是 Express 1.1.1. 概念 1.1.2. 通俗理解 1.1.3. Express 的本质 1.2. 进一步理解 Express 1.2.1. 问题引入1——不使用 Express 能否创建 Web 服务器&#xff1f; 1.2.2. 问题引入2——有了 http 内置模块&#xff0c;为什么还要用 Exp…

【算法刷题 | 贪心算法03】4.25(最大子数组和、买卖股票的最佳时机|| )

文章目录 4.最大子数组和4.1题目4.2解法一&#xff1a;暴力4.2.1暴力思路4.2.2代码实现 4.3解法二&#xff1a;贪心4.3.1贪心思路4.3.2代码实现 5.买卖股票的最佳时机||5.1题目5.2解法&#xff1a;贪心5.2.1贪心思路5.2.2代码实现 4.最大子数组和 4.1题目 给你一个整数数组 n…

【JavaScript】内置对象 ③ ( Math 内置对象 | Math 内置对象简介 | Math 内置对象的使用 )

文章目录 一、Math 内置对象1、Math 内置对象简介2、Math 内置对象的使用 二、代码示例1、代码示例 - Math 内置对象的使用2、代码示例 - 封装 Math 内置对象 一、Math 内置对象 1、Math 内置对象简介 JavaScript 中的 Math 内置对象 是一个 全局对象 , 该对象 提供了 常用的 数…

openEuler-22.03下载、安装

一、下载 下载地址&#xff1a;openEuler下载 | 欧拉系统ISO镜像 | openEuler社区官网 下载版本&#xff1a;openEuler-22.03-LTS-x86_64-dvd.iso 二、安装 配置完后开启虚拟机 设置完后&#xff0c;重启虚拟机 设置桥接模式的网络 cd /etc/sysconfig/network-scripts/ vi if…

Apple公司面试题之Apple-Orange

1. 引言 你幻想过在Apple公司工作吗&#xff1f; 如果心动过&#xff0c;那这个逻辑推理面试题就是给你准备的&#xff01;这是一道有趣的面试题&#xff0c;如下所示&#xff1a; 看到这里的同学&#xff0c;我建议你暂停文章&#xff0c;拿起笔和纸&#xff0c;试一试。准…

图像在神经网络中的预处理与后处理的原理和作用(最详细版本)

1. 问题引出及内容介绍 相信大家在学习与图像任务相关的神经网络时&#xff0c;经常会见到这样一个预处理方式。 self.to_tensor_norm transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]) 具体原理及作用稍后解释&…

用html写一个旋转菜单

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>旋转菜单</title><link relstylesheet href"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css"&…

重发布的原理及其应用

重发布的作用&#xff1a; 在一个网络中&#xff0c;若运行多种路由协议或者相同协议的不同进程&#xff1b;因为协议之间不能直接沟通计算&#xff0c;进程之间也是独立进行转发和运算的&#xff0c;所以&#xff0c;需要使用重发布来实现路由的共享。 条件 &#xff1a; 1&am…