C++类构造函数和析构函数

news2024/10/6 18:36:09

11.3 类构造函数和析构函数

构造函数:是为了在定义对象时自动初始化其成员变量的值。

构造函数没有返回值,也没有被声明为void类型;因此,构造函数没有声明类型。

11.3.1 声明和定义一个构造函数

构造函数原型:在这里有个十分尴尬的情况,构造函数参数名和类的成员变量如果相同将会导致代码混乱,常见的解决方案就是加前缀或后缀:

//构造函数是这样,参数shares和share_val,如果类成员也是这样参数shares和share_val,将会导致混乱
Stock::Stock(const string & company, long shares, double share_val)
{
	...
}
//解决方案
class Stock
{
    private:
    string m_company;
    long m_shares;
    ...

or

class Stock
{
    private:
    string company_;
    long shares_;
    ...
}
// constructor prototype with some default arguments
Stock(const std::string & co, long n = 0, double pr = 0.0);

构造函数定义:

// constructor definition
Stock::Stock(const std::string& co, long n, double pr)
{
	company = co;
	if (n < 0)
	{
		std::cerr << "Number of shares can’t be negative; "
			<< company << " shares set to 0.\n";
		shares = 0;
	}
	else
		shares = n;
	share_val = pr;
	set_tot();
}

11.3.2 使用构造函数

//下面这两种都是可以的嘿嘿
Stock food = Stock("World Cabbage", 250, 1.25);
Stock garment("Furry Mason", 50, 2.5);
//这个是结合了动态内存分配
Stock *pstock = new Stock("Electroshock Games", 18, 19.0);

11.3.3 默认构造函数

默认构造函数时在为提供显式初始值时,用来创建对象的构造函数。

//如果你没有给自定义类定义构造函数,那么系统会自动生成下面这个构造函数,称为默认构造函数
Stock::Stock() { }
//那么对于下面这个变量fluffy_the_cat,它的成员函数没有被初始化
Stock fluffy_the_cat; // uses the default constructor

//如果自定义了构造函数,那么系统不再自动生成默认构造函数了,因此对于上面这句定义,系统将会报错
//因此需要自定义默认构造函数,有两种方式,一是给函数设置默认形参,如下所示:
Stock(const string & co = "Error", int n = 0, double pr = 0.0);
//二是自己定义一个无参数的默认构造函数
Stock::Stock() // default constructor
{
    company = "no name";
    shares = 0;
    share_val = 0.0;
    total_val = 0.0;
}

//以下代码调用默认构造函数
Stock first; // calls default constructor implicitly
Stock first = Stock(); // calls it explicitly
Stock *prelief = new Stock; // calls it implicitly

//以下代码调用其他构造函数
Stock first("Concrete Conglomerate"); // calls constructor

11.3.4 析构函数

析构函数就是在类名前加上。因此Stock类的析构函数为Stock()。另外,与构造函数一样,析构函数也可以没有返回值和声明类型。与构造函数不同的是,析构函数没有参数。

析构函数原型:

~Stock();

析构函数定义:

Stock::~Stock()
{
}

析构函数什么时候调用呢?--------析构函数是自动调用的

如果创建的时静态存储类对象,则其析构函数将在程序结束时自动被调用。如果创建的是自动存储类对象,则其析构函数将在函数执行完代码块时自动被调用。如果对象时通过new创建的,则它将驻留在栈内存或自由存储区中,当使用delete来释放内存时,其析构函数将自动被调用。最后,程序可以创建临时对象来完成特定的功能,在这种情况下,程序将在结束对该对象的使用时自动调用其析构函数。

构造函数有默认构造函数,如果用户没有自定义析构函数,系统将会生成一个默认析构函数。

11.3.5 自定义类举例

11.3.5.1 源文件及运行结果

头文件:

#pragma once
// stock00.h -- Stock class interface
// version 00
#ifndef STOCK00_H_
#define STOCK00_H_
#include <string>
class Stock
{
private:
	std::string company;
	long shares;
	double share_val;
	double total_val;
	void set_tot() { total_val = shares * share_val; }
public:
	// two constructors
	Stock(); // default constructor
	Stock(const std::string& co, long n = 0, double pr = 0.0);
	~Stock(); // noisy destructor
	void buy(long num, double price);
	void sell(long num, double price);
	void update(double price);
	void show();
};
#endif

函数实现文件:

将文件名放在双引号而不是方括号中意味着编译器将在源文件所在的目录中搜索它。

// stock00.cpp -- implementing the Stock class
// version 00
#include <iostream>
#include "stock00.h"

// constructors (verbose versions)
Stock::Stock() // default constructor
{
	std::cout << "Default constructor called\n";
	company = "no name";
	shares = 0;
	share_val = 0.0;
	total_val = 0.0;
}
Stock::Stock(const std::string& co, long n, double pr)
{
	std::cout << "Constructor using " << co << " called\n";
	company = co;
	if (n < 0)
	{
		std::cout << "Number of shares can’t be negative; "
			<< company << " shares set to 0.\n";
		shares = 0;
	}
	else
		shares = n;
	share_val = pr;
	set_tot();
}
// class destructor
Stock::~Stock() // verbose class destructor
{
	std::cout << "Bye, " << company << "!\n";
}
// other methods
void Stock::buy(long num, double price)
{
	if (num < 0)
	{
		std::cout << "Number of shares purchased can’t be negative. "
			<< "Transaction is aborted.\n";
	}
	else
	{
		shares += num;
		share_val = price;
		set_tot();
	}
}
void Stock::sell(long num, double price)
{
	using std::cout;
	if (num < 0)
	{
		cout << "Number of shares sold can’t be negative. "
			<< "Transaction is aborted.\n";
	}
	else if (num > shares)
	{
		cout << "You can’t sell more than you have! "
			<< "Transaction is aborted.\n";
	}
	else
	{
		shares -= num;
		share_val = price;
		set_tot();
	}
}
void Stock::update(double price)
{
	share_val = price;
	set_tot();
}
void Stock::show()
{
	using std::cout;
	using std::ios_base;
	// set format to #.###
	ios_base::fmtflags orig =
		cout.setf(ios_base::fixed, ios_base::floatfield);
	std::streamsize prec = cout.precision(3);
	cout << "Company: " << company
		<< " Shares: " << shares << '\n';
	cout << " Share Price: $" << share_val;
	// set format to #.##
	cout.precision(2);
	cout << " Total Worth: $" << total_val << '\n';
	// restore original format
	cout.setf(orig, ios_base::floatfield);
	cout.precision(prec);
}

main文件:

// usestck0.cpp -- the client program
// compile with stock00.cpp
#include <iostream>
#include "stock00.h"
int main()
{
	{//这个大括号是为了制造一个块,然后这个块呢可以使得在程序结束之前调用析构函数并在窗口显示文字
		//如果没有这个块,那么就不会看到Bye, NanoSmart!和Bye, Nifty Foods!的显示了
		using std::cout;
		cout << "Using constructors to create new objects\n";
		Stock stock1("NanoSmart", 12, 20.0); // syntax 1
		stock1.show();
		Stock stock2 = Stock("Boffo Objects", 2, 2.0); // syntax 2
		stock2.show();
		cout << "Assigning stock1 to stock2:\n";
		stock2 = stock1;//When you assign one object to another of the same class, by default C++ copies the contents of each data member of the source object to the corresponding data member of the target object.
		cout << "Listing stock1 and stock2:\n";
		stock1.show();
		stock2.show();
		cout << "Using a constructor to reset an object\n";
		stock1 = Stock("Nifty Foods", 10, 50.0); // temp object
		cout << "Revised stock1:\n";
		stock1.show();
		cout << "Done\n";
	}
	return 0;
}

运行结果:

Using constructors to create new objects
Constructor using NanoSmart called
Company: NanoSmart Shares: 12
 Share Price: $20.00 Total Worth: $240.00
Constructor using Boffo Objects called
Company: Boffo Objects Shares: 2
 Share Price: $2.000 Total Worth: $4.00
Assigning stock1 to stock2:
Listing stock1 and stock2:
Company: NanoSmart Shares: 12
 Share Price: $20.000 Total Worth: $240.00
Company: NanoSmart Shares: 12
 Share Price: $20.000 Total Worth: $240.00
Using a constructor to reset an object
Constructor using Nifty Foods called
Bye, Nifty Foods!
Revised stock1:
Company: Nifty Foods Shares: 10
 Share Price: $50.000 Total Worth: $500.00
Done
Bye, NanoSmart!
Bye, Nifty Foods!

D:\Prj\C++\Class_Defined\Debug\Class_Defined.exe (进程 4956)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .

11.3.5.2 注意事项

有些编译器可能出现以下结果:

Using constructors to create new objects
Constructor using NanoSmart called
Company: NanoSmart Shares: 12
Share Price: $20.00 Total Worth: $240.00
Constructor using Boffo Objects called
Bye, Boffo Objects! << additional line
Company: Boffo Objects Shares: 2
Share Price: $2.00 Total Worth: $4.00
...

原因是:

对于以下语句C++标准给了两种方式执行:

Stock stock2 = Stock ("Boffo Objects", 2, 2.0);

第一种是下面这样的:

Constructor using Boffo Objects called
Company: Boffo Objects Shares: 2

第二种是生成一个临时变量:调用构造函数来创建一个临时对象,然后将该临时对象复制到stock2中,并丢弃它。如果编译器使用的时这种方式,则将为临时对象调用析构函数,因此生成下面的输出:

Constructor using Boffo Objects called
Bye, Boffo Objects!
Company: Boffo Objects Shares: 2

生成上述输出的编译器可能立刻删除临时对象,但也可能会等一段时间,在这种情况下,析构函数的消息将会过一段时间才显示。
由此得出结论:

如果既可以通过初始化,也可以通过复制来设置对象的值,则应采用初始化方式。通常这种方式的效率更高。

11.3.6 移动语义

11.3.6.1 移动构造函数

对于构造函数的深复制,在某些情况下源数据将被删除而不需要副本,而且涉及到的内存比较大,此时编译器可以将数据的所有权转让给相关的变量,就避免了做大量无用功。

实际文件还留在原来的地方,而只是修改了记录;这种方法称为移动语义。

默认移动构造函数—系统自动生成,如果程序员提供了则使用程序员的版本。

Someclass::Someclass(Someclass &&); // defaulted move constructor
vector<string> vstr_copy1(vstr); // #1
vector<string> vstr_copy2(allcaps(vstr)); // #2

要实现移动语义,需要采取某种方式,让编译器直到什么时候需要复制,什么时候不需要。这就是右值引用发挥作用的地方。可定义两个构造函数。其中一个是常规复制构造函数,它使用const左值引用作为参数,这个引用关联到左值实参,如语句#1中的vstr;另一个是移动构造函数,它使用右值引用作为参数,这个引用关联到右值实参,如语句#2中allcaps(vstr)的返回值。复制构造函数可执行深复制,而移动构造函数只调整记录。在将所有权转移给新对象的过程中,移动构造函数可能修改其实参,这意味着右值引用参数不应是const。

如何实现移动语义:
1.右值引用让编译器知道何时可使用移动语义;
2.编写移动构造函数,使其提供所需的行为。
在这里插入图片描述

11.3.6.2 移动赋值运算符

移动赋值运算符删除目标对象中的原始数据,并将源对象的所有权转让给目标。
移动赋值运算符的参数不能是const引用,因为这个方法修改了源对象。

默认移动赋值运算符—系统自动生成,如果程序员提供了则使用程序员的版本。

Someclass & Someclass::operator=(Someclass &&); // defaulted move assignment

在这里插入图片描述

11.3.6.3 强制移动

使用头文件utility头文件中的std::move()函数将对象的类型强制转换为移动类型。

11.3.6.4 举例

code
useless.h

#pragma once
#ifndef _USELESS_H_
#define _USELESS_H_
#include <utility>
#include <iostream>
// interface
class Useless
{
private:
	int n; // number of elements
	char* pc; // pointer to data
	static int ct; // number of objects
	void ShowObject() const;
public:
	Useless();
	explicit Useless(int k);
	Useless(int k, char ch);
	Useless(const Useless& f); // regular copy constructor
	Useless(Useless && f); // move constructor
	~Useless();
	Useless operator+(const Useless& f)const;
	void ShowData() const;
	Useless& operator=(const Useless& f);// copy assignment
	Useless& operator=(Useless&& f);// move assignment
};
#endif

useless.cpp

#include "useless.h"
using namespace std;

// implementation
int Useless::ct = 0;
Useless::Useless()
{
	++ct;
	n = 0;
	pc = nullptr;
	cout << "default constructor called; number of objects: " << ct << endl;
	ShowObject();
}
Useless::Useless(int k) : n(k)
{
	++ct;
	cout << "int constructor called; number of objects: " << ct << endl;
	pc = new char[n];
	ShowObject();
}
Useless::Useless(int k, char ch) : n(k)
{
	++ct;
	cout << "int, char constructor called; number of objects: " << ct
		<< endl;
	pc = new char[n];
	for (int i = 0; i < n; i++)
		pc[i] = ch;
	ShowObject();
}
Useless::Useless(const Useless& f) : n(f.n)
{
	++ct;
	cout << "copy const called; number of objects: " << ct << endl;
	pc = new char[n];
	for (int i = 0; i < n; i++)
		pc[i] = f.pc[i];
	ShowObject();
}
Useless::Useless(Useless&& f) : n(f.n)
{
	++ct;
	cout << "move constructor called; number of objects: " << ct << endl;
	pc = f.pc; // steal address
	f.pc = nullptr; // give old object nothing in return
	f.n = 0;
	ShowObject();
}
Useless::~Useless()
{
	cout << "destructor called; objects left: " << --ct << endl;
	cout << "deleted object:\n";
	ShowObject();
	delete[] pc;
}
Useless Useless::operator+(const Useless& f)const
{
	cout << "Entering operator+()\n";
	Useless temp = Useless(n + f.n);
	for (int i = 0; i < n; i++)
		temp.pc[i] = pc[i];
	for (int i = n; i < temp.n; i++)
		temp.pc[i] = f.pc[i - n];
	cout << "temp object:\n";
	cout << "Leaving operator+()\n";
	return temp;
}
void Useless::ShowObject() const
{
	cout << "Number of elements: " << n;
	cout << " Data address: " << (void*)pc << endl;
}
void Useless::ShowData() const
{
	if (n == 0)
		cout << "(object empty)";
	else
		for (int i = 0; i < n; i++)
			cout << pc[i];
	cout << endl;
}

Useless& Useless::operator=(const Useless& f) // copy assignment
{
	cout << "Entering operator=()\n";
	if (this == &f)
		return *this;
	delete[] pc;
	n = f.n;
	pc = new char[n];
	for (int i = 0; i < n; i++)
		pc[i] = f.pc[i];
	cout << "Leaving operator=()\n";
	return *this;
}

Useless& Useless::operator=(Useless&& f) // move assignment
{
	cout << "Entering move operator=()\n";
	if (this == &f)
		return *this;
	delete[] pc;
	n = f.n;
	pc = f.pc;
	f.n = 0;
	f.pc = nullptr;
	cout << "Leaving move operator=()\n";
	return *this;
}

main.cpp

/*
Project name :			_36move_semantics
Last modified Date:		2022年5月23日21点48分
Last Version:			V1.0
Descriptions:			移动构造函数
*/
#include <iostream>
#include "useless.h"
using namespace std;

int main()
{
	cout << "one*******************" << endl;
	Useless one(10, 'x');
	cout << "two*******************" << endl;
	Useless two;
	two = one; // calls copy constructor
	cout << "three*******************" << endl;
	Useless three(20, 'o');
	cout << "four*******************" << endl;
	Useless four(one + three); // calls operator+(), move constructor
	cout << "five*******************" << endl;
	Useless five; 
	five = one + four;// calls operator+(), move constructor
	//默认构造,+运算符,移动构造,移动赋值
	cout << "six*******************" << endl;
	Useless six;
	six = std::move(one); // forced move assignment
	//默认构造函数,移动赋值
	cout << "object one: ";
	one.ShowData();
	cout << "object two: ";
	two.ShowData();
	cout << "object three: ";
	three.ShowData();
	cout << "object four: ";
	four.ShowData();
	cout << "object five: ";
	five.ShowData();
	cout << "object six: ";
	six.ShowData();
	return 0;
}

运行结果

one*******************
int, char constructor called; number of objects: 1
Number of elements: 10 Data address: 0000022953D00CE0
two*******************
default constructor called; number of objects: 2
Number of elements: 0 Data address: 0000000000000000
Entering operator=()
Leaving operator=()
three*******************
int, char constructor called; number of objects: 3
Number of elements: 20 Data address: 0000022953D011E0
four*******************
Entering operator+()
int constructor called; number of objects: 4
Number of elements: 30 Data address: 0000022953CFC650
temp object:
Leaving operator+()
move constructor called; number of objects: 5
Number of elements: 30 Data address: 0000022953CFC650
destructor called; objects left: 4
deleted object:
Number of elements: 0 Data address: 0000000000000000
five*******************
default constructor called; number of objects: 5
Number of elements: 0 Data address: 0000000000000000
Entering operator+()
int constructor called; number of objects: 6
Number of elements: 40 Data address: 0000022953CFDCA0
temp object:
Leaving operator+()
move constructor called; number of objects: 7
Number of elements: 40 Data address: 0000022953CFDCA0
destructor called; objects left: 6
deleted object:
Number of elements: 0 Data address: 0000000000000000
Entering move operator=()
Leaving move operator=()
destructor called; objects left: 5
deleted object:
Number of elements: 0 Data address: 0000000000000000
six*******************
default constructor called; number of objects: 6
Number of elements: 0 Data address: 0000000000000000
Entering move operator=()
Leaving move operator=()
object one: (object empty)
object two: xxxxxxxxxx
object three: oooooooooooooooooooo
object four: xxxxxxxxxxoooooooooooooooooooo
object five: xxxxxxxxxxxxxxxxxxxxoooooooooooooooooooo
object six: xxxxxxxxxx
destructor called; objects left: 5
deleted object:
Number of elements: 10 Data address: 0000022953D00CE0
destructor called; objects left: 4
deleted object:
Number of elements: 40 Data address: 0000022953CFDCA0
destructor called; objects left: 3
deleted object:
Number of elements: 30 Data address: 0000022953CFC650
destructor called; objects left: 2
deleted object:
Number of elements: 20 Data address: 0000022953D011E0
destructor called; objects left: 1
deleted object:
Number of elements: 10 Data address: 0000022953D015A0
destructor called; objects left: 0
deleted object:
Number of elements: 0 Data address: 0000000000000000

D:\Prj\_C++Self\_36move_semantics\x64\Debug\_36move_semantics.exe (进程 4060)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .

11.3.7 default关键字

关键字default显式地声明方法为默认版本。

default关键字只能用于6个特殊成员函数(默认构造函数、复制构造函数、复制赋值运算符、析构函数、移动构造函数、移动赋值运算符)。

class Someclass
{
public:
    Someclass(Someclass &&);
    Someclass() = default; // use compiler-generated default constructor
    Someclass(const Someclass &) = default;
    Someclass & operator=(const Someclass &) = default;
    ...
};

11.3.8 delete关键字

关键字delete用于禁止编译器使用特定方法。例如,要禁止复制对象,可禁用复制构造函数和复制赋值运算符。

delete关键字可用于任何成员函数。

class Someclass
{
public:
	Someclass() = default; // use compiler-generated default constructor
	// disable copy constructor and copy assignment operator:
	Someclass(const Someclass&) = delete;
	Someclass& operator=(const Someclass&) = delete;
	// use compiler-generated move constructor and move assignment operator:
	Someclass(Someclass&&) = default;
	Someclass& operator=(Someclass&&) = default;
	Someclass& operator+(const Someclass&) const;
	...
};

要禁止复制,可以将复制构造函数和赋值运算符放在类定义的private部分,但使用delete也能达到这个目的,且更不容易犯错,更容易理解。
如果在启用移动方法同时禁用复制方法,那么将允许移动复制而不允许按值复制。

Someclass one;
Someclass two;
Someclass three(one); // not allowed, one an lvalue
Someclass four(one + two); // allowed, expression is an rvalue

delete的一种应用场景为:禁止特定的转换。

class Someclass
{
public:
	...
		void redo(double);
	...
};
Someclass sc;
sc.redo(5);//OK

class Someclass
{
public:
	...
		void redo(double);
	void redo(int) = delete;
	...
};

Someclass sc;
sc.redo(5);//error---编译错误

11.3.9 委托构造函数

在一个构造函数的定义中使用另一个构造函数,被称为委托。

class Notes {
	int k;
	double x;
	std::string st;
public:
	Notes();
	Notes(int);
	Notes(int, double);
	Notes(int, double, std::string);
};
Notes::Notes(int kk, double xx, std::string stt) : k(kk),
x(xx), st(stt) {/*do stuff*/
}
Notes::Notes() : Notes(0, 0.01, "Oh") {/* do other stuff*/ }
Notes::Notes(int kk) : Notes(kk, 0.01, "Ah") {/* do yet other stuff*/ }
Notes::Notes(int kk, double xx) : Notes(kk, xx, "Uh") {/* ditto*/ }

默认构造函数使用第一个构造函数初始化数据成员并执行函数体,然后再执行自己的函数体。

11.3.10 继承构造函数

让派生类能够继承基类构造函数的机制。让派生类继承基类所有的构造函数,但是派生类自己定义的构造函数将覆盖与之参数相同的基类的构造函数。

class BS
{
	int q;
	double w;
public:
	BS() : q(0), w(0) {}
	BS(int k) : q(k), w(100) {}
	BS(double x) : q(-1), w(x) {}
	B0(int k, double x) : q(k), w(x) {}
	void Show() const { std::cout << q << ", " << w << '\n'; }
};
class DR : public BS
{
	short j;
public:
	using BS::BS;
	DR() : j(-100) {} // DR needs its own default constructor
	DR(double x) : BS(2 * x), j(int(x)) {}
	DR(int i) : j(-2), BS(i, 0.5 * i) {}
	void Show() const { std::cout << j << ", "; BS::Show(); }
};
int main()
{
	DR o1; // use DR()
	DR o2(18.81); // use DR(double) instead of BS(double)
	DR o3(10, 1.8); // use BS(int, double)
	...
}

11.3.11 const成员函数

const Stock land = Stock("Kludgehorn Properties");
land.show();

对于当前C++来说,编译器将拒绝第二行,这是为什么呢?因为show()的代码无法确保调用对象不被修改—调用对象和const一样,不应被修改。C++的解决方法是将const关键字放在函数的括号后面,使之成为const成员函数。

void show() const; // promises not to change invoking object
void stock::show() const // promises not to change invoking object

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

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

相关文章

windows安装配置git和ToriseGit

目录1、下载安装git2、下载安装ToriseGit3、配置ToriseGit4、公司钥生成1、下载安装git 下载地址 安装&#xff1a;所有都按照默认&#xff0c;直接next就行 2、下载安装ToriseGit 下载地址 下图中两个都要下载&#xff0c;第二个是语言包 安装&#xff1a; 1、先安装主程…

C++行为型模式-职责链模式

1.1 基本概念 职责链模式&#xff08;Chain of Responsibility Pattern&#xff09;:避免请求发送者与接收者耦合在一起&#xff0c;让多个对象都有可能接收请求&#xff0c;将这类对象链接成一条链&#xff0c;并沿着这条链传递请求&#xff0c;直到有对象处理它为止。 1.2 …

Neural Collaborative Filtering论文笔记

ABSTRACT 深度神经网络在语音识别、计算机视觉和自然语言处理等方面取得了巨大的成果&#xff0c;但是对于推荐系统尚且缺少。虽然即使有用深度学习作为推荐&#xff0c;但是都是对建模起辅助作用。当涉及到用户和项目之间的交互&#xff0c;都会选择流行的矩阵分解&#xff0…

三、react组件的生命周期

目标 灵活掌握react组件的生命周期以及组件的活动过程。 能够灵活使用react的生命周期 知识点 react的类组件的生命周期分为三个阶段 实例期存在期销毁期 实例期在组件第一次被实例化的时候触发一次&#xff0c;在这个过程中会执行的生命周期函数如下&#xff1a; construct…

2、CKA-简单搭建K8s集群

基础环境&#xff1a; 主机IP资源系统主机名192.168.100.1104核8GCentos8K8s-master192.168.100.1204核8GCentos8K8s-node1192.168.100.1304核8GCentos8K8s-node2 推荐一个小网站&#xff1a;https://labs.play-with-k8s.com/ 其他的废话不多说&#xff0c;直接部署起来先~~ 部…

[附源码]Python计算机毕业设计 校园疫情防控系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

校企合作,人才共育|湖南工程学院第二期万应低代码实训营圆满收官

2022年11月11日&#xff0c;湖南工程学院第二期万应低代码实训营圆满收官&#xff0c;来自湖南工程学院计算机与通信学院&#xff08;人工智能产业学院&#xff09;的47位同学经过为期9天、共计51课时的培训课程&#xff0c;用出色的交付成果顺利结业。湖南工程学院计算机与通信…

最简单的git图解(最基本命令)

git clone: 这个命令用于将远程代码仓库克隆到本地&#xff0c;这是对任何项目进行开发前的第一步。 比如你本地本来并没有某个项目的代码仓库&#xff0c;此时随便找一个文件目录并进入cmd命令窗口&#xff0c;执行命令git clone [remote address]&#xff0c;[remote addres…

春节静态HTML网页作业模板 传统节日文化网站设计作品 静态学生网页设计作业简单网页制作

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

python计算长方形面积 青少年编程电子学会python编程等级考试一级真题解析2022年6月

目录 python计算长方形面积 一、题目要求 1、编程实现 2、输入输出

TCP粘包和拆包

TCP粘包和拆包 &#xff08;1&#xff09;TCP是面向连接的&#xff0c;面向流的&#xff0c;提供可靠性服务。收发两端&#xff08;客户端和服务端&#xff09;都要有一一成对的socket&#xff0c;因此&#xff0c;发送端为了将多个发给接收端的包&#xff0c;更有效的发给对方…

【前端】Vue+Element UI案例:通用后台管理系统-代码总结

文章目录前言项目文件目录apimockServehome.jspermission.jsindex.jsmock.jsuser.jsassertcomponentsCommonAside.vueCommonHeader.vueCommonTags.vuedataechartsDataorder.jsuser.jsvideo.jsmockDatatableData.jsuserData.jsvideoData.jsCountData.jsMenuData.jsTableData.jsT…

389. 找不同(简单不一定知道)

问题描述&#xff1a; 给定两个字符串 s 和 t &#xff0c;它们只包含小写字母。 字符串 t 由字符串 s 随机重排&#xff0c;然后在随机位置添加一个字母。 请找出在 t 中被添加的字母。 示例 &#xff1a; 示例 1&#xff1a; 输入&#xff1a;s "abcd", t …

大学生抗疫逆行者网页作业 感动人物HTML网页代码成品 最美逆行者dreamweaver网页模板 致敬疫情感动人物网页设计制作

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

多维时序 | MATLAB实现ELM极限学习机多维时序预测(股票价格预测)

多维时序 | MATLAB实现ELM极限学习机多维时序预测(股票价格预测) 目录 多维时序 | MATLAB实现ELM极限学习机多维时序预测(股票价格预测)效果一览基本介绍程序设计结果输出参考资料效果一览 基本介绍

MySQL-僵持锁

前言 一个僵持锁&#xff08;deadlocks&#xff09;是指锁处于僵持的状态&#xff0c;持有锁的事务既得不到期望的资源&#xff0c;也不愿意释放其他事务需要的资源&#xff0c;也就是&#xff0c;多个锁相互之间都持有其他锁所需的资源&#xff0c;所有的事务都在等待各自需要…

防止重复下单(redis+数据库唯一索引requestId实现幂等)

文章目录为什么会重复下单如何防止重复下单利用数据库实现幂等利用Redis防重为什么会重复下单 为什么会重复下单&#xff0c;对于订单服务而言&#xff0c;就是接到了多个下单的请求&#xff0c;原因可能有很多&#xff0c;最常见的是这两种&#xff1a; 用户重复提交网络原因…

使用easygui制作app

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 使用easygui制作app [太阳]选择题 对于以下python代码表述错误的一项是? import easygui easygui.msgbox("我是msgbox","msgbox标题") choices["A",…

学生网页设计作业源码(HTML+CSS)——海贼王6页代码质量好

HTML实例网页代码, 本实例适合于初学HTML的同学。该实例里面有设置了css的样式设置&#xff0c;有div的样式格局&#xff0c;这个实例比较全面&#xff0c;有助于同学的学习,本文将介绍如何通过从头开始设计个人网站并将其转换为代码的过程来实践设计。 ⚽精彩专栏推荐&#x1…

【Pytorch with fastai】第 13 章 :卷积神经网络

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…