C++其他语法..

1.运算符重载

之前有一个案例如下所示 其中我们可以通过add方法将两个点组成一个新的点

class Point {
	friend Point add(Point, Point);
	int m_x;
	int m_y;
public:
	Point(int x, int y) : m_x(x), m_y(y) {

	}
	void display() {
		cout << "(" << m_x << ", " << m_y << ")" << endl;
	}
};
Point add(Point p1, Point p2) {
	return Point(p1.m_x + p2.m_x, p1.m_y + p2.m_y);
}
int main() {
	Point p1(10, 20);
	Point p2(20, 30);
	Point p3 = add(p1, p2);
	p3.display();
	getchar();
	return 0;
}

但是有一个想法就是 可不可以直接通过加法运算将两个顶点组成新的点 即Point p3 = p1 + p2
答案是可以的 我们可以通过实现operator+来为加法运算增加新功能
以下案例中 我们通过重载方法operator实现了Point对象的加法运算

class Point {
	friend Point operator+(Point p1, Point p2);
	int m_x;
	int m_y;
public:
	Point(int x, int y) : m_x(x), m_y(y) {

	}
	void display() {
		cout << "(" << m_x << ", " << m_y << ")" << endl;
	}
};
Point operator+(Point p1, Point p2) {
	return Point(p1.m_x + p2.m_x, p1.m_y + p2.m_y);
}
int main() {
	Point p1(10, 20);
	Point p2(20, 30);
	Point p3 = p1 + p2;
	p3.display();
	getchar();
	return 0;
}

其实p1 + p2的本质就是调用了operator+(p1, p2)
在这里插入图片描述
我们再来看一下以下这个案例

class Point {
	friend Point operator+(Point p1, Point p2);
	int m_x;
	int m_y;
public:
	Point(int x, int y) : m_x(x), m_y(y) {

	}
	void display() {
		cout << "(" << m_x << ", " << m_y << ")" << endl;
	}
};
Point operator+(Point p1, Point p2) {
	return Point(p1.m_x + p2.m_x, p1.m_y + p2.m_y);
}
int main() {
	Point p1(10, 20);
	Point p2(20, 30);
	Point p3(30, 40);
	Point p4 = p1 + p2 + p3;
	p4.display();
	getchar();
	return 0;
}

我们应该可以知道p1 + p2 + p3的本质其实就是调用了两次operator+
在这里插入图片描述
我们可以对上述operator+方法进行优化 具体改写成
修改原因:1.对象类型做参数时 可能会产生不必要的中间对象 所以尽量使用引用/指针来避免
2.参数用const修饰可以使得参数接受范围更大 因为他可以接收const和非const参数 而非const形参显然只能接收非const实参
基于以上两点原因 有了以下优化代码

Point operator+(const Point& p1, const Point& p2) {
	return Point(p1.m_x + p2.m_x, p1.m_y + p2.m_y);
}

说到这里 我们应该就可以明白拷贝构造函数形参如此写法的原因了
原因有二:1.如果我们的形参是一个对象类型的话 那么当我们调用拷贝构造函数创建一个新对象时 就会无限次的调用该拷贝构造函数 原因在于将实参赋值给形参就会创建新对象 从而调用拷贝构造函数 调用了之后 又会将实参赋值给形参从而调用构造函数 之后就一直重复这个过程 但当我们将对象类型改成引用类型以后 我们就可以杜绝无限调用的现象
2.如果我们传递的实参是const修饰 那么显然非const形参是无法接收这个实参的 所以必须要将形参设计为const修饰 才能接收更大范围的实参

其实对于运算符重载函数而言 我们还可以进一步优化 将其内置于类内部 变成成员函数 这样做的好处是我们可以不用通过友元函数的声明来实现对类内部私有成员的访问 在类内部的成员函数就可以直接访问类内部的私有成员了

class Point {
	int m_x;
	int m_y;
public:
	Point(int x, int y) : m_x(x), m_y(y){}
	void display() {
		cout << "(" << m_x << ", " << m_y << ")" << endl;
	}
	Point operator+(const Point& p2) {
		return Point(m_x + p2.m_x, m_y + p2.m_y);
	}
};
int main() {
	Point p1(10, 20);
	Point p2(20, 30);
	// 相当于调用了p1对象内部的operator+函数 即p1.operator+(p2)
	Point p3 = p1 + p2;
	p3.display();
	getchar();
	return 0;
}

