西安石油大学C++上机实验 上机四 运行时的多态性和抽象类程序设计(2学时)

news/2024/4/25 22:16:39/文章来源:https://blog.csdn.net/shaozheng0503/article/details/130347288

上机四 运行时的多态性和抽象类程序设计

上机目的

1.理解多态性的概念。

2.掌握运行时的多态性概念和设计方法。

3.掌握虚函数的使用方法。

实验目的

理解多态性的概念。

掌握运行时的多态性概念和设计方法。

掌握虚函数的使用方法。

实验内容

P187:6.10,6.11

上机内容(p187 6.11)

编写计算正方体、圆柱体、球体的表面积和体积的类。要求:

(1) 这三个类有一个公共的基类;

(2) 这三个类计算正方体、圆柱体、球体的表面积和体积的成员函数名字相同;

(3) 按照运行时的多态性方法设计一个测试主函数,并进行测试。
正确源码

#include<iostream>
using namespace std;class basic {
public:virtual double superficial_area() = 0;virtual double volume() = 0;~basic(){}
};class cube :public basic
{
private:double length;
public:cube(double a):length(a){}double superficial_area(){return(6 * length * length);}double volume(){return(length * length * length);}~cube(){}
};class cylinder :public basic
{
private:double radius;double high;
public:cylinder(double a, double b):radius(a), high(b){}double superficial_area(){return ((2 * 3.1415 * radius * radius) + (2 * 3.1415 * radius * high));}double volume(){return (3.1415 * radius * radius * high);}~cylinder(){}
};class globe :public basic
{
private:double radius;
public:globe(double a):radius(a){}double superficial_area(){return (4 * 3.1415 * radius * radius);}double volume(){return (((3.1415 * 4) / 3) * radius * radius * radius);}~globe(){}
};int main() {int a;char c, e, f;double b, d, g, h;basic* p;cout << "请选择形状:" << endl;cout << "1.正方形" << endl << "2.圆柱体" << endl << "3.球体" << endl;cout << "-----------------------------------" << endl;while (scanf("%d", &a) != EOF) {switch (a) {case 1:{cout << "请输入边长:";cin >> b;cube cube1(b);p = &cube1;cout << "-----------------------------------" << endl;cout << "请选择操作:" << endl << "a.表面积" << endl << "b.体积" << endl << "c.返回" << endl;while (cin >> c) {if (c == 'a') {cout << "正方体的表面积是:" << p->superficial_area() << endl;}if (c == 'b') {cout << "正方体的体积是:" << p->volume() << endl;}if (c == 'c') {cout << "-----------------------------------" << endl;break;}}break;}case 2:{cout << "请输入半径:";cin >> d;cout << endl;cout << "请输入高:";cin >> h;cylinder cylinder1(d, h);p = &cylinder1;cout << "-----------------------------------" << endl;cout << "请选择操作:" << endl << "a.表面积" << endl << "b.体积" << endl << "c.返回" << endl;while (cin >> e) {if (e == 'a') {cout << "圆柱体的表面积是:" << p->superficial_area() << endl;}if (e == 'b') {cout << "圆柱体的体积是:" << p->volume() << endl;}if (e == 'c') {cout << "-----------------------------------" << endl;break;}}break;}case 3:{cout << "请输入半径:";cin >> g;globe globe1(g);p = &globe1;cout << "-----------------------------------" << endl;cout << endl;cout << "请选择操作:" << endl << "a.表面积" << endl << "b.体积" << endl << "c.返回" << endl;while (cin >> f) {if (f == 'a') {cout << "球体的表面积是:" << p->superficial_area() << endl;}if (f == 'b') {cout << "球体的体积是:" << p->volume() << endl;}if (f == 'c') {cout << "-----------------------------------" << endl;break;}}break;}}}return 0;
}
以下是一个示例实现,满足上述所有要求:#include <iostream>
#include <cmath>using namespace std;// 定义基类Shape
class Shape {
public:// 虚析构函数virtual ~Shape() {}// 计算表面积的成员函数calcAreavirtual double calcArea() = 0;// 计算体积的成员函数calcVolumevirtual double calcVolume() = 0;
};// 定义派生类Cube,继承自Shape
class Cube : public Shape {
private:double sideLength;public:// 构造函数Cube(double sideLength) {this->sideLength = sideLength;}// 计算表面积double calcArea() override {return 6 * sideLength * sideLength;}// 计算体积double calcVolume() override {return sideLength * sideLength * sideLength;}
};// 定义派生类Cylinder,继承自Shape
class Cylinder : public Shape {
private:double radius;double height;public:// 构造函数Cylinder(double radius, double height) {this->radius = radius;this->height = height;}// 计算表面积double calcArea() override {return 2 * M_PI * radius * (radius + height);}// 计算体积double calcVolume() override {return M_PI * radius * radius * height;}
};// 定义派生类Sphere,继承自Shape
class Sphere : public Shape {
private:double radius;public:// 构造函数Sphere(double radius) {this->radius = radius;}// 计算表面积double calcArea() override {return 4 * M_PI * radius * radius;}// 计算体积double calcVolume() override {return (4.0 / 3.0) * M_PI * pow(radius, 3);}
};// 测试主函数,使用指针数组和循环调用基类的成员函数
int main() {Shape* shapes[] = {new Cube(2.0),new Cylinder(1.0, 3.0),new Sphere(1.5)};int numShapes = sizeof(shapes) / sizeof(shapes[0]);for (int i = 0; i < numShapes; ++i) {cout << "Shape " << i+1 << ", Area: " << shapes[i]->calcArea()<< ", Volume: " << shapes[i]->calcVolume() << endl;delete shapes[i];}return 0;
}
在上述代码中,所有形状都是从基类Shape继承而来,并且具有相同名称的calcArea()calcVolume()成员函数。为了支持运行时的多态性(即派生类对象可以赋值给基类指针),这些成员函数均被声明为虚函数。而在测试主函数中,我们创建了一个指针数组,存放了三个不同形状的对象。使用循环遍历每个对象,并分别调用基类的成员函数来计算表面积和体积。最后,为了释放动态分配的内存,我们还需要使用delete来删除每个对象。

