赞
踩
1、首先我们来讨论在C/C++中的声明和定义..
1)我们先从函数声明和定义说起...
一般我们在C++里都会先定义一个函数,然后再Main函数前将函数声明,比如:
- //函数声明
- int Add(int);
-
-
- int Main
- {
-
- }
- //函数定义
- int Add(int)
- {
- }
声明就是告诉编译器,咱这儿有一个名字叫Add,返回值和参数需要int的函数,就给你说一声
定义就是在内存中拓展出了这么一片空间给该函数分配内存
所以你看,定义只能定义一次吧,如果你稍微变了个啥,这函数就不是自己了,但是声明你随意,你想声明啥声明啥,我内存没有啊,也就不存在调用,就相当于你在那空喊,没人理你...
2)我们再来讨论变量的声明和定义...
在C++里面,我们是这么声明和定义的
- //声明
- extren int var;
- typeof int INT;
- struct Node;
-
- //定义
- extern int ble = 10;
所以声明是不开辟内存空间的,而定义必须占用内存空间...
因此,在C++中,常用到定义和声明的就是函数和变量。。。
3)实例化和初始化
在面向对象的编程中,通常把用类创建对象的过程成为实例化,注意,他一般用在类上
初始化可以理解为给声明的对象赋值的过程,也就相当于定义
2:C#中的定义和声明
在C#中,其实和C++大概一样的,不过在C#中,你定义一个函数以后,可以直接进行使用,而不用在主函数体上方声明函数,至于变量的定义和声明,和C++一样,如果是int a ;只是声明,没有定义,使用int a = 10;这样才算创建出来了变量。
首先看看C#有哪些成员
字段是一种表示与对象或类型关联的变量,也叫成员变量
看如下代码,可以看出字段是如何一步步变成属性
- using UnityEngine;
- using System;
-
- public class GetSetProperty : MonoBehaviour
- {
-
- private void Start()
- {
- //一、未使用Get/Set属性
- Student stu1 = new();
- Student stu2 = new();
- Student stu3 = new();
-
- stu1.Age = 20;
- stu2.Age = 20;
- stu3.Age = 20;
-
- //此时如果有一个年龄被不小心修改了,比如第三个学生年龄修改成200,这种字段被污染很难发现
- int avgAge = (stu1.Age + stu2.Age + stu3.Age) / 3;
- //Debug.Log(avgAge);
-
-
- //二、使用Get/Set方法
- Student1 stu4 = new();
- Student1 stu5 = new();
- Student1 stu6 = new();
-
- //此时如果不小心将年龄修改成200,程序就会报错
- //可以使用try catch,程序就不会崩溃
-
- stu4.SetAge(20);
- stu5.SetAge(20);
- //stu6.SetAge(200);
- int avgAge1 = (stu4.GetAge() + stu5.GetAge() + stu6.GetAge())/3;
- try
- {
- stu6.SetAge(200);
- Debug.Log(avgAge1);
- }
- catch (Exception ex)
- {
- Debug.Log(ex.Message);
- }
-
- //三、使用Get/Set访问器
- Student2 stu7 = new Student2();
- Student2 stu8 = new Student2();
- Student2 stu9 = new Student2();
-
- stu7.Age = 20;
- stu8.Age = 20;
- stu8.Age = 20;
- int avgAge2 = (stu7.Age + stu8.Age + stu9.Age) / 3;
-
- Debug.Log(avgAge2);
- }
- }
- class Student
- {
- public int Age;
- public int Score;
- }
-
- /// <summary>
- /// 二、此时使用Get,Set函数,可以对字段进行约束
- /// </summary>
- class Student1
- {
- private int age;
- public int GetAge()
- {
- return this.age;
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="value"></param>
- public void SetAge(int value)
- {
- if (value >= 0 && value <= 120)
- {
- this.age = value;
- }
- else
- throw new System.Exception("value has error");
- }
- }
-
- /// <summary>
- /// 三、使用微软的Get/Set访问器
- /// </summary>
- class Student2
- {
- private int age;
- public int Age
- {
- get
- {
- return age;
- }
- set
- {
- if (value >= 0 && value <= 120)
- {
- this.age = value;
- }
- else
- {
- throw new Exception("Age value has error");
- }
- }
- }
- }
刚开始我们使用字段存储数据
但是考虑到暴露的缘故,我们引入了Get和Set函数来对字段进行约束
微软对Get/Set访问器进行了简化,就形成了Get/Set访问器
可以使用PropFull进行快速生成属性
属性是一种用于访问对象或类型的特征的成员,属性是字段的自然扩展
属性和字段都是用于表示实体的状态
属性大多数情况是字段的包装器
建议:永远使用属性来暴露数据,即字段永远是private或protected的
static关键字可以在类的定义,变量的声明,方法的定义中
变量前加上Static,变量成为静态变量,静态变量的内存分布在全局静态区,相当于它就是全局变量,Time.timescale就是静态变量
在函数前加上static,函数就变成了静态函数,直接类名+函数名就可以调用,比如Debug,或者Find函数都是静态函数
在类名的前面加上static,该类就变成了静态类,静态类不需要被实例化,它不能继承,静态类内的成员都需要带上static关键字,但是静态函数不需要一定在静态类中
一般情况下,将工具函数或者工具类,做成静态类或者静态函数。
CPU和GPU从名字上来说,一个是Central Processing Unit,一个是Graphic Processing Unit
后者是专门对图像进行处理的,为什么要针对图像处理要用专门的处理单元呢?
GPU(图形处理器)是图形系统结构的重要元件,是连接计算机和显示终端的纽带
就是说如果你要把图像显示在显示器上,必须要使用GPU,而GPU是如何工作的?可以参见下面的视频:
来看看CPU和GPU的内部结构
从图中可以看出,我们GPU有大量的运算单元,而CPU只有简单的4个ALU,而我GPU有成百上千的计算单元,我们单论单线的计算能力,比如你把一个数学中的复杂运算交给CPU,效率会变得特别高,它也理所当然能够完成任务,但是在图形计算方面,我们并没有呢么多高级运算,而是要进行大量的矩阵运算变换,也就是所谓的顶点计算→光栅化计算→纹理帖图→像素处理→最终输出
而在这样的运算中,都是一个一个像素点进行处理的,对于高像素的屏幕,有非常多的像素点,而对于每个像素点都得进行大量的计算,所以使用CPU效率实在太低,此时如果使用GPU,效率会变得很高,但是要注意的是:
光影都是CPU计算的,GPU只有2个工作,1多边形生成。2为多边形上颜色。
如下视频可以简单的告诉你CPU和GPU的区别...
NVIDIA现场形象展示CPU和GPU工作原理上的区别_哔哩哔哩_bilibili
这就是简单的CPU和GPU的区别介绍
计算机的逻辑运算在CPU中进行,CPU中又有ALU(Arithmetic/Logic Unit)和CU(Control Unit)
ALU是由"And Gate"(与门) 和"Or Gate"(或门)构成的算术逻辑单元,主要功能是进行二位元的算术运算
而CU是负责程序的流程管理。正如工厂的物流分配部门,控制单元是整个CPU的指挥控制中心,由指令寄存器IR(Instruction Register)、指令译码器ID(Instruction Decoder)和操作控制器OC(Operation Controller)三个部件组成
问题就出在,在计算机进行计算时,并不是将所有的数据都放在CPU,而是放在内存中,CPU对其进行调用,将内存中的数据放在寄存器中,所以CPU根据计算需求对内存进行调用,而我们说的堆和栈就是在内存中的两个区域
栈内存(Stack):栈中存放的是对象的引用及对象方法中参数的值,由操作系统自动分配释放
栈内存是动态分配和静态分配结合,是局部的
入栈和出栈遵循弹夹原则,先进后出,后进先出
栈的生长方向向下,内存地址由高到低
堆内存(Heap):堆中存放的是实例对象及成员变量的值(属性的值),堆由开发人员分配和释放, 若开发人员不释放,程序结束时由 OS 回收
堆是动态分配的,是全局的
堆可以被看成是一棵树,如:堆排序
堆的生长方向向上,内存地址由低到高
值类型:C#的所有值类型均隐式派生自System.ValueType。值类型是直接存储该值的
byte,short,int,long,float,double,decimal,char,bool 和 struct 统称为值类型。
值类型在声明后,不管有没有赋值,都已分配了内存
引用类型:引用类型是存储该类型的引用
string 和 class,数组,接口,委托统称为引用类型。
引用类型在声明后,只在栈中分配一小片内存用于容纳一个地址,而此时并没有为其分配堆上的内存空间;当使用 new 创建一个类的实例时,分配堆上的空间。
装箱和拆箱:
知道了值类型和引用类型以后,就牵扯一件事,这两种类型之间需要转换,比如
- ArrayList arraylist = new ArrayList();
- arraylist[0].add(1);
- arraylist[1].add('a');
- ...
此时我们需要将值类型的1和字符类型的a放在引用类型的数组中arraylist中,我们知道所有数据类型的基类是object,所以要想把值类型的对象放在引用类型的对象中,需要将值类型转换为object,这种转化是隐式进行的,此时上面的数组中的0号元素就是引用类型的
再看下一段
int a = (int)arraylist[0];
此时我们是把上面数组中的引用类型转化为值类型int,此时就进行了强转化
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。