模仿以上案例 我们可以自己来实现一下减法运算符重载函数 其中p2 - p1的本质就是调用了p2.operator-(p1)

class Point {
	int m_x;
	int m_y;
public:
	Point(int x, int y) : m_x(x), m_y(y){}
	void display() {
		cout << "(" << m_x << ", " << m_y << ")" << endl;
	}
	Point operator+(const Point& p2) {
		return Point(m_x + p2.m_x, m_y + p2.m_y);
	}
	Point operator-(const Point& p2) {
		return Point(m_x - p2.m_x, m_y - p2.m_y);
	}
};
int main() {
	Point p1(10, 20);
	Point p2(20, 30);
	Point p3 = p2 - p1;
	p3.display();
	getchar();
	return 0;
}

但是呢 有一个潜在的问题 我们知道 对一个临时数据赋值是没有任何意义的 因为他马上就要销毁了 而在赋值到销毁的这段过程中完全是发生在当前语句中 所以压根不能被任何人使用
在c++中 允许对一个表达式进行赋值操作的 也允许对对象之间的运算结果进行赋值操作 但是不允许对常量进行赋值操作
表达式中对象之间的运算结果便是一个临时数据(未用一块内存进行储存) 虽然可以对其赋值 但是没有任何意义 所以我们要杜绝这种赋值行为
我们可以将返回值设置成常量 这样表达式的结果就是一个常量 自然而然是不可以对一个常量进行赋值操作的

class Point {
	int m_x;
	int m_y;
public:
	Point(int x, int y) : m_x(x), m_y(y){}
	void display() {
		cout << "(" << m_x << ", " << m_y << ")" << endl;
	}
	const Point operator+(const Point& p2) {
		return Point(m_x + p2.m_x, m_y + p2.m_y);
	}
	const Point operator-(const Point& p2) {
		return Point(m_x - p2.m_x, m_y - p2.m_y);
	}
};
int main() {
	Point p1(10, 20);
	Point p2(20, 30);
	(p1 + p2) = Point(40, 50);// error
	getchar();
	return 0;
}

但是一旦运算符重载函数的返回值修改成了常量 那么之前的三数相加或者三数相减的操作就不被允许了 为什么呢 这是因为const对象只能调用const函数 不能调用非const函数的缘故 所以我们需要将运算符重载函数修改成const修饰的函数

class Point {
	int m_x;
	int m_y;
public:
	Point(int x, int y) : m_x(x), m_y(y){}
	void display() {
		cout << "(" << m_x << ", " << m_y << ")" << endl;
	}
	const Point operator+(const Point& p2) {
		return Point(m_x + p2.m_x, m_y + p2.m_y);
	}
	const Point operator-(const Point& p2) {
		return Point(m_x - p2.m_x, m_y - p2.m_y);
	}
};
int main() {
	Point p1(10, 20);
	Point p2(20, 30);
	Point p3(30, 40);
	Point p4 = p1 + p2 + p3;// error
	getchar();
	return 0;
}
class Point {
	int m_x;
	int m_y;
public:
	Point(int x, int y) : m_x(x), m_y(y){}
	void display() {
		cout << "(" << m_x << ", " << m_y << ")" << endl;
	}
	const Point operator+(const Point& p2) const {
		return Point(m_x + p2.m_x, m_y + p2.m_y);
	}
	const Point operator-(const Point& p2) const {
		return Point(m_x - p2.m_x, m_y - p2.m_y);
	}
};
int main() {
	Point p1(10, 20);
	Point p2(20, 30);
	Point p3(30, 40);
	Point p4 = p1 + p2 + p3;// ok
	p4.display();
	getchar();
	return 0;
}

除了加法和减法运算 我们还可以实现一下+=运算符的重载函数