实验用例所写的代码

#include<string>
#include<iostream>
using namespace std;
#define pi 3.1415926
class Shap
{
public:
virtual void area()=0;
virtual void volume()=0;
41
};
class Cube:public Shap//正方体
{
private:
float side_length;
public:
Cube(float Side_length):side_length(Side_length){}
void area()
{
cout<<"正方体表面积是:"<<6*pow(side_length,2)<<endl;
}
void volume()
{
cout<<"正方体体积是:"<<pow(side_length,3)<<endl;
}
};
class Cylinder:public Shap//圆柱体
{
private:
float r;
float h;
public:
Cylinder(float H,float R):r(R),h(H){}
void area()
{
cout<<"圆柱体表面积是:"<<2*pi*pow(r,2)+4*pi*r*h<<endl;
}
void volume()
{
cout<<"圆柱体体积是:"<<pi*pow(r,2)*h<<endl;
}
};
class Sphere:public Shap//球体
{
private:
float r;
public:
Sphere(float R):r(R){}
void area()
{
cout<<"球体表面积是:"<<4*pi*pow(r,2)<<endl;
}
void volume()
{
cout<<"球体体积是:"<<4*pi*pow(r,3)/3<<endl;
}
};
#include "stdafx.h"
#include<iostream>
#include<stdlib.h>
#include <stdio.h>
#include "class.h"
using namespace std;
void main(void)
{
Shap *p;
int n;//形状
char op;//操作
float side_length;
float r;
float h;
bool flag=1;
cout<<"请选择形状:"<<endl;cout<<"1:正方体"<<endl;
cout<<"2:圆柱体"<<endl;
cout<<"3:球体"<<endl;
// cin>>n;
loop: cout<<"-------------------------------------"<<endl;
while(cin>>n)
{switch(n){case 1://正方体
44cout<<"请输入边长:";cin>>side_length;p=new Cube(side_length);cout<<"-------------------------------------"<<endl;cout<<"请选择操作:"<<endl;cout<<"a:表面积"<<endl;cout<<"b:体积"<<endl;cout<<"c:返回"<<endl;while(cin>>op){switch(op){case 'a':p->area();break;case 'b':p->volume();break;case 'c':goto loop;default:cerr<<"输入错误!"<<endl;}}break;case 2://圆柱体 cout<<"请输入半径:";cin>>r;cout<<endl;cout<<"请输入高:";cin>>h;p=new Cylinder(r,h);cout<<"-------------------------------------"<<endl;cout<<"请选择操作:"<<endl;cout<<"a:表面积"<<endl;cout<<"b:体积"<<endl;cout<<"c:返回"<<endl;while(cin>>op){switch(op){case 'a': p->area();break;case 'b':p->volume();break;case 'c':goto loop; 
default:cerr<<"输入错误!"<<endl;}}break;case 3://球体 cout<<"请输入半径:";cin>>r;p=new Sphere(r);cout<<"-------------------------------------"<<endl;cout<<endl;cout<<"请选择操作:"<<endl;cout<<"a:表面积"<<endl;cout<<"b:体积"<<endl;cout<<"c:返回"<<endl;while(cin>>op){switch(op){case 'a':p->area();break;case 'b':p->volume();break;case 'c':goto loop; default:cerr<<"输入错误!"<<endl;}}break;}
}
}

