C++基础-类和对象(下)

news2024/9/27 17:35:02

文章目录

  • 前言
  • 一、构造深入
    • 1.初始化列表
    • 2.隐式类型转换
      • 1.隐式类型转换
      • 2.explicit
    • 3.委托构造
  • 二、类的静态成员
    • 1.静态成员声明
    • 2.静态成员定义
    • 3.静态成员特性
  • 三、重载运算符和类型转化
    • 1.关系及算数运算符重载
    • 2.递增递减运算符重载及如何区分
    • 3.赋值运算符重载
    • 4.重载输入输出运算符
      • 1.重载输入运算符
      • 2.重载输出运算符
    • 5.函数匹配与重载运算符
  • 四、类的其他细节
    • 1.const成员函数
    • 2.内部类
      • 内部类的特性
    • 3.匿名对象
    • 4.拷贝时编译器的优化
    • 5.对封装的进一步认识
  • 总结

前言

对于任何C++的类来说,构造函数都是其中重要的组成部分,我们已经在上篇介绍了类的一些基础知识,这篇我们将继续了解类的一些其他功能。并对之前讲解过的内容(如构造函数)进行一些更加深入的讨论。

一、构造深入

1.初始化列表

有时我们可以忽略数据成员初始化和赋值的差异,但并非总是这样。如果成员是const或者是引用的话,我们必须将其初始化。类似的,当成员属于某种类类型且该类没有定义默认构造函数时,也必须将这个成员进行初始化。

class STU
{
public:
	//错误,my_id和rid必须要被初始化
	STU(int i)
	{
		id = i;//正确
		my_id = i;//错误:不可以给const赋值
		rid = i;//错误:rid没有被初始化
	}
private:
	int id;
	const int my_id;
	int& rid;
};

在这里插入图片描述
我们初始化const或者引用类型的数据成员的唯一机会就是通过构造函数初始值!!!

	STU(int i):id(i),my_id(i),rid(id){}//显示的初始化引用和const成员

上面就是我们的初始化列表。
初始化列表: 以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。
注意:

  1. 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)
  2. 引用成员变量,const成员变量和自定义类型成员(且该类没有默认构造函数时)必须放在初始化列表位置进行初始化
  3. 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。
  4. 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关
class A
{
public:
	A(int i):a(i),b(a){}
	void print()
	{
		cout << "A:" << a << "  B:" << b << endl;
	}
private:
	int b;
	int a;
};
int main()
{
	A a(10);
	a.print();
	return 0;
}

上面代码的结果是什么样的呢?是10,10吗?
在这里插入图片描述
从运行结果可以看出,显然不是上面的10,10。为什么有随机值呢?
根据我们上面的第四条,我们先声明的b,初始列表会按照声明顺序进行赋值,和初始化列表中的先后次序无关,所以还是先对b进行赋值,b的值来自a,此时a为随机值,所以b现在也为随机值,为b赋值后轮到a,此时a的值来自i,所以a是10.

2.隐式类型转换

1.隐式类型转换

在C++中,我们的内置类型存在隐式转换,同样的,我们的类存在这样的隐式转换。如果构造函数只接受一个实参,则它实际上定义了此类型的隐式转换机制。有时我们把这种构造函数称为转换构造函数。

class A
{
public:
	A(int i = 0):_a(i)
	{
		cout << "A()" << endl;
	}
	void print()
	{
		cout << "A:" << _a << endl;
	}
private:
	int _a;
	int _b;
};
int main()
{
	A a1(10);
	// 用一个整形变量给A类对象赋值,实际编译器背后会用100构造一个无名对象,最后用无名对象给a2对象进行赋值
	A a2 = 100;
	a1.print();
	a2.print();
	return 0;
}

在这里插入图片描述
构造函数不仅可以构造与初始化对象,对于单个参数或者除第一个参数无默认值其余均有默认值的构造函数,还具有类型转换的作用。

2.explicit

当我们想要抑制构造函数的类型转换时,我们需要explicit关键字

class A
{
public:
	explicit A(int i = 0) :_a(i)
	{
		cout << "A()" << endl;
	}
	void print()
	{
		cout << "A:" << _a << endl;
	}
private:
	int _a;
	int _b;
};
int main()
{
	A a1(10);
	A a2 = 100;
	a1.print();
	a2.print();
	return 0;
}