class Point {
	int m_x;
	int m_y;
public:
	Point(int x, int y) : m_x(x), m_y(y){}
	void display() {
		cout << "(" << m_x << ", " << m_y << ")" << endl;
	}
	const Point operator+(const Point& p2) const {
		return Point(m_x + p2.m_x, m_y + p2.m_y);
	}
	const Point operator-(const Point& p2) const {
		return Point(m_x - p2.m_x, m_y - p2.m_y);
	}
	void operator+=(const Point& p2){
		m_x += p2.m_x;
		m_y += p2.m_y;
	}
};
int main() {
	Point p1(10, 20);
	Point p2(20, 30);
	p1 += p2;
	p1.display();
	getchar();
	return 0;
}

但是a += b这个表达式是可以被赋值的 因为表达式的结果是一块内存 所以p1 += p2是可以进行赋值操作的 我们希望可以有+=重载函数有一个返回值 这样由此创建的表达式就可以进行赋值操作了

class Point {
	int m_x;
	int m_y;
public:
	Point(int x, int y) : m_x(x), m_y(y){}
	void display() {
		cout << "(" << m_x << ", " << m_y << ")" << endl;
	}
	const Point operator+(const Point& p2) const {
		return Point(m_x + p2.m_x, m_y + p2.m_y);
	}
	const Point operator-(const Point& p2) const {
		return Point(m_x - p2.m_x, m_y - p2.m_y);
	}
	Point operator+=(const Point& p2){
		m_x += p2.m_x;
		m_y += p2.m_y;
		return *this;
	}
};
int main() {
	Point p1(10, 20);
	Point p2(20, 30);
	(p1 += p2) = Point(40, 50);
	p1.display();
	getchar();
	return 0;
}

但是 打印的结果不符合我们的预期 因为实际上p1 += p2的结果是一个全新的对象 只不过他拷贝了p1的数据而已 为了防止函数调用完毕局部变量被回收的现象
所以说为了避免中间对象的产生(主要是为了减少内存开销 但是可能会指向一块回收后再次分配的内存)而导致数据的错误 我们需要将返回值改成引用类型的

class Point {
	int m_x;
	int m_y;
public:
	Point(int x, int y) : m_x(x), m_y(y){}
	void display() {
		cout << "(" << m_x << ", " << m_y << ")" << endl;
	}
	const Point operator+(const Point& p2) const {
		return Point(m_x + p2.m_x, m_y + p2.m_y);
	}
	const Point operator-(const Point& p2) const {
		return Point(m_x - p2.m_x, m_y - p2.m_y);
	}
	Point& operator+=(const Point& p2){
		m_x += p2.m_x;
		m_y += p2.m_y;
		return *this;
	}
};
int main() {
	Point p1(10, 20);
	Point p2(20, 30);
	(p1 += p2) = Point(40, 50);
	p1.display();
	getchar();
	return 0;
}

由于+=重载方法中需要修改成员变量 而const函数不能修改 所以+=重载方法是不可以由const修饰的

我们在来看一下==运算符重载函数的实现 但是需要注意的是如果是const对象调用operator ==方法的话 那么该方法只能够是const修饰

class Point {
	int m_x;
	int m_y;
public:
	Point(int x, int y) : m_x(x), m_y(y){}
	void display() {
		cout << "(" << m_x << ", " << m_y << ")" << endl;
	}
	const Point operator+(const Point& p2) const {
		return Point(m_x + p2.m_x, m_y + p2.m_y);
	}
	const Point operator-(const Point& p2) const {
		return Point(m_x - p2.m_x, m_y - p2.m_y);
	}
	Point& operator+=(const Point& p2){
		m_x += p2.m_x;
		m_y += p2.m_y;
		return *this;
	}
	bool operator==(const Point& p2) const {
		return ((m_x == p2.m_x) && (m_y == p2.m_y));
	}
};
int main() {
	Point p1(10, 20);
	Point p2(20, 30);
	cout << (p1 == p2) << endl;
	getchar();
	return 0;
}

我们实现一下!=运算符重载函数 但是需要注意的是如果是const对象调用operator!=方法的话 那么该方法只能够是const修饰