p1876.10

程序阅读题

#include <iostream>
using namespace std;
class Base {//定义了一个Base类public:virtual void Set(int b) {//虚函数的使用x = b;}virtual int Get() {return x;}private://定义私有类int x;
};class Derived: public Base {public:void Set(int d) {y = d;}int Get() {return y;}private:int y;
};int main() {Base B_obj;Derived D_obj;Base *p = & B_obj;p->Set(100);cout << "B_obj x=" << p->Get() << endl;p = &D_obj;p->Set(200);cout << "D_obj x=" << p->Get() << endl;p->Base::Set(300);cout << "B_obj x=" << p->Base::Get() << endl;p->Set(p->Get() + 200);cout << "D_obj y=" << p->Get() << endl;}

对这段代码的理解

这段代码是一个简单的继承示例,其中`Base`类作为基类,具有一个虚函数`Set()`和一个虚函数`Get()`,分别用于设置和获取私有成员变量`x`的值。`Derived`类从`Base`派生,并覆盖了`Set()`和`Get()`函数,引入了新的私有成员变量`y`。由于这两个函数在`Base`中被声明为虚函数,则它们在`Derived`中也是虚函数。在主函数中,首先创建了一个`Base`类型的对象`B_obj`和一个`Derived`类型的对象`D_obj`,并使用指向`Base`的指针`p`依次指向这两个对象。接着调用前者的`Set()`函数,并输出其值;然后调用后者的`Set()`函数,并输出其值。随后,又调用了基类中的`Set()`和`Get()`函数,并输出其结果。最后,在调用`p->Set(p->Get() + 200)`时,将使用`Derived`对象的`Set()`函数,为私有成员变量`y`重新赋值,并输出其结果。需要注意的是,在这个例子中,如果想直接修改`Derived`对象的私有成员变量`y`,可以通过`Derived`类型的指针或引用实现。因此:
```
Derived d;
d.Set(100); // 修改 y 的值
```与```
Base* p = &d;
p->Set(100); // 修改 x 的值(Base 类中的私有成员变量)
```是不同的效果,即通过指向基类的指针或引用修改派生类对象的私有成员变量,只能访问到其从基类继承得来的成员变量,不能直接访问派生类独有的成员变量。如果要修改派生类独有成员变量的值,需要使用指向派生类类型的指针或引用。

此外,还需要注意以下几点:

  1. Base中的x成员变量被设置为私有成员,因此只能通过Set()Get()函数进行访问。在Derived类中并没有直接访问Base类的私有成员变量,而是引入了新的私有成员变量y,这样保证了数据的封装性。

  2. Derived类中Set()Get()函数使用了相同的名称,但它们与基类中同名函数不属于重载,而是函数覆盖(override)。在派生类中重新定义同名函数时,使用关键字virtual可以使其变为虚函数,并实现多态特性。当使用指向派生类对象的指针或引用调用这些函数时,将自动根据对象类型选择正确的函数版本。

  3. 在基类和派生类的各个函数中,如果想避免出现隐藏的Bug,应该使用作用域解析运算符(::)来明确指明要使用哪个类的函数或成员变量。比如,在最后一行的代码中,使用了如下语句:p->Set(p->Get() + 200);。由于Derived类中的成员变量和函数都被隐藏了,所以无法直接访问到Derived对象的私有成员变量y。需要使用p->Get()来获取当前对象的值,并利用Set()函数来重新赋值。在这个过程中,使用了作用域解析运算符来明确指明调用的是基类中的Set()Get()函数。

  4. 在这个例子中,将基类的指针或引用指向派生类对象时,使用了向上转型(upcasting)的方式。向上转型发生在从派生类类型到基类类型的隐式转换中,这是一种安全的转换方式。可以将指向派生类的指针或引用赋值给指向基类的指针或引用,从而可以通过基类接口操纵派生类对象。

  5. 调用虚函数时,会依据调用者的实际类型选择正确的函数版本,即使用后期绑定(late binding)技术。在这个例子中,当p指向基类对象B_obj时,调用的是基类的Set()Get()函数,输出了其私有成员变量x的值;当p指向派生类对象D_obj时,调用的是派生类的Set()Get()函数,输出了其私有成员变量y的值。

  6. 在最后一句代码中使用了链式操作语法:先调用p->Get()获取当前值,再将其加上200,并作为参数传递给p->Set()函数进行修改。需要注意的是,由于Set()函数没有返回值,因此不能在一个语句中同时对其进行两次调用。如果想避免出错,可以分别对其进行多条语句的连续调用,或者将操作和输出分开进行。