在这里插入图片描述
explicit关键字只对一个实参的构造函数有效,需要多个实参的构造函数不能用于执行隐式转换,所以多个实参的构造函数无需指定为explicit,且只能在类内声明构造函数时使用explicit关键字,在类外部定义时不应该重复。
当我们使用explicit关键字声明构造函数时,它将只能以直接初始化的形式使用。而且,编译器将不会在自动转换过程中使用该构造函数。

3.委托构造

在C++11新标准扩展了构造函数初始值的功能,使得我们可以定义所谓的委托构造函数。一个委托构造也有一个成员初始值的列表和一个函数体。
在委托构造函数内,成员初始值列表只有唯一的入口,就是类名本身,和其他成员初始值一样,类名后面紧跟圆括号括起来的参数列表,参数列表必须与类中的另外一个构造函数匹配。

class A
{
public:
	//非委托构造,使用对应的实参进行初始化成员
	A(int a,int b,int c) :_a(a),_b(b),_c(c)
	{
		cout << "A(int a,int b,int c)" << endl;
	}
	//委托构造
	A() : A(0,0,0) 
	{
		cout << "A()" << endl;
	}
	//委托构造
	A(int a) : A(a,0,0) 
	{
		cout << "A(int a)" << endl;
	}
	void print()
	{
		cout << "_a:" << _a << "  _b" << _b << "  _c" << _c << endl;
	}
private:
	int _a;
	int _b;
	int _c;
};
int main()
{
	A a1;
	A a2(10);
	a1.print();
	a2.print();
	return 0;
}

在这里插入图片描述
这里默认构造把它委托给三个参数的构造函数,它无需执行任务,我们从结果可以看出,当三个参数的执行过后才执行默认构造,一个参数的构造函数也它委托给三个参数的构造函数。受委托的构造函数会执行,然后控制权才会还给委托者的函数体。

二、类的静态成员

有时间我们的类需要它的一些成员函数与类本身直接相关,而不是与类的各个对象保持关联,这时间我们就可以把这个类的成员声明为静态的。

1.静态成员声明

声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数。静态成员变量一定要在类外进行初始化。

class A
{
public:
	A();
	static void pid();//静态成员函数
private:
	int _a;
	int _b;
	static int id;//静态成员变量
};
int A::id = 0;//静态成员变量只能在类外进行初始化。

类的静态成员存在于任何对象之外,对象中不包含任何与静态成员有关数据,从上一篇的类的大小我们也可以看到。因此,只能有一个id对象,且它被所有的A对象共享。
类似的,静态成员函数也不可以与任何对象绑定在一起,他们不包含this指针,作为结果,静态成员函数不可以声明为const的。而且我们也不可以在static函数体内使用this指针。

2.静态成员定义

在类的外部定义静态成员时,不能重复static关键字,该关键字只能出现在类内部的声明语句中。
一般来说,我们不能在类的内部初始化静态成员。相反的,必须在类的外部定义和初始化每个静态成员。和其他对象一样,一个静态数据成员只能定义一次。想要确保对象只定义一次,最好的办法是把静态数据成员的定义与其他非内联函数的定义放在同一个文件中。

3.静态成员特性

静态成员特性如下:

  1. 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区。
  2. 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明
  3. 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问
  4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员。
  5. 静态成员也是类的成员,受public、protected、private 访问限定符的限制

三、重载运算符和类型转化

上一章我们已经浅浅的认识了一下重载,这次让我们更加深入的学习重载吧。

1.关系及算数运算符重载

class A
{
public:
	A(int a = 0,int b = 0):_a(a),_b(b){}
	A operator+(const A& a1)//重载加号
	{
		A tmp;
		tmp._a = _a + a1._a;
		tmp._b = _b + a1._b;
		return tmp;
	}
	A& operator+=(const A& a1)//重载加等号
	{
		_a += a1._a;
		_b += a1._b;
		return *this;
	}
	void print()
	{
		cout << "_a:" << _a << "  _b:" << _b << endl;
	}
private:
	int _a;
	int _b;
};
int main()
{
	A a1(10, 20);
	A a2(30, 40);
	cout << "a1:";
	a1.print();
	cout << "a2:";
	a2.print();
	A a3 = a1 + a2;
	a1 += a2;
	cout << "a1:";
	a1.print();
	cout << "a3:";
	a3.print();
}