class Point {
	int m_x;
	int m_y;
public:
	Point(int x, int y) : m_x(x), m_y(y){}
	void display() {
		cout << "(" << m_x << ", " << m_y << ")" << endl;
	}
	const Point operator+(const Point& p2) const {
		return Point(m_x + p2.m_x, m_y + p2.m_y);
	}
	const Point operator-(const Point& p2) const {
		return Point(m_x - p2.m_x, m_y - p2.m_y);
	}
	Point& operator+=(const Point& p2){
		m_x += p2.m_x;
		m_y += p2.m_y;
		return *this;
	}
	bool operator==(const Point& p2) const {
		return ((m_x == p2.m_x) && (m_y == p2.m_y));
	}
	bool operator!=(const Point& p2) const {
		return ((m_x != p2.m_x) || (m_y != p2.m_y));
	}
};
int main() {
	Point p1(10, 20);
	Point p2(20, 30);
	cout << (p1 != p2) << endl;
	getchar();
	return 0;
}

我们实现一下负号运算符重载函数 请注意 负号是不会改变操作数的数值的
既然负号不会改变操作数的数值 那么我们就需要返回一个新建的对象
由于返回值构成的表达式可以被赋值 而赋值操作没有任何意义 所以我们需要禁止赋值 所以用const修饰返回值
如果我们接连使用多次负号 那么就会产生const对象调用的问题 const对象只能够调用const函数 所以我们需要用const修饰函数

class Point {
	int m_x;
	int m_y;
public:
	Point(int x, int y) : m_x(x), m_y(y){}
	void display() {
		cout << "(" << m_x << ", " << m_y << ")" << endl;
	}
	const Point operator+(const Point& p2) const {
		return Point(m_x + p2.m_x, m_y + p2.m_y);
	}
	const Point operator-(const Point& p2) const {
		return Point(m_x - p2.m_x, m_y - p2.m_y);
	}
	Point& operator+=(const Point& p2){
		m_x += p2.m_x;
		m_y += p2.m_y;
		return *this;
	}
	bool operator==(const Point& p2) {
		return ((m_x == p2.m_x) && (m_y == p2.m_y));
	}
	bool operator!=(const Point& p2) {
		return ((m_x != p2.m_x) || (m_y != p2.m_y));
	}
	const Point operator-() const {
		return Point(-m_x, -m_y);
	}
};
int main() {
	Point p1(10, 20);
	Point p2(20, 30);
	Point p3 = (-(-p1));
	p1.display();
	p3.display();
	getchar();
	return 0;
}

我们在来实现一下自增运算符重载函数
这得分成两类 一类是前缀自增运算符重载函数 一类则是后缀自增运算符重载函数 这两类在写法上有所区分 前者就是默认的写法 而后者则是基于默认写法的基础上在参数列表中加入int
我们先来讲讲前缀自增运算符重载函数
由于前缀自增表达式可以被赋值 所以需要有返回值
再者 为了防止产生中间对象而导致数据错乱 所以我们需要让返回值变成引用类型

class Point {
	int m_x;
	int m_y;
public:
	Point(int x, int y) : m_x(x), m_y(y){}
	void display() {
		cout << "(" << m_x << ", " << m_y << ")" << endl;
	}
	const Point operator+(const Point& p2) const {
		return Point(m_x + p2.m_x, m_y + p2.m_y);
	}
	const Point operator-(const Point& p2) const {
		return Point(m_x - p2.m_x, m_y - p2.m_y);
	}
	Point& operator+=(const Point& p2){
		m_x += p2.m_x;
		m_y += p2.m_y;
		return *this;
	}
	bool operator==(const Point& p2) {
		return ((m_x == p2.m_x) && (m_y == p2.m_y));
	}
	bool operator!=(const Point& p2) {
		return ((m_x != p2.m_x) || (m_y != p2.m_y));
	}
	const Point operator-() const {
		return Point(-m_x, -m_y);
	}
	Point& operator++() {
		m_x++;
		m_y++;
		return *this;
	}
};
int main() {
	Point p1(10, 20);
	Point p2(20, 30);
	(++p1) = Point(40, 50);
	p1.display();
	getchar();
	return 0;
}