总之,这个例子展示了基类和派生类继承关系中的一些基本语法和概念。在实际编程中,应该合理运用继承、多态等特性,遵循良好的设计原则和编码规范,以提高代码质量和可维护性。
除了基类和派生类之间的继承关系,C++还支持多重继承、虚继承、抽象类等高级特性。下面简单介绍一下这些概念:

  1. 多重继承:一个派生类可以同时继承多个基类。该派生类将具有所有基类的成员和方法,并按照声明的顺序排列。如果多个基类具有相同的函数或成员变量,衍生类必须使用作用域解析运算符指定访问哪个基类的成员。

  2. 虚继承:当一个派生类通过多层继承直接或间接地继承自同一基类时,可能会出现菱形继承的问题。为了避免这种情况,C++提供了虚继承的机制,使得派生类中只有一个共享基类的实例。

  3. 抽象类:在C++中,抽象类通常是指包含纯虚函数(即没有实现的虚函数)的类。抽象类不能被实例化,只能被用作基类来派生新的类。

除此之外,C++还支持运算符重载、类型转换、模板等高级特性,这些功能可以充分发挥C++语言的优势,提高开发效率和代码质量。
在实际应用中,面向对象的编程思想可以帮助我们更好地组织程序结构,降低代码的复杂度和耦合度,提高代码的可扩展性和可重用性。下面列举一些使用面向对象编程思想的例子:

  1. 游戏开发:游戏中的各种角色、场景、物品等都可以抽象成对象,通过继承和多态来实现不同类别之间的关系。

  2. GUI界面编程:GUI控件是很常见的面向对象应用,例如按钮、文本框、菜单栏等都可以设计为独立的类,然后利用继承和虚函数来实现其共性和特性。

  3. 数据库管理系统编程:数据库里的表、字段、记录等也可以用对象来表示,便于进行封装、抽象和组合。

  4. 设计模式应用:设计模式是固定模式化的解决问题的方案,在某些复杂场景中尤其有用。例如工厂模式、单例模式、观察者模式等都是以对象为基础思想的典型例子。

总之,在C++语言中,面向对象编程思想得到广泛应用,对软件设计与开发有着重要的贡献。但同时也需要注意遵循良好的设计、规范和命名等规则,才能使程序结构更清晰、简洁、易于理解和维护。

思考题

虚函数的运行机制是如何实现的,静态联编和动态联编有何区别?

虚函数是实现多态的关键机制,在C++中,当一个基类指针或引用调用虚函数时,将自动进行后期绑定(late binding)或动态绑定(dynamic binding)动作,即在运行时根据实际对象类型动态解析调用哪个版本的虚函数。

那么虚函数的运行机制是如何实现的呢?在编译阶段,编译器会为每个包含虚函数的类生成一张虚函数表(vtable),其中保存了该类所有虚函数的地址。在运行阶段,通过访问对象的虚函数表中对应的位置,确定调用哪一个具体的虚函数。

静态联编和动态联编有什么区别呢?静态联编也称为早期绑定(early binding),是在编译阶段进行的函数调用绑定,即根据函数名和参数类型来识别调用哪个函数。这种绑定方式在效率上比较高,但不支持多态。

动态联编也称为后期绑定(late binding),则是在运行时进行的函数调用绑定,即根据实际对象类型确定调用哪个函数。这种绑定方式可以支持多态,使得程序更加灵活。但由于需要在运行时动态解析调用,因此效率相对较低。