在这里插入图片描述
问什么调用operator+=来替换operator+更加有效呢?
因为+需要创建一个临时对象,而+=只有一个对象。

class A
{
public:
	A(int a = 0, int b = 0) :_a(a), _b(b) {}
	bool operator<(const A& a1)//重载小于号
	{
		return (_a < a1._a) && (_b < a1._b);
	}
private:
	int _a;
	int _b;
};
int main()
{
	A a1(10, 20);
	A a2(30, 40);
	if (a1 < a2)
	{
		cout << "TRUE" << endl;
	}
	return 0;
}

在这里插入图片描述
这里我们使用的是对象中每一个对象成员均小于另一个对象才返回真。

2.递增递减运算符重载及如何区分

class A
{
public:
	A(int a = 0, int b = 0) :_a(a), _b(b) {}
	A& operator++()//重载前置++
	{
		_a++;
		_b++;
		return *this;
	}
	A& operator++(int)//重载后置++
	{
		A tmp = *this;
		_a++;
		_b++;
		return tmp;
	}
	void print()
	{
		cout << "_a:" << _a << "  _b:" << _b << endl;
	}
private:
	int _a;
	int _b;
};
int main()
{
	A a1(10, 20);
	A a2(30, 40);
	++a1;//前置++
	a1.print();
	A a3 = a2++;
	a3.print();
	return 0;
}

在这里插入图片描述
我们发现后置++多了一个参数,但我们并没有进行传参,编译器是如何知道我们要调用后置的呢?
后置的版本接受一个额外的(不被使用)int型参数,当我们使用后置运算符时,编译器会提供一个值为0的实参。 尽管从语法上来说我们后置函数会使用这个额外的形参,但在实际过程中通常不会这样做。这个形参的唯一作用就是区分前置版本还是后置版本,而不是真的参加运算。
大家可以自己实现一下前置- -和后置- -;

3.赋值运算符重载

class A
{
public:
	A(int a = 0, int b = 0) :_a(a), _b(b) {}
	A& operator=(const A& a1)
	{
		_a = a1._a;
		_b = a1._b;
		return *this;
	}
	void print()
	{
		cout << "_a:" << _a << "  _b:" << _b << endl;
	}
private:
	int _a;
	int _b;
};
int main()
{
	A a1(10, 20);
	A a2;
	a2 = a1;
	a2.print();
	return 0;
}

在这里插入图片描述
这个我们上一篇已经见到过了。需要注意的是:赋值运算符都必须定义为成员函数。

4.重载输入输出运算符

1.重载输入运算符

通常情况下,输出运算符的第一个形参是一个非常量ostream对象的引用。之所以ostream是非常量是因为向流写入内容会改变其状态:而该形参是引用是因为我们无法直接复制一个ostream对象.

class A
{
public:
	A(int a = 0, int b = 0) :_a(a), _b(b) {}
	ostream& operator<<(ostream &os)
	{
		os << "_a:" << _a << "  _b:" << _b << endl;
		return os;
	}
private:
	int _a;
	int _b;
};
int main()
{
	A a1(10, 20);
	//cout << a1;
	a1 << cout;
	return 0;
}

在这里插入图片描述
在这里插入图片描述
我们发现打印的方式和我们正常使用的方式不一样,这又是为什么呢?
因为我们调用类的函数的一个参数都是隐含的this指针,所以我们的调用要我们的类对象在前。
为了与标准库兼容,我们的输入输出运算符必须是普通的非成员函数,而不是类的成员函数。

class A
{
public:
	friend ostream& operator<<(ostream& os, A& a1);
	A(int a = 0, int b = 0) :_a(a), _b(b) {}
private:
	int _a;
	int _b;
};
ostream& operator<<(ostream& os, A& a1)
{
	os << "_a:" << a1._a << "  _b:" << a1._b << endl;
	return os;
}
int main()
{
	A a1(10, 20);
	A a2(20, 40);
	cout << a1 << a2 << endl;
	return 0;
}

在这里插入图片描述
我们要保证返回的类型也为ostream的引用,这样可以做到连续输出。

2.重载输出运算符