然后再来讲讲后缀自增运算符重载函数
由于后缀自增表达式可以参与到加法运算中 所以需要返回值Point 但是同时也可以进行赋值运算了
但是由于我的预期是对最新的值进行赋值操作 而不是针对旧值 所以说 我们不能进行赋值操作 所以需要用const修饰返回值

class Point {
	int m_x;
	int m_y;
public:
	Point(int x, int y) : m_x(x), m_y(y){}
	void display() {
		cout << "(" << m_x << ", " << m_y << ")" << endl;
	}
	const Point operator+(const Point& p2) const {
		return Point(m_x + p2.m_x, m_y + p2.m_y);
	}
	const Point operator-(const Point& p2) const {
		return Point(m_x - p2.m_x, m_y - p2.m_y);
	}
	Point& operator+=(const Point& p2){
		m_x += p2.m_x;
		m_y += p2.m_y;
		return *this;
	}
	bool operator==(const Point& p2) {
		return ((m_x == p2.m_x) && (m_y == p2.m_y));
	}
	bool operator!=(const Point& p2) {
		return ((m_x != p2.m_x) || (m_y != p2.m_y));
	}
	const Point operator-() const {
		return Point(-m_x, -m_y);
	}
	Point& operator++() {
		m_x++;
		m_y++;
		return *this;
	}
	const Point operator++(int) {
		Point old(m_x, m_y);
		m_x++;
		m_y++;
		return old;
	}
};
int main() {
	Point p1(10, 20);
	Point p2(20, 30);
	Point p3 = p2++ + Point(40, 50);
	p3.display();
	getchar();
	return 0;
}

我们再来实现一下左移运算符重载函数
首先左移运算符重载函数不可以写在类内部 因为这样会导致<<左边必须为对象类型 而真实代码中<<左边必须是cout(cout是一个类对象 是ostream类对象 ) 所以需要将重载方法定义为全局方法 但是我们就需要将该方法声明为友元方法 这样才能够访问类内部的私有成员
再者 重载方法需要返回值 因为<<可以连用 并且<<左边必须是cout对象 所以返回值是ostream类型 为了防止中间对象的产生 所以返回值需要为ostream&引用类型 至于说要不要加上const修饰 通过测试基本类型的cout的赋值操作(比如:cout << 1 = cout) 我们可以知道赋值操作是行不通的 所以我们需要将返回值设置为常量 即用const修饰返回值 而且由于返回值是const的缘故 导致形参中cout也必须是const修饰
我说实话 const只能够修饰成员函数 并不能修饰全局函数(const对象只能调用const成员函数 但是对于全局函数来说 有无const没有任何影响)
并且由于C++内置的cout行为所在的方法中形参cout也是非const修饰 基于这一点 我们都不能把返回值设置为const修饰
至于说 左移运算符重载函数内部要不要写死endl 如果你是想要将endl灵活的布局在cout语句中 那么请不要写死 反之可以写死 而且千万不要有这种想法 就是cout << endl;执行的是我们自定义的这个方法 实际上他执行的是C++内置的行为

class Point {
	friend ostream& operator<<(ostream& cout, const Point& p);
	int m_x;
	int m_y;
public:
	Point(int x, int y) : m_x(x), m_y(y){}
	void display() {
		cout << "(" << m_x << ", " << m_y << ")" << endl;
	}
	const Point operator+(const Point& p2) const {
		return Point(m_x + p2.m_x, m_y + p2.m_y);
	}
	const Point operator-(const Point& p2) const {
		return Point(m_x - p2.m_x, m_y - p2.m_y);
	}
	Point& operator+=(const Point& p2){
		m_x += p2.m_x;
		m_y += p2.m_y;
		return *this;
	}
	bool operator==(const Point& p2) {
		return ((m_x == p2.m_x) && (m_y == p2.m_y));
	}
	bool operator!=(const Point& p2) {
		return ((m_x != p2.m_x) || (m_y != p2.m_y));
	}
	const Point operator-() const {
		return Point(-m_x, -m_y);
	}
	Point& operator++() {
		m_x++;
		m_y++;
		return *this;
	}
	const Point operator++(int) {
		Point old(m_x, m_y);
		m_x++;
		m_y++;
		return old;
	}
};
ostream& operator<<(ostream& cout, const Point& p) {
	cout << "(" << p.m_x << ", " << p.m_y << ")";
	return cout;
}
int main() {
	Point p1(10, 20);
	Point p2(20, 30);
	cout << p1 << p2 << endl;
	getchar();
	return 0;
}