在C++中,默认情况下通过基类指针或引用进行函数调用时,是采用动态联编的方式。如果想要使用静态联编,需使用限定作用域运算符::(双冒号)来明确指明要调用的函数版本。

总之,虚函数实现了多态和动态绑定的特性,为C++语言提供了强大的面向对象能力。掌握虚函数的运行机制和区别可以更好地理解和应用这一特性。

除了虚函数,C++还提供了纯虚函数(pure virtual function)和抽象类(abstract class)来实现接口和多态。

纯虚函数是指没有函数体的虚函数,其声明形式为virtual type func() = 0;,其中0表示没有函数体。纯虚函数不能被直接调用,只能被子类重载实现。如果一个类包含纯虚函数,那么该类就成为抽象类,无法实例化。抽象类的作用是为了定义公共接口,用于派生新的类。

例如,下面的Animal类中定义了一个纯虚函数eat(),并且因此成为了一个抽象类:

class Animal{public:virtual void eat() = 0;
};

类似地,我们可以创建如下的Dog、Cat子类,并分别对eat()纯虚函数进行重载:

class Dog : public Animal{public:void eat(){cout << "狗吃骨头" << endl;}
};class Cat : public Animal{public:void eat(){cout << "猫吃鱼" << endl;}
};

这样,我们就可以通过基类指针或引用来调用子类对象的eat()方法,并实现多态效果:

int main(){Animal *animal1 = new Dog();animal1->eat();  // 输出:“狗吃骨头”Animal *animal2 = new Cat();animal2->eat();  // 输出:“猫吃鱼”delete animal1;delete animal2;return 0;
}

总之,C++中的纯虚函数和抽象类为接口和多态的实现提供了重要支持,使得程序设计更加灵活和可扩展。在实际应用中,我们可以根据需要定义自己的接口和抽象类,以达到规范化、复用性和扩展性的目的。

除了虚函数和纯虚函数之外,C++中还有虚析构函数和多重继承等特性。

虚析构函数的作用是帮助确保在通过基类指针或引用销毁对象时能够正确调用子类析构函数。如果基类析构函数不是虚函数,那么当通过基类指针或引用销毁对象时,只会调用该对象的基类部分的析构函数。而如果基类析构函数是虚函数,那么当销毁子类对象时,会先调用子类的析构函数,然后再调用父类的析构函数。因此,在设计需要通过基类指针或引用销毁对象的程序时,应该将基类的析构函数定义为虚函数。

例如,下面是一个包含虚析构函数的基类Shape,以及派生类Rectangle和Triangle的定义:

class Shape{public:virtual ~Shape(){}
};class Rectangle : public Shape{public:~Rectangle(){cout << "销毁矩形" << endl;}
};class Triangle : public Shape{public:~Triangle(){cout << "销毁三角形" << endl;}
};

在主函数中,我们可以使用基类指针来指向不同的子类对象,并尝试销毁这些对象:

int main(){Shape *shape1 = new Rectangle();Shape *shape2 = new Triangle();delete shape1;  // 输出:“销毁矩形”delete shape2;  // 输出:“销毁三角形”return 0;
}

多重继承是指一个派生类可以同时继承自两个或以上的基类。由于多重继承可能导致命名冲突和二义性等问题,在使用时需要特别注意设计。

例如,假设我们有形状Shape、颜色Color和图案Pattern三个基类,现在需要定义一个具有形状、颜色和图案属性的新类Graphic。那么我们可以像下面这样使用多重继承:

class Color{public:void setColor(string c){color = c;}string getColor() const{return color;}private:string color;
};class Pattern{public:void setPattern(string p){pattern = p;}string getPattern() const{return pattern;}private:string pattern;
};class Shape{public:virtual double area() const = 0;virtual void print() const = 0;
};class Graphic : public Shape, public Color, public Pattern{public:void print() const{cout << "形状:" << endl;Shape::print();cout << "颜色:" << getColor() << endl;cout << "图案:" << getPattern() << endl;}
};

在Graphic类中,我们既继承了Shape的area()和print()接口,又继承了Color和Pattern的属性。在print()方法中,我们还可以通过getColor()和getPattern()方法获取对象的颜色和图案等属性。

