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);// errorgetchar();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;// errorgetchar();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;// okp4.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不影响
相关文章:

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 <<…...

【Vue3源码学习】— CH2.6 effect.ts:详解
effect.ts:详解 1. 理解activeEffect1.1 定义1.2 通过一个例子来说明这个过程a. 副作用函数的初始化b. 执行副作用函数前c. 访问state.countd. get拦截器中的track调用e. 修改state.count时的set拦截器f. trigger函数中的依赖重新执行 1.3 实战应用1.4 activeEffect…...

C语言:文件操作(一)
目录 前言 1、为什么使用文件 2、什么是文件 2.1 程序文件 2.2 数据文件 2.3 文件名 3、文件的打开和关闭 3.1 文件指针 3.2 文件的打开和关闭 结(一) 前言 本篇文章将介绍C语言的文件操作,在后面的内容讲到:为什么使用文…...
集中进行一系列处理——函数
需要多次执行相同的处理,除了编写循环语句之外,还可以集中起来对它进行定义。 对一系列处理进行定义的做法被称为函数,步骤,子程序。 对函数进行定一后,只需要调用该函数就可以了。如果需要对处理的内容进行修正&…...
git diff
1. 如何将库文件的变化生成到patch中 git diff --binary commit1 commit2 > test.patch 打patch: git apply test.patch 2. 如何消除trailing whitespace 问题 git diff --ignore-space-at-eol commit1 commit2 > test.patch 打patch: git ap…...

新手使用GIT上传本地项目到Github(个人笔记)
亲测下面的文章很有用处。 1. 初次使用git上传代码到github远程仓库 - 知乎 (zhihu.com) 2. 使用Git时出现refusing to merge unrelated histories的解决办法 - 知乎...
结合《人力资源管理系统》的Java基础题
1.编写一个Java方法,接受一个整数数组作为参数,返回该数组中工资高于平均工资的员工数量。假设数组中的每个元素都代表一个员工的工资。 2.设计一个Java方法,接受一个字符串数组和一个关键字作为参数,返回包含该关键字的姓名的员…...
PostgreSQL备份还原数据库
1.切换PostgreSQL bin目录 配置Postgresql环境变量后可以不用切换 pg_dump 、psql都在postgresql bin目录下,所以需要切换到bin目录执行命令 2.备份数据库 方式一 语法 pg_dump -h <ip> -U <pg_username> -p <port> -d <databaseName>…...
实现读写分离与优化查询性能:通过物化视图在MySQL、PostgreSQL和SQL Server中的应用
实现读写分离与优化查询性能:通过物化视图在MySQL、PostgreSQL和SQL Server中的应用 在数据库管理中,读写分离是一种常见的性能优化方法,它通过将读操作和写操作分发到不同的服务器或数据库实例上,来减轻单个数据库的负载&#x…...
pytest中文使用文档----10skip和xfail标记
1. 跳过测试用例的执行 1.1. pytest.mark.skip装饰器1.2. pytest.skip方法1.3. pytest.mark.skipif装饰器1.4. pytest.importorskip方法1.5. 跳过测试类1.6. 跳过测试模块1.7. 跳过指定文件或目录1.8. 总结 2. 标记用例为预期失败的 2.1. 去使能xfail标记 3. 结合pytest.param方…...

【Spring MVC】快速学习使用Spring MVC的注解及三层架构
💓 博客主页:从零开始的-CodeNinja之路 ⏩ 收录文章:【Spring MVC】快速学习使用Spring MVC的注解及三层架构 🎉欢迎大家点赞👍评论📝收藏⭐文章 目录 Spring Web MVC一: 什么是Spring Web MVC࿱…...

Python(乱学)
字典在转化为其他类型时,会出现是否舍弃value的操作,只有在转化为字符串的时候才不会舍弃value 注释的快捷键是ctrl/ 字符串无法与整数,浮点数,等用加号完成拼接 5不入??? 还有一种格式化的方法…...

OpenHarmony实战:轻量级系统之子系统移植概述
OpenHarmony系统功能按照“系统 > 子系统 > 部件”逐级展开,支持根据实际需求裁剪某些非必要的部件,本文以部分子系统、部件为例进行介绍。若想使用OpenHarmony系统的能力,需要对相应子系统进行适配。 OpenHarmony芯片适配常见子系统列…...
Neo4j基础知识
图数据库简介 图数据库是基于数学里图论的思想和算法而实现的高效处理复杂关系网络的新型数据库系统。它善于高效处理大量的、复杂的、互连的、多变的数据。其计算效率远远高于传统的关系型数据库。 在图形数据库当中,每个节点代表一个对象,节点之间的…...

HTTP/1.1 特性(计算机网络)
HTTP/1.1 的优点有哪些? 「简单、灵活和易于扩展、应用广泛和跨平台」 1. 简单 HTTP 基本的报文格式就是 header body,头部信息也是 key-value 简单文本的形式,易于理解。 2. 灵活和易于扩展 HTTP 协议里的各类请求方法、URI/URL、状态码…...

每日一题————P5725 【深基4.习8】求三角形
题目: 题目乍一看非常的简单,属于初学者都会的问题——————————但是实际上呢,有一些小小的坑在里面。 就是三角形的打印。 平常我们在写代码的时候,遇到打印三角形的题,一般简简单单两个for循环搞定 #inclu…...
第三题:时间加法
题目描述 现在时间是 a 点 b 分,请问 t 分钟后,是几点几分? 输入描述 输入的第一行包含一个整数 a。 第二行包含一个整数 b。 第三行包含一个整数 t。 其中,0≤a≤23,0≤b≤59,0≤t, 分钟后还是在当天。 输出描…...
【RAG】内部外挂知识库搭建-本地GPT
大半年的项目告一段落了,现在自己找找感兴趣的东西学习下,看看可不可以搞出个效果不错的local GPT,自研下大模型吧 RAG是什么? 检索增强生成(RAG)是指对大型语言模型输出进行优化,使其能够在生成响应之前引用训练数据来…...
MySQL——锁
全局锁 全局锁是一种数据库锁定机制,它可以锁定整个数据库,阻止其他会话对数据库的读写操作。在MySQL中,全局锁定可以使用FLUSH TABLES WITH READ LOCK命令来实现。执行这个命令后,MySQL将获取一个全局读锁,直到当前会…...
C++(12): std::mutex及其高级变种的使用
1. 简述 在多线程或其他许多场景下,同时对一个变量或一段资源进行读写操作是一个比较常见的过程,保证数据的一致性和防止竞态条件至关重要。 C的标准库中为我们提供了使用的互斥及锁对象,帮助我们实现资源的互斥操作。 2. std::mutex及其衍…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...

ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...

【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...

从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践
作者:吴岐诗,杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言:融合数据湖与数仓的创新之路 在数字金融时代,数据已成为金融机构的核心竞争力。杭银消费金…...
WebRTC从入门到实践 - 零基础教程
WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC? WebRTC(Web Real-Time Communication)是一个支持网页浏览器进行实时语音…...