最后再来实现一下右移运算符重载函数 同样的 由于成员函数要求>>左边必须是对象类型 而不是istream类型 所以我们得将其声明为全局函数
接着 由于C++中内置的cin的行为所在的函数的形参cin是非const修饰 所以编译器为了让我们统一格式 所以也要求我们自定义的方法中形参的cin必须不被const所修饰 所以也就要求我们函数的返回值不被const修饰
我们也不能用const修饰全局函数
由于我们键入数据的行为相当于对指定变量进行修改 所以我们不能够将形参中的对象类型用const修饰 因为常量是不可以修改的

class Point {
	friend ostream& operator<<(ostream& cout, const Point& p);
	friend istream& operator>>(istream& cin, Point& p);
	int m_x;
	int m_y;
public:
	Point(int x, int y) : m_x(x), m_y(y){}
	void display() {
		cout << "(" << m_x << ", " << m_y << ")" << endl;
	}
	const Point operator+(const Point& p2) const {
		return Point(m_x + p2.m_x, m_y + p2.m_y);
	}
	const Point operator-(const Point& p2) const {
		return Point(m_x - p2.m_x, m_y - p2.m_y);
	}
	Point& operator+=(const Point& p2){
		m_x += p2.m_x;
		m_y += p2.m_y;
		return *this;
	}
	bool operator==(const Point& p2) {
		return ((m_x == p2.m_x) && (m_y == p2.m_y));
	}
	bool operator!=(const Point& p2) {
		return ((m_x != p2.m_x) || (m_y != p2.m_y));
	}
	const Point operator-() const {
		return Point(-m_x, -m_y);
	}
	Point& operator++() {
		m_x++;
		m_y++;
		return *this;
	}
	const Point operator++(int) {
		Point old(m_x, m_y);
		m_x++;
		m_y++;
		return old;
	}
};
ostream& operator<<(ostream& cout, const Point& p) {
	cout << "(" << p.m_x << ", " << p.m_y << ")";
	return cout;
}
istream& operator>>(istream& cin, Point& p) {
	cin >> p.m_x;
	cin >> p.m_y;
	return cin;
}
int main() {
	Point p1(10, 20);
	Point p2(20, 30);
	cin >> p1 >> p2;
	cout << p1 << p2 << endl;
	getchar();
	return 0;
}

我们在自定义对象类型的相关运算符的重载函数时 优先考虑成员函数 不行在定义为全局函数

那么为什么对于刚才的左移运算符重载函数和右移运算符重载函数 他们的返回值既然都是非const 那理应可以进行赋值操作 为什么反而不行 这是因为在ostream/istream类中 赋值运算符重载函数是一个私有的函数 不可访问
从这个解答 我们也可以得出一个思路:
之前的对象拷贝操作如果没有自定义拷贝构造函数的话 那么就得对所有的成员进行赋值操作 但是如果不想要对所有的成员赋值的话 那么我们也可以通过拷贝构造函数进行部分成员的赋值 但是如果连拷贝构造函数都没有的话 那么我们也可以在类中自定义一个赋值运算符重载函数已完成部分成员的赋值操作

总结一下 对于以上重载函数的书写 有个大致的思路:
首先我们可以将基本类型的解决方法代入到对象类型的程序流程中
接着我们需要判断是否需要返回值 这取决于我们是否需要连用、赋值或者参与运算符等其他操作
接着需要判断一下返回值是否需要设置为引用类型 如果没有引用类型会使得预期出现偏差的话 那么我们就需要将返回值设计为引用类型
接着如果返回值确定为不可赋值的话 那么显然为常量 所以返回值需要用const修饰
然后函数需不需要用const修饰取决于你是否需要通过const对象去调用成员函数 因为对于const对象而言 他只可以调用const修饰的成员函数 但是对于全局函数 有无const不影响

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

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