总之,C++中的虚析构函数和多重继承为程序设计提供了更多的灵活性和可扩展性。虚析构函数可以确保通过基类指针或引用销毁对象时能够正确调用子类析构函数;多重继承可以让派生类同时继承多个基类的接口和属性。在使用时,需要特别注意继承顺序、二义性和其他相关问题。

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

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

相关文章

搜索引擎找外贸客户

说起搜索引擎&#xff0c;我们每个人都不陌生&#xff0c;也许第一时间就能想到平日经常使用的“百度一下”和凭借强大算法及丰富功能占据近85%市场份额的谷歌搜索&#xff08;Statista 2023年1月数据&#xff09;这些耳熟能详的搜索引擎。对于外贸人而言搜索引擎也是非常实用的…

一文谈谈文心一言对比ChatGPT4.0的差距

对于想体验文心一言的朋友&#xff0c;可以进行申请尝试&#xff0c;快速入口 如果想体验ChatGPT的朋友&#xff0c;可以自行fq注册&#xff1b;但是由于现在限制注册并且不稳定&#xff0c;对于不会用梯子不想注册的朋友可以使用这个进行访问&#xff0c;快速入口 关于ChatG…

PMP证书备考攻略+PMP知识点汇总

一&#xff0c;考PMP好处多 1.能力提升 大型项目&#xff0c;领导专业团队 2.升职加薪 晋升管理岗&#xff0c;优先升职加薪 3.招投标加分 具有PMP证书&#xff0c;企业招标有加分 4.转型利器 助力转型&#xff0c;拓宽职业发展 5.公司支持 企业鼓励学习&#xff0c;报销费用 6…

C++模板使用

感谢你的阅读&#xff01;&#xff01;&#xff01; 目录 感谢你的阅读&#xff01;&#xff01;&#xff01; 举个例子&#xff1a; template 有什么意义为什么要用模板 与typedef的区别 使用方法 模板&#xff1a;隐式实例化与显示实例化 和非模板函数以及多个模板类…

气传导耳机和骨传导耳机的区别是啥?气传导耳机有哪些优缺点?

本文主要讲解一下气传导耳机和骨传导耳机的区别、气传导耳机的优缺点&#xff0c;并推荐一些目前主流的气传导耳机款式&#xff0c;大家可以根据自身需求&#xff0c;选择自己感兴趣的部分观看。 气传导耳机和骨传导耳机不同点&#xff1a; 气传导耳机和骨传导耳机最大且最根…

什么是 MVVM?MVVM和 MVC 有什么区别?什么又是 MVP ?

目录标题 一、什么是MVVM&#xff1f;二、MVC是什么&#xff1f;三、MVVM和MVC的区别&#xff1f;四、什么是MVP&#xff1f; 一、什么是MVVM&#xff1f; MVVM是 Model-View-ViewModel的缩写&#xff0c;即模型-视图-视图模型。MVVM 是一种设计思想。 模型&#xff08;Model…

windows安装sqli-labs靶场,两种方式

1、安装phpstudy 官网打不开了&#xff0c;下载地址在这儿https://download.csdn.net/download/weixin_59679023/87711536 双击安装 点自定义安装&#xff0c;选择安装目录&#xff0c;注意目录不要有空格和中文 安装完成启动红框内的两个服务 2、安装sqli靶场 这个包支持ph…

信息收集(三)端口和目录信息收集

信息收集&#xff08;一&#xff09;域名信息收集 信息收集&#xff08;二&#xff09;IP信息收集 端口是什么 "端口"是英文port的意译&#xff0c;可以认为是设备与外界通讯交流的出口。端口可分为虚拟端口和物理端口&#xff0c;其中虚拟端口指计算机内部或交换机…

关于package.json中版本锁定的方法和问题解决

前置知识&#xff1a;先了解一下package.json和package-lock.json的关系和区别&#xff0c;请看这篇文章 然后我们来说一下改怎么锁定版本&#xff1f; 首先肯定是要把package.json中的 ^ 这个符号去掉&#xff0c;但是如果你只去掉package.json中的 ^那就太天真了&#xff0…

必应,百度,神马头条,搜狗专用站长seo推送工具大全

软件介绍&#xff1a; 百度开始打击滥用api问题&#xff0c;针对这个问题已经开发了拟人推送系列功能&#xff0c;放心使用。 五合一高效推送软件&#xff0c;目前支持百度&#xff0c;神马&#xff0c;必应&#xff0c;搜狗&#xff0c;头条&#xff0c;谷歌六大搜索引擎同步…