class A
{
public:
	friend istream& operator>>(istream& is, A& a1);
	friend ostream& operator<<(ostream& os, A& a1);
	A(int a = 0, int b = 0) :_a(a), _b(b) {}
private:
	int _a;
	int _b;
};
istream& operator>>(istream& is, A& a1)
{
	int a = 0;
	int b = 0;
	is >> a >> b;
	if (is)//检查输入是否成功
	{
		a1._a = a;
		a1._b = b;
	}
	else
	{
		a1 = A();//输入失败,对象被赋予默认状态
	}
	return is;
}
ostream& operator<<(ostream& os, A& a1)
{
	os << "_a:" << a1._a << "  _b:" << a1._b << endl;
	return os;
}
int main()
{
	A a1;
	cin >> a1;
	cout << a1 << endl;
	return 0;
}

在这里插入图片描述
输入运算符必须处理输入可能失败的情况,而输出运算符不需要。当我们的读取操作发生错误时,输入运算符应该负责从错误中恢复。

5.函数匹配与重载运算符

重载运算符也是重载函数。因此,通用的函数匹配规则也同样适用于判断在给定的表达式中到底应该使用内置类型运算符还是重载的运算符。
当我们调用一个命名的函数时,具有该名字的成员函数和非成员函数彼此不会重载,这是因为我们用来调用命名函数的语法形式对于成员函数和非成员函数来说是不同的。当我们通过类类型的对象(或者该对象的指针及引用)进行函数调用时,只考虑该类的成员函数。而当我们在表达式中使用重载的运算符时,无法判断正在使用的是成员函数还是非成员函数,因此二者都应该在考虑的范围内。
表达式中的运算符的候选函数集既应该包括成员函数,也应该包括非成员函数。我们不可以对一个类既提供了转化目标是算数类型的转化,也提供重载的运算符,这样会产生二义性问题。

四、类的其他细节

1.const成员函数

将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。

class A
{
public:
	A(int a = 0, int b = 0) :_a(a), _b(b) {}
	void print() const
	{
		cout << "_a:" << _a << "  _b:" << _b << endl;
	}
private:
	int _a;
	int _b;
};
int main()
{
	A a1;
	return 0;
}

由于我们不想对该对象进行修改,但我们又不可以在形参上面加入const,所以我们把const加在形参列表后面
在这里插入图片描述
编译器会对const进行上述的处理。

2.内部类

如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限。
注意:
内部类就是外部类的友元类,参见友元类的定义,内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。

内部类的特性

内部类的特性如下:

  1. 内部类可以定义在外部类的public、protected、private都是可以的。
  2. 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。
  3. sizeof(外部类)=外部类,和内部类没有任何关系。
class A
{
public:
	class B 
	{
	public:
		void print(const A& a)
		{
			cout << "A::_a:" << a._a << "   A::_b:" << a._b << "   B::id:" << id << endl;
		}
	private:
		int id = 0;
	};
private:
	int _a = 0;
	int _b = 0;
};
int main()
{
	A::B b;
	b.print(A());
	cout <<"A的大小:" << sizeof(A) << endl;
	return 0;
}

在这里插入图片描述

3.匿名对象