相关文章

Codigger Desktop:开发者的利器,每个人的好帮手(一)

在当今这个信息化、数字化的时代&#xff0c;开发者们面临着前所未有的挑战和机遇。为了更好地助力开发者们应对这些挑战&#xff0c;抓住机遇&#xff0c;Codigger应运而生。其中Codigger Desktop 是一款基于 Codigger 系统的桌面应用&#xff0c;为用户提供直观易用的操作界面…

LEAP模型的能源环境发展、碳排放建模预测及不确定性分析教程

原文链接&#xff1a;LEAP模型的能源环境发展、碳排放建模预测及不确定性分析教程https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247599754&idx4&sn243c9f8bff355235a7056c2cbb1331fa&chksmfa82076dcdf58e7b871c3369c95ead9ff1d90baa0431318b26b6abd27…

Pytorch for training1——read data/image

blog torch.utils.data.Dataset create dataset with class torch.utils.data.Dataset automaticly import torch from torch.utils.data import Datasetclass MyDataset(Dataset):def __init__(self, data):self.data datadef __getitem__(self, index):# 根据索引获取样本…

关于跑yolov5.6.1项目的一些错误情况的记录

&#xff08;1&#xff09; 错误问题一&#xff1a;TypeError: meshgrid() got multiple values for keyword argument ‘indexing’ 1.1解决方案&#xff1a;点击图片中黄色部分所在位置的文件&#xff0c;删除indexing“ij” (2)错误问题二&#xff1a;AttributeError: ‘F…

是否应该升级到ChatGPT 4.0?深度对比ChatGPT 3.5与4.0的差异

如果只是想简单地体验AI的魅力&#xff0c;感受大模型的独特之处&#xff0c;或是玩一玩文字游戏&#xff0c;那么升级至ChatGPT 4.0可能并非必需。然而&#xff0c;若你期望将AI作为提升工作学习效率的得力助手&#xff0c;那么我强烈建议你升级到ChatGPT 4.0。 如果你不知道…

【Springboot整合系列】SpringBoot整合WebService

目录 Web服务介绍Web服务的两种类型Web服务架构Web服务的主要特点Web服务使用场景Web服务标准和技术 WebService介绍WebService的作用适用场景不适用场景 WebService的原理三个角色相关概念 WebService开发框架代码实现服务端1.引入依赖2.实体类3.业务层接口接口实现类 4.配置类…

活动回顾丨掘金海外,探寻泛娱乐社交APP出海新风口

3月中旬,Flat Ads携手声网、XMP在广州成功举办“泛娱乐社交APP出海新风口——广州站”的主题线下沙龙活动。 多位大咖与泛娱乐社交APP赛道的行业伙伴汇聚一堂。本次活动邀请到Flat Ads 市场VP 王若策、声网娱乐视频产品负责人 陈际陶、XMP资深产品运营专家 屈俊星等多位行业大…

python ---- %r %s格式输出的区别

在python中&#xff0c; % s和 % r是我们常用的格式符&#xff0c;它们的用法基本一致&#xff0c;但作用却不尽相同&#xff0c;下面简要说明一下两者的区别&#xff1a; 1. % s是将对象 / 变量传递到str()方法中&#xff0c;并将其转化为面向用户的可阅读的格式。 2. % r是将…

ARM 寄存器学习:(前言)七种模式\异常源\向量表\异常返回

一、ARM的七种工作模式 Arm微处理器支持7种工作模式&#xff0c;分别为&#xff1a; 1&#xff0e; 用户模式&#xff08;Usr&#xff09; 用于正常执行程序 2&#xff0e; 系统模式&#xff08;sys&#xff09; 运行均有特权的操作系统任务 3&#…

既然有 HTTP 协议,为什么还要有 RPC?(计算机网络)

使用纯裸 TCP 会有什么问题 TCP 是有三个特点&#xff0c;面向连接、可靠、基于字节流。这里我们需要关注的是基于字节流这一点。 字节流可以理解为一个双向的通道里流淌的数据&#xff0c;这个数据其实就是我们常说的二进制数据&#xff0c;简单来说就是一大堆 01 串。纯裸 T…