优秀简历的HR视角:怎样打造一份称心如意的简历?

简历的排版应该简洁工整&#xff0c;注重细节。需要注意对齐和标点符号的使用&#xff0c;因为在排版上的细节需要下很大功夫。除此之外&#xff0c;下面重点讲述几点简历内容需要注意的地方。 要点1&#xff1a;不相关的不要写。 尤其是与应聘岗位毫不相关的实习经历&#x…

服务提供者 Eureka + 服务消费者(Rest + Ribbon)实战

1、Ribbon背景介绍 Ribbon是Netflix发布的开源项目&#xff0c;主要功能是提供客户端的软件负载均衡算法&#xff0c;将Netflix的中间层服务连接在一起。Ribbon客户端组件提供一系列完善的配置项如连接超时&#xff0c;重试等。简单来说&#xff0c;就是在配置文件中列出Load B…

【手把手做ROS2机器人系统开发二】熟悉ROS2基本命令

【手把手做ROS2机器人系统开发二】熟悉ROS2基本命令 一、上讲回顾 在上一讲开发环境搭建中&#xff0c;我们讲解了如何搭建Ubuntu系统环境和ROS2开发运行环境。 1.Ubuntu系统安装 2.ROS2系统环境安装 二、ROS2核心命令讲解 1、daemon-各种守护进程相关的子命令 查看帮助&am…

【计算机网络】网络命令的使用

文章目录 一、实验目的二、实验工具三、实验要求四、实验过程01 ping 命令的使用应用1&#xff1a;验证本地计算机上是否正确安装了 TCP/IP 协议应用2&#xff1a;测试某个目的主机可达性应用3&#xff1a;键入 ping&#xff0c;查看 ping 的其他参数含义 02 netstat 命令的典型…

可能是最强的Python可视化神器,建议一试

数据分析离不开数据可视化&#xff0c;我们最常用的就是Pandas&#xff0c;Matplotlib&#xff0c;Pyecharts当然还有Tableau&#xff0c;看到一篇文章介绍Plotly制图后我也跃跃欲试&#xff0c;查看了相关资料开始尝试用它制图。 Plotly Plotly是一款用来做数据分析和可视化的…

关于GeoServer发布的wfs服务的精度问题

本周基于arcgis/core组件&#xff0c;利用arcgis api for js 4.22版本加载GeoServer发布的同一数据源的wms和wfs服务&#xff0c;出现了偏移的问题。 分析&#xff1a;同一数据源不同的访问方式&#xff0c;出现了偏移&#xff0c;这是很严重的问题。初步判断为js api加载方式的…

HTB-SecNotes

HTB-SecNotes 信息收集8808端口80端口通过CSRF获取通过二次注入 立足tyler -> administrator 信息收集 8808端口 Windows IIS 10.0 可以从官方文档查看10.0版本可能的操作系统。 80端口 通过CSRF获取 目录扫描发现需要登陆后继续进一步操作啊。 对其进行简单的SQL注入测…

Ubuntu20.04安装CUDA和CUDNN

CUDA是GPU深度学习的运行库&#xff0c;那么cuDNN就是训练加速工具&#xff0c;两者要相互配合使用&#xff0c;所以一般机器学习需要训练引擎(tensorflow-gpu) CUDA cuDNN使用。想不安装cuDNN是不可以的&#xff0c;而且cuDNN版本要和CUDA版本相互搭配。 1、前置工作 查看…

MinIO快速入门

一、MinIO概述 官网地址&#xff1a;http://www.minio.org.cn/ 文档地址&#xff1a;http://docs.minio.org.cn/docs/ MinIO是一款基于Apache License v2.0开源协议的分布式文件系统&#xff08;或者叫对象存储服务&#xff09;&#xff0c;可以做为云存储的解决方案用来保存海…

uniapp + vue3开发中组合式函数必须是一个同步函数

目录 vue3中的组合式函数用法&#xff1a; 官网示例异步组合式函数&#xff1a;同步函数写法 改造成导出async组合式函数时&#xff1a; uniapp无法使用async组合式函数的原因&#xff1a; vue3中的组合式函数使用时&#xff0c;导出的组合式函数必须是一个同步函数。 vue3…