class A
{
public:
	A(int a = 0):_a(a)
	{
		cout << "A()" << endl;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
private:
	int _a;
};
int main()
{
	A aa1;
	cout << "到匿名对象了" << endl;
	A();// 我们可以这么定义匿名对象,匿名对象的特点不用取名字
	// 但是他的生命周期只有这一行,我们可以看到下一行他就会自动调用析构函数
	cout << "匿名对象结束了" << endl;
	A aa2(2);
	return 0;
}

在这里插入图片描述
注意:匿名对象的生命周期只有这一行

4.拷贝时编译器的优化

在传参和传返回值的过程中,一般编译器会做一些优化,减少对象的拷贝,下面就让我们看看编译器的优化吧。

class A
{
public:
	A(int a = 0):_a(a)
	{
		cout << "A(int a)" << endl;
	}
	A(const A& aa):_a(aa._a)
	{
		cout << "A(const A& aa)" << endl;
	}
	A& operator=(const A& aa)
	{
		cout << "A& operator=(const A& aa)" << endl;
		if (this != &aa)
		{
			_a = aa._a;
		}
		return *this;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
private:
	int _a;
};
void fun1(A aa){}
A fun2()
{
	A aa;
	return aa;
}
int main()
{
	//传值传参
	A aa1;
	fun1(aa1);
	cout << endl;
	//传值返回
	fun2();
	cout << endl;
	// 隐式类型,连续构造+拷贝构造->优化为直接构造
	fun1(1);
	// 一个表达式中,连续构造+拷贝构造->优化为一个构造
	fun1(A(2));
	cout << endl;
	// 一个表达式中,连续拷贝构造+拷贝构造->优化一个拷贝构造
	A aa2 = fun2();
	cout << endl;
	// 一个表达式中,连续拷贝构造+赋值重载->无法优化
	aa1 = fun2();
	cout << endl;
	return 0;
}

在这里插入图片描述
我们要尽量构造函数和拷贝放进一个句子中,这样可以少量的提升我们的效率。

5.对封装的进一步认识

类是对某一类实体(对象)来进行描述的,描述该对象具有那些属性,那些方法,描述完成后就形成了一种新的自定义类型,才用该自定义类型就可以实例化具体的对象。
在这里插入图片描述

总结

到这里我们的类已经入门了。想要对类进一步了解我们还要学习继承和多态,进一步的学习需要我们熟练的使用我们现在所学的类的内容,所以下一步我们会进入容器的学习。

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

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

相关文章

【基础篇】五、基于SpringBoot来整合SSM的案例(上)

文章目录 0、创建模块1、实体类的快速开发Lombok2、数据层开发&#xff08;CRUD&#xff09;3、分页4、条件查询5、业务层的标准开发6、业务层的快速开发&#xff08;基于MyBatisPlus&#xff09;7、表现层开发 接下来在SpringBoot下&#xff0c;把Spring、SpringMVC、MyBatis整…

项目进度管理(3-3)PERT计划评审技术详解

1 计划评审技术起源 PERT&#xff08;Program Evaluation and Review Technique&#xff0c;项目评估和审查技术&#xff09;的起源可以追溯到20世纪50年代&#xff0c;与美国国防部和美国海军的项目管理有关。 PERT的发展始于20世纪50年代初&#xff0c;当时美国国防部正面临…

ConfigMaps-2

文章目录 主要内容一.Volume 挂载 ConfigMap1.创建一个Pod&#xff0c;起挂载的内容&#xff0c;将来自下面的configmap&#xff1a;代码如下&#xff08;示例&#xff09;: 2.解释 二.环境变量 ConfigMap1.创建一个名为 mysqlpass 且包含 passwordABCabc123 的 configmap&…

第一、二题见贴图第三题 实现求1-100之间的质数?

print("模式A") while True: for i in range (1,7): for j in range(1, 7): if j < i: print(j,end"\t") print() break print() print("模式B") while True: for i in range (6,…

【测开】Java快转Python 学习路径记录

写在前面 工作后需要用python&#xff0c;记录下学习的一些资料和总结&#xff0c;仅供参考&#xff0c;希望对你有帮助。 2023/9/8 (碎碎念&#xff1a;我太懂工作要用时自己却不会的感觉了…心好累&#xff0c;问大家怎么学就说这简单…md记录一下&#xff09; Part.1 对比 …

基于Java汽车服务商城系统 设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

知识图谱(3)关系抽取

信息抽取旨在从大规模非结构化或半结构化的自然语言文本中抽取结构化信息。关系抽取是其中的重要子任务&#xff0c;主要目的是从文本中识别实体并抽取实体之间的语义关系。 比如有下面的文本&#xff1a; International Business Machines Corporation (IBM or the company) …

2019-2021年上市公司润灵ESG评分评级数据

2019-2021年上市公司润灵ESG评分评级数据 1、时间&#xff1a;2019-2021年 2、指标&#xff1a;股票代码、股票简称、评级年份、所属指数名称、GICS行业一级分类、GICS行业一级分类代码、GICS行业二级分类、GICS行业二级分类代码、GICS行业三级分类、GICS行业三级分类代码、E…

【Qt 图形视图框架】QGraphics分析及使用

组成 Qt 图形视图框架分为三部分&#xff1a;场景、视图、图元。 场景对于程序来说&#xff0c;场景是不可见的&#xff0c;是一个抽象的管理图形项的容器。 可以向场景中添加图形项&#xff0c;比如&#xff1a;圆形、矩形、三角形等等 此外&#xff0c;还可以获取场景中的某…

games101 作业2

题目 光栅化一个三角形 1. 创建三角形的 2 维 bounding box。 2. 遍历此 bounding box 内的所有像素&#xff08;使用其整数索引&#xff09;。然后&#xff0c;使用像素中心的屏幕空间坐标来检查中心点是否在三角形内。 3. 如果在内部&#xff0c;则将其位置处的插值深度值 (…

GICv3学习

GICv3学习 参考文档&#xff1a; 《corelink_gic600_generic_interrupt_controller_technical_reference_manual_100336_0106_00_en》 《IHI0069H_gic_architecture_specification》 《ECM0495013B_GIC_Stream_Protocol》 一、GICv3寄存器接口 接口如下图所示&#xff1a…

手搭手入门Mybatis-Plus配置多数据源

https://baomidou.com/ Mybatis-Plus介绍 为简化开发而生 MyBatis-Plus(opens new window)&#xff08;简称 MP&#xff09;是一个 MyBatis (opens new window) 的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。 特性 无…

Python 多线程概述

视频版教程 Python3零基础7天入门实战视频教程 几乎所有的操作系统都支持同时运行多个任务&#xff0c;一个任务通常就是一个程序&#xff0c;每一个运行中的程序就是一个进程。当一个程序运行时&#xff0c;内部可能包含多个顺序执行流&#xff0c;每一个顺序执行流就是一个线…

指针笔试题

目录 指针笔试题 NO1. NO2. NO3. NO4. NO5.✔ NO6. NO7. NO8.✔ 今天接着继续指针练习。&#x1f642;&#x1f642;&#x1f642; 指针笔试题 NO1. //指针的类型 //转化后的类型 //解引用访问根据指针类型访问几个字节 //整型在内存中的存储------小端存储 //*解引…

项目上线部署--》服务器部署流程(二)安装Nginx、Node.js、MySQL

阅读本篇文章前请先阅读项目上线部署--》服务器部署流程&#xff08;一&#xff09; 目录 &#x1f31f;安装Nginx 先登录远程服务器&#xff0c;安装依赖包 下载并解压包 &#x1f31f;安装Node.js 安装nodejs进程管理工具 &#x1f31f;安装MySQL &#x1f31f;写在最…

透过《眼睛的故事》:需求为何成为纪录片的“价值锚点”?

我们正处在一个内容过载、追求流量的时代。 对于观众来说&#xff0c;这是幸运的&#xff0c;也是不幸的。一方面&#xff0c;相比以前能接受到的内容指数级增长&#xff0c;自己的视野无限扩大&#xff0c;但另一方面&#xff0c;“流量思维”下粗制滥制的内容不在少数&#…

一百七十八、ClickHouse——海豚调度执行ClickHouse的.sql文件

一、目的 由于数仓的ADS层是在ClickHouse中&#xff0c;即把Hive中DWS层的结果数据同步到ClickHouse中&#xff0c;因此需要在ClickHouse中建表&#xff0c;于是需要海豚调度执行ClickHouse的.sql文件 二、实施步骤 &#xff08;一&#xff09;第一步&#xff0c;海豚建立Cl…

JavaWeb的基本概念

一、Web基本概念 Web的基本结构&#xff1a; 1.客户端的概述 1.1. 客户端的作用 与用户进行交互&#xff0c;用于接收用户的输入(操作)、展示服务器端的数据以及向服务器传递数据 1.2. 常见的客户端 PC端网页&#xff1a; 移动端&#xff1a; Iot设备&#xff1a; 2…

基于LUT查找表方法的图像gamma校正算法FPGA实现,包括tb测试文件和MATLAB辅助验证

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 将gamma2.2和gamma1/2.2的数据分别导入到matlab进行对比&#xff1a; 2.算法运行软件版本 matlab2022a 3.部分核心程序 timescale 1ns / 1ps //…

MyBatisPlus中使用Mybatis方式操作数据库。

说明 MyBatisPlus中&#xff0c;可以使用 Mybatis 方式操作数据库。在 Mapper.xml 中&#xff0c;编写 SQL 来实现比较复杂的操作。 一般比较复杂的逻辑&#xff0c;需要多表联合查询&#xff0c;比较适合直接写SQL。 MybatisPlus比较适合单表操作。 PS&#xff1a;本示例只…