物联网行业中,我们如何选择数据库?

在当今数字化潮流中&#xff0c;我们面对的不仅是海量数据&#xff0c;更是时间的涟漪。从生产线的传感器到金融市场的交易记录&#xff0c;时间序列数据成为了理解事物演变和趋势的关键。在面对这样庞大而动态的数据流时&#xff0c;我们需要深入了解一种强大的工具——时序数…

比torchvision更强大,从timm库引用预训练模型和本地加载的方法

1&#xff0c;介绍 torchvision是大家最常用的预训练模型来源&#xff0c;但是其包含的预训练模型种类很少&#xff0c;往往并不能满足研究者们的需求。 而timm库提供了一个更强大的替代选项。 利用如下代码查询 import timmprint(len(timm.list_models())) 输出 1032 可…

【C++】 vector <string> 的超详细解析!!!

目录 一、前言 二、 vector <string> 的个人理解和总结 三、vector <string> 的初始化 四、vector <string> 的输入 \ 输出 五、vector <string> 中的注意事项 六、常考面试题 七、共勉 一、前言 在【C】中&#xff0c;vector 是一个动态数组…

游戏开发各岗位的优势和劣势

在这个充满创意和技术的时代&#xff0c;游戏行业成为众多创新人才追求梦想的热土。对于那些准备踏入这个充满挑战与机遇的领域的新人来说&#xff0c;了解游戏开发的各个岗位及其独特性是至关重要的。游戏程序员、美术设计师和游戏策划——这三个核心岗位不仅构成了游戏创造的…

【SpringBoot整合系列】SpirngBoot整合EasyExcel

目录 背景需求发展 EasyExcel官网介绍优势常用注解 SpringBoot整合EaxyExcel1.引入依赖2.实体类定义实体类代码示例注解解释 3.自定义转换器转换器代码示例涉及的枚举类型 4.Excel工具类5.简单导出接口SQL 6.简单导入接口SQL 7.复杂的导出&#xff08;合并行、合并列&#xff0…

Maplesoft Maple 2024(数学科学计算)mac/win

Maplesoft Maple是一款强大的数学计算软件&#xff0c;提供了丰富的功能和工具&#xff0c;用于数学建模、符号计算、数据可视化等领域的数学分析和解决方案。 Mac版软件下载&#xff1a;Maplesoft Maple 2024 for mac激活版 WIn版软件下载&#xff1a;Maplesoft Maple 2024特别…

Kubernetes中pod的概念

pod pod是什么&#xff1a;pod是k8s中基本的构建模块&#xff0c;一个pod可以包含多个和单个容器&#xff0c;包含多个容器时&#xff0c;这些容器总是运行在同一个工作节点上&#xff0c;因为一个pod绝不会跨多个工作节点。 了解pod&#xff1a; pod将容器绑定在一起&#xf…

浅析扩散模型与图像生成【应用篇】(十五)——SDG

15. More Control for Free! Image Synthesis with Semantic Diffusion Guidance 该文提出一种基于语义引导扩散模型的的图像生成算法&#xff0c;SDG&#xff0c;可使用文本或图像作为引导来指引图像的生成&#xff0c;也可以二者同时使用&#xff0c;实现多模态的引导。增加引…

【Redis】Redis的类型及相关操作

一、常用的key操作命令 keys * 查看当前数据库的键值 ttl key 查看还有多少秒过期&#xff0c;-1表示永不过期&#xff0c;-2表示过期 del / unlink key 同样是删除&#xff0c;unlink是非阻塞删除&#xff0c;del则有可能导致阻塞 select dbindex 切换数据库 flushdb 清空…

微服务(基础篇-007-RabbitMQ部署指南)

目录 05-RabbitMQ快速入门--介绍和安装_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1LQ4y127n4?p65&vd_source60a35a11f813c6dff0b76089e5e138cc 1.单机部署 1.1.下载镜像 1.2.安装MQ 2.集群部署 2.1.集群分类 2.2.设置网络 视频地址&#xff1a; 05-Rab…