C++基础(二)
目录
1.类和对象
1.1类的定义
1.2访问限定符
1.3类域
2.实例化
2.1实例化概念
2.2对象大小
3.this指针
4.类的默认成员函数
4.1构造函数
4.2析构函数
4.5运算符重载
1.类和对象
1.1类的定义
类的定义格式
class为定义类的关键字,Stack为类的名字,{}中为类的主体,注意定义结束时后面分号不省略。类体中内容称为类的成员:类中的变量称为类的属性或成员变量;类中的函数称为类的方法或成员函数。
//text.cpp
#include<iostream>
using namespace std;class Stack
{//成员变量int* a;int top;int capacity;//成员函数void Push(){}void Pop(){}
};//分号不能省略
int main()
{return 0;
}
- 为了区分成员变量,一般习惯上成员变量会加一个特殊标识,如成员变量前面或后面加_或者m_开头。这个C++语法上并没有规定,仅凭个人或公司喜好
//为区分成员变量,一般前面加_
//成员变量
int* _a;
int _top;
int _capacity;
- C++中struct也可以定义类,C++兼容c中struct的用法,同时struct升级成了类,明显的变化是struct中也可以定义函数,一般情况下我们还是推荐用class定义类
- 定义在类里面的成员默认为inline
1.2访问限定符
C++一种实现封装的方式,用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用
- public(公有)修饰的成员在类外可以直接被访问,protected(保护)和private(私有)修饰的成员在类外不能直接被访问,protected和private是一样的
- 访问权限作用域从该访问权限出现的位置开始直到下一个访问限定符出现为止,如果后面没有访问限定符,作用域就到 } 即类结束
//text.cpp
#include<iostream>
using namespace std;class Stack
{///void Push(){}//Push 没给限定符 class默认私有 private ///
public:void Pop(){}int Swap(){}//Pop和Swap 被public修饰,直到下一个限定符出现之前都为公有///
protected:int add();
//add 被public修饰,直到下一个限定符出现之前都为保护
/// /private:int* _a;int _top;int _capacity;
//成员变量被private修饰,直到}结束都为私有
};
int main()
{Stack st;//公有可以访问st.Pop();st.Swap();//私有不可访问st._top;return 0;
}
额外注意:
- class定义成员没有被访问限定符修饰时默认为private,struct默认为public
- 一般成员变量都会被限制为private/protected,需要给别人使用的成员函数会被放为public
1.3类域
类定义了一个新的作用域,类所有成员都在类的作用域中,在类体外定义成员时,需要使用 ::作用域操作符指明成员属于哪个类域
类域影响的是编译的查找规则,下面程序中Init如果不指定类域Stack,那么编译器就会把Init当成全局函数,那么编译时找不到_top等成员,就会到类域去找
//text.cpp
#include<iostream>
using namespace std;class Stack
{public:void Init(int x, int y);};
void Stack::Init(int x, int y){_top = x;_capacity = y;}
int main()
{return 0;
}
注意:
- 类里面的函数声明定义分离,类创建后形成了新的类域,需要指定类域,否则不可访问
2.实例化
2.1实例化概念
- 用类型在物理内存中创建的过程,称为类实例化出对象
- 类是对象进行一种抽象描述,是一个模型一样的东西,限定了类有哪些成员变量,这些成员变量只是声明,没有分配空间,用类实例化出对象时,才会去分配空间
//text.cpp
#include<iostream>
using namespace std;class Stack
{//声明int* _a;int _top;int _capacity;};int main()
{Stack::_top = 2024;//编译器报错,_top只是声明,并未实例化return 0;
}
- 一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间,存储成员变量。打个比方:类实例化出对象就像现实中使用建筑设计图造房子一样,类就像设计图,设计图规划出有多少个房间,房子大小等,但是并没有实体的建筑存在,也不能住人,用设计图修建出房子,房子才能住人。同样类就像设计图一样,只是告诉编译器即将要开多大的内存,但是不开内存,只有实例化出的对象才分配物理内存存储数据
-
//text.cpp #include<iostream> using namespace std;class Stack {//声明int* _a;int _top;int _capacity;};int main() {Stack st;st._top=2024; //Stack实例化出st,系统已经给st分配内存了,可以存储数据,编译通过return 0; }
2.2对象大小
- 分析一下类对象都有哪些成员呢?类实例化出的每个对象,都有独立的数据空间,所以对象中肯定包含成员变量,那么成员函数是否包含呢?首先函数被编译后是一段指令,对象中没法储存,这些指令存储在一个单独的区域(代码段),那么对象非要存储的话,只能是成员函数的指针。对象中是否有存储指针的必要呢,Date实例化出两个对象d1和d2,di和d2都有各自独立的成员变量_year/_month/_day存储各自的数据,但是d1和d2的成员函数Init/Print指针却是一样的,存储在对象中就浪费了。如果用Date实例化出100个对象,那么成员函数指针就重复存储100次,太浪费了。其实函数指针不需要存储的,函数指针是一个地址,调用函数被编译成汇编指令[call地址],其实编译器在编译链接时,就要找到函数的地址,不是在运行时找,只有动态多态是在运行时找,就需要存储函数地址。
内存对齐规则
- 第一个成员在与结构体偏移量为0处的地址处
- 其他成员变量要对齐对齐数的整数倍的地址处
- 对齐数=编译器默认的对齐数与该成员的大小的较小值
- VS x64平台默认对齐数是4,x86默认对齐数是8
- 结构体总大小为:最大对齐数(所有类型变量最大者与默认对齐数取最小)的整数倍
- 如果嵌套了结构体的情况,嵌套的结构体对齐到自己最大对齐数的整数倍,结构体整体大小就是所有最大对齐数(含嵌套结构体对齐数)的整数倍
class A
{
public:void Print(){cout << _ch << endl;}
private:char _ch;int _i;
};
//_ch 是一个字节,默认对齐数是4,最大对齐数是4,所以开辟4个字节用来存在_ch
// _i是4个字节,默认对齐数是4,最大对齐数是4,所以开辟4个字节用来存储_i
class B
{
public:void Print(){//。。。}};
class B
{};
//B和C里面没有存储任何成员变量,只有一个函数,可成员函数不存对象里面
// 按理来说是0,但是结构体怎么会没大小,为表示对象存在C++对这种规定大小为1,为了占位标识对象存在
3.this指针
编译器编译后,类的成员函数默认都会在形参第一个位置,增加一个当前类的指针,叫做this指针
例如Date类中的Init原型为 void Init(Date * const this,int year ,int month,int day),类的成员函数中访问成员变量,本质是通过this指针访问的,如Init函数中给_year赋值,this->_year=year
原型:
class Date
{void Print(){cout << _year << "\n" << _month << "\n" << _day << endl;}void Init( int year, int month,int day){_year = year;_month = month;_day = day;}private:int _year;int _month;int _day;};
Date d1;
d1.Init(2024,7,10);d1.Print();
Date d2;d2.Init(2024, 7, 9);
d2.Print();
真实原型
class Date
{void Init(Date* const this,int year, int month,int day){this->_year = year;this->_month = month;this->_day = day;}void Printf(Date* const this){cout << this->_year << "\n" <<this-> _month << "\n" << this->_day << endl;}
private:int _year;int _month;int _day;};
Date d1;
d1.Init(&d1,2024,7,10);
d1.Print(&d1);Date d2;
d2.Init(&d2,2024, 7, 9);
d2.Print();
C++规定不准在实参和形参的位置写this指针(编译时编译器会处理),但是可以在函数体内显示使用this指针,this指针不能修改,但this指针指向的内容可以
this指针存在栈里
4.类的默认成员函数
默认成员函数就是用户没有显示定义,编译器会自动生成的成员函数称为默认成员函数
4.1构造函数
构造函数是特殊的成员函数,需要注意的是,构造函数虽然名字叫构造函数,但是构造函数的主要内容并不是开辟空间创造对象(我们平常使用的局部对象是栈帧创建时,空间就开好了),而是对象实例化时初始化对象。构造函数的本质是要替代我们以前Stack和Date类中写的Init函数的功能,构造函数自动调用的特点就完美替代了Init
构造函数的特点:
- 函数名与类名相同
- 无返回值(返回值啥也不需要给,也不要写void C++就是这样规定)
- 对象实例化时系统会自动调用对应的构造函数
- 构造函数可以重载
- 如果类中没有显示定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显示定义编译器将不再生成
class Date
{public://1.无参构造函数Date(){_year = 1;_month = 1;_day = 1;}//2.带参构造函数Date(int year, int month, int day)
{_year = year;_month = month;_day = day;}//3.全缺省构造函数Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;};
无参构造函数,全缺省构造函数,我们不写构造时编译器默认生成的构造函数,都叫做默认构造函数。但是这三个有且只能有一个存在,不能同时存在。无参构造函数和全缺省构造函数虽然构成函数重载,但是调用时会存在歧义。注意并不是只有默认构造函数就是编译器默认生成的那就是构造函数,无参构造函数,全缺省构造函数也是默认构造函数,总结一下就是不传参就能调用
我们不写,编译器默认生成的构造,对内置类型成员变量的初始化没有要求,也就是说是是否初始化是不确定的,看编译器。
//text.cpp
#include<iostream>
using namespace std;
typedef int STDataType;
class Stack
{
public:Stack(int n = 4){_a = (STDataType*)malloc(sizeof(STDataType) * n);if (nullptr == _a){perror("malloc申请失败");}_capacity = n;_top = 0;}private:STDataType* _a;size_t _capacity;size_t _top;
};
//两个Stack实现队列
class MyQueue
{
private:int size;Stack pushst;Stack popst;
};int main()
{MyQueue my;return 0;
}
C++把类型分为自定义类型和内置类型(基本类型)。内置类型就是语言提供的原生数据类型,如int/char/double/指针等,自定义类型就是我们使用class/struct等关键字自己定义的类型。这里构造函数自动初始化,VS也将内置类型size初始化了,不同的编译器初始化值不同,C++并没有规定
对于自定义类型成员变量,要求调用这个成员变量的默认构造函数初始化。如果这个成员变量,没有默认的构造函数,那么就会报错,我们要初始化这个成员变量,需要用初始化列表才能解决
总结:大多数情况下,构造函数都需要我们自己去实现,少数情况类似MyQueue且Stack有默认构造函数时,MyQueue自动生成就可以用
4.2析构函数
~Stack()
{free(_a);_a = nullptr;_top = _capacity = 0;
}
析构函数的特点:
1.析构函数名是在类名前面加上字符~
2.无参无返回值(与构造函数一致)
3.一个类只能有一个析构函数。若未显示定义,系统也会自动生成默认的析构函数
4.对象声明周期结束时,系统会自动调用析构函数,
5.跟构造函数类似,我们不写编译器自动生成的析构函数对内置类型成员不做处理,自定义类型成员会调用其他的析构函数
6.还需注意的是我们显示析构函数,对于自定义类型成员也会调用他的析构函数,也就是说自定义类型成员无论什么情况都会自动调用析构函数。
//text.cpp
#include<iostream>
using namespace std;
typedef int STDataType;
class Stack
{
public:Stack(int n = 4){_a = (STDataType*)malloc(sizeof(STDataType) * n);if (nullptr == _a){perror("malloc申请失败");}_capacity = n;_top = 0;}~Stack(){free(_a);_a = nullptr;_top=_capacity=0;}
private:STDataType* _a;size_t _capacity;size_t _top;};
//两个Stack实现队列
class MyQueue
{public://编译器默认生成MyQueue的构造函数调用了Stack的构造,完成了两个成员的初始化//编译器默认生成MyQueue的析构函数调用了Stack的析构,释放了Stack内部的资源//显示写析构也会调用Stack的析构~MyQueue(){cout << "~MyQueue" << endl;}
private: Stack pushst;Stack popst;};int main()
{MyQueue my;return 0;
}
MyQueue里的析构啥也没干,但是C++规定会调用其他的析构来释放内存
如果没有申请资源时,析构可以不写,直接使用编译器生成的默认析构函数,如Date,如果默认生成的析构可以用,也就不需要显示写析构如MyQueue,但是有资源申请时,一定要直接写析构,否则会造成资源泄漏如Stack
4.5运算符重载
- 当运算符被用于类型的对象时,C++语言允许我们通过运算符重载的形式指定新的含义。C++规定类类型对象使用运算符时,必须转换成调用对应运算符重载,若没有则编译器报错
- 运算符重载是具有特定名字的函数,他的名字是由operator和后面要定义的运算符共同构成。和其他函数一样,它也具有其返回类型和参数列表以及函数体
bool operator<(Date d1, Date d2)
{}
bool operator==(Date d1,Date d2)
{return d1._year == d2._year && d1._month == d2._month && d1._day == d2._day;
}
- 重载运算符函数的参数个数和该运算符作用的参数一样多。一元运输安抚有一个参数,二元运算符有两个参数,二元运算符的左侧运算对象传给第一个参数,右侧运算对象传给第二个参数
//text.cpp
#include<iostream>
using namespace std;class Date
{
public:Date(int year, int month, int day){_year= year;_month = month;_day = day;}int _year;int _month;int _day;};int GetMonthDay(int year ,int month)
{
static int monthDayArray[13]={-1,31,28,31,30,31,30,31,31,30,31,30,31};if(month==2&&((year%4==0&&year%100!=0)||(year%400==0){return 29;}return monthDayArray[month];
} bool operator<(Date d1, Date d2)
{
Date tem=*this;
tem-=day;
return tmp;
}
//天数是否相等
bool operator==(Date d1,Date d2)
{return d1._year == d2._year && d1._month == d2._month && d1._day == d2._day;
}
//日期-天数
Date& Date:operator-=(int day)
{_day-=day;
while(_say<=0){
--_month;if(_month==0){
_month=12;
--_year;}}
_day+=GetMonthDay(_year,_month);
}
//Date 加一个天数
Date& Date::operator+=(int day)
{_day+=day;
while(_day>GetMonthFay(_year,_month)){_day-=GetMonthDay(_year,_month);++month;if(_month==13){_year++;_month=1;}}
return *this;
)
//日期比大小
bool Date::operator<(const Date& d)
{if(_year<d._year){return ture;}elae if(_year==d,_year){
if(_month<d._month)
{
return true;
}
else if(_month==d._month)
{
return _day<d._day;
}
}
return false;
}//日期比大小
bool Date :: operator<=(const Date&d)
{
return *this<d||*this==d;
}
//日期比大小
bool Date :: operator>=(const Date&d)
{
return !(*this<=d);
}
int main()
{Date d1(2024, 7, 10);Date d2(2024,7,9);
//两种用法都可以d1 == d2;operator==(d1 , d2);return 0;
}
- 如果一个重载运算符函数是成员函数,则他的第一个运算对象默认传给隐式的this指针,因此运算符重载作为成员函数时,参数比运算对象少一个
- 运算符重载以后,其优先级和结合性与内置类型运算保持一致
- 不能通过连接语法中没有的符合来创建性的操作符:比如operator@
- .* :: sizeof ?: . 以上五个不能重载
相关文章:

C++基础(二)
目录 1.类和对象 1.1类的定义 1.2访问限定符 1.3类域 2.实例化 2.1实例化概念 2.2对象大小 3.this指针 4.类的默认成员函数 4.1构造函数 4.2析构函数 4.5运算符重载 1.类和对象 1.1类的定义 类的定义格式 class为定义类的关键字,Stack为类的名字&…...

R 绘图 - 中文支持
R 绘图 - 中文支持 R 是一种广泛使用的统计和数据分析编程语言,它提供了强大的绘图功能。然而,R 的默认设置并不直接支持中文,这可能会在使用 R 进行绘图时造成困扰,尤其是当需要在图表中添加中文标签或标题时。本文将介绍如何在…...

使用Godot4组件制作竖版太空射击游戏_2D卷轴飞机射击-标题菜单及游戏结束界面(九)
文章目录 开发思路标题菜单界面标题菜单脚本代码结束菜单界面结束菜单脚本代码 使用Godot4组件制作竖版太空射击游戏_2D卷轴飞机射击(一) 使用Godot4组件制作竖版太空射击游戏_2D卷轴飞机射击-激光组件(二) 使用Godot4组件制作竖版…...

[终端安全]-6 移动终端之应用程序安全
笔者在终端安全专题前面的文章中介绍了移动终端硬件安全和操作系统安全,本文主要介绍移动终端应用安全。在本文最前面,笔者想先解答一位朋友的疑问,为什么需要费心打造一个完整的面面俱到的安全体系? 1 移动终端安全的重要性 移…...

基于望获实时Linux的高性能运动控制器适配
在快速迭代的工业自动化与机器人控制领域,高性能运动控制器无疑是实现极致精度与效率的核心引擎。实时操作系统(Real-Time Operating System,RTOS)凭借其低延迟与高度确定性的特性,成为这些高精度、高速度应用的首选平台。 望获…...

电气工程VR虚拟仿真实训平台以趣味化方式增强吸引力
在工业4.0时代和教育信息化的双重推动下,我们致力于推动实训课件的跨界合作与共创。VR实训课件不仅促进了不同领域、不同行业之间的紧密合作,更让学习变得生动直观。我们凭借3D技术生动、直观、形象的特点,开发了大量配套3D教材,让…...

数据结构(单链表(1))
前言 线性表中有着许多的结构,如顺序表和链表。而单链表则是链表的最基础的一种形式,下面就让我们对其做一个了解。 概念 概念:链表是⼀种物理存储结构上⾮连续、⾮顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次…...

STM32第十八课:SPIFlash
目录 需求一、SPI概要二、SPI配置1.开时钟2.配置IO3.配置&使能SPI 三、FLash操作函数1.SPI发送数据2.FLASH写使能3.FLASH等待操作完成4.FLASH页写操作5.FLASH读操作6.FLASH扇区擦除 四、需求实现 需求 通过SPI控制FLash进行数据的保存和删除。 一、SPI概要 在我们使用UA…...

如何使用IPython的并行计算能力处理大数据
目录 引言IPython概述 什么是IPythonIPython的特点 并行计算简介 什么是并行计算并行计算的优势 IPython的并行计算功能 IPython.parallel模块IPython并行架构 IPython的安装与配置 安装IPython配置并行环境 IPython并行计算的基础 任务分发与负载均衡核心概念:Cli…...

前端热门面试题二
你有使用过哪些前端构建工具(如Webpack、Gulp、Rollup)?并谈谈它们的特点和优势。 在前端开发中,构建工具扮演着至关重要的角色,它们能够自动化处理各种任务,如代码压缩、模块打包、代码转换、静态资源管理…...

Android TabLayout+ViewPager2如何优雅的实现联动详解
一、介绍 Android开发过程中,我们经常会遇到滑动导航栏的做法,之前的做法就是我们通过ViewGroup来转动,然后通过大量的自定义来完成,将导航栏item与viewpage 滑动,达到业务需求 二、现实方案 通过介绍,我…...

k8s快速部署一个网站
1)使用Deployment控制器部署镜像: kubectl create deployment web-demo --imagelizhenliang/web-demo:v1 kubectl get deployment,pods[rootk8s-matser ~]# kubectl get pods NAME READY STATUS RESTARTS A…...

期货量化交易客户端开源教学第四节——交易接口协议
指令介绍: 01----09:服务端发送到客户端指令 10----49:客户端发送操作指令 50----59:客户端与服务端通讯指令 60----99:股票接口与服务端交互指令 --------------------------------------------------- 02:商品行情 03:用户信息接收 04:用户资产信息接收 ----发送到…...

M1000 4G蓝牙网关:高速稳定,赋能物联网新体验
桂花网M1000的4G移动网络功能主要体现在以下几个方面: 一、高速稳定的数据传输 高速率:M1000支持4G移动网络,能够实现高速的数据传输。根据4G网络的技术标准,其理论上的最大下行速率可达到数百Mbps(如TD-LTE在20MHz带…...

中国高端水果元宇宙
高档榴莲通常指的是品质上乘、口感极佳、产地知名且价格较高的榴莲品种。榴莲因其独特的风味和营养价值而被誉为“水果之王”,在东南亚尤其受欢迎。以下是一些被认为是高档榴莲的品种: 1.**猫山王榴莲(Musang King or Mao Shan Wangÿ…...

MySQL:库操作
1. 创建数据库 create database [if not exists] name [create_specification], [create_specification]... []内为可选的选项 create_specification: character set charset_name -- 指定数据库采用的字符集 -- 数据库未来存储数据 collate collation_name -- 指定数据库字符…...

struts2如何防止XSS脚本攻击(XSS防跨站脚本攻击过滤器)
只需要配置一个拦截器即可解决参数内容替换 一、配置web.xml <filter><filter-name>struts-xssFilter</filter-name><filter-class>*.*.filters.XssFilter</filter-class></filter><filter-mapping><filter-name>struts-xss…...

SQL基础 | NOT NULL 约束介绍
在SQL中,NOT NULL是一个约束条件,用于确保列不接受NULL值。 这个约束通常在创建表或修改表时使用,以确保数据的完整性和准确性。 以下是NOT NULL的一些常见用法: 创建表时指定NOT NULL约束: 当你创建一个新表时&#x…...

C语言 ——— 实用调试技巧(Visual Studio)
目录 Debug 和 Release 的区别 F10 --- 逐过程调试 & F11 --- 逐语句调试 F9 --- 新建/切换断点 & F5 --- 开始调试 shift F5 & ctrl F5 Debug 和 Release 的区别 Debug:通常为调试版本,它包含调试信息,并且不作任何优化…...

音频demo:使用faad2将AAC数据解码出PCM数据
1、README 前言 本demo是使用的开源项目faad2将aac数据解码成pcm数据。 a. 编译使用 faad2的编译:(faad2下载地址:https://sourceforge.net/projects/faac/files/faad2-src/faad2-2.8.0/) tar xzf faad2-2.8.8.tar.gz cd faad2-2.8.8/ ./configure …...

力扣 hot100 -- 多维动态规划
👇woc,这不是最熟悉那种,记忆化 dfs 或者 普通的深度优先搜索??都适用于二维地图👇 DFS(深度优先搜索)8种题型_dfs典型问题-CSDN博客 目录 🥃不同路径 🌼最…...

[misc]-流量包-wireshark-icmp
wireshark打开,大部分都是icmp,查看data部分 提取data长度: tshark.exe -r 1.pcapng -T fields -e data.len > length.txt 使用python解析这个文件,剔除异常值,每8个取一个值,得到flag ds [] with open(length.tx…...

探索性数据分析:使用Python与Pandas库实现数据洞察
探索性数据分析:使用Python与Pandas库实现数据洞察 引言 在当今数据驱动的时代,数据分析已成为决策制定、策略规划和业务优化的关键环节。无论是商业智能、金融分析还是市场研究,数据分析都扮演着至关重要的角色。Pandas库作为Python生态系统…...

枚举的高阶用法之枚举里写方法以及注入spring的bean
1、前言 一般我们使用枚举都是用来定义一些常量。比如我们需要一个表示订单类(pc订单、手机订单)的常量,那我们就可以使用枚举来实现,如下: AllArgsConstructor public enum OrderTypeEnum{PC("PC", "电脑端"),PHONE("PHONE", "手机端&quo…...

游戏开发面试题2
网络游戏分为客户端和服务端,你能说说客户端和服务端都干了一些什么工作吗? 客户端(Client) 客户端是玩家直接交互的部分,主要负责用户界面、输入处理、渲染和部分逻辑处理。具体工作包括: 用户界面&…...

华为机试题-单车道汽车通行时间-Java
代码在最后面 1 题目描述 M(1 ≤ M ≤ 20)辆车需要在一条不能超车的单行道到达终点,起点到终点的距离为 N(1 ≤ N ≤ 400)。 速度快的车追上前车后,只能以前车的速度继续行驶,求最后一辆车到达…...

6-5,web3浏览器链接区块链(react+区块链实战)
6-5,web3浏览器链接区块链(react区块链实战) 6-5 web3浏览器链接区块链(调用读写合约与metamask联动) 6-5 web3浏览器链接区块链(调用读写合约与metamask联动) 这里就是浏览器端和智能合约的交…...

C# 多态性
C# 多态性 介绍 多态性是面向对象编程(OOP)的一个核心概念,它允许不同类的对象对同一消息做出响应,并产生不同的结果。在C#中,多态性主要通过继承、接口和虚方法来实现。本文将深入探讨C#中的多态性,包括其原理、实现方式以及在实际编程中的应用。 原理 多态性允许将…...

Visual Studio 安装程序无法执行修复或更新
一.问题场景 出现问题的场景:当你的VS已经安装但是无法在工具中下载新组件或者卸载了当时一直无法安装。 二.问题原因 如果计算机上的 Visual Studio 实例已损坏,则可能会出现此问题。 三.解决方法 如果之前尝试修复或更新 Visual Studio 失败&…...

C#与PLC通信——如何设置电脑IP地址
前言: 我们与PLC通过以太网通信时,首先要做的就是先设置好电脑的IP,这样才能实现上位机电脑与PLC之间的通信,并且电脑的ip地址和PLC的Ip地址要同处于一个网段,比如电脑的Ip地址为192.168.1.1,那么PLC的Ip地…...