[Unity中文课堂教程] C#中级编程 - 05 - 构造函数/封装/继承
原教程视频地址:
《[Unity中文课堂教程预告片] C#中级编程_哔哩哔哩_bilibili》
内容短小精悍简练,每节只有几分钟。很适合用来预习和复习。
构造函数
在上一篇《04》笔记中提到过,这次详细做实验。
- 构造函数没有返回值(void也不需要),构造函数的命名必须和类名相同,或不设会有一个默认的构造函数。
public class Exercise_4_9
{
public Exercise_4_9()
{
Debug.Log("Exercise_4_9 构造函数");
}
}
- 构造函数也允许重载,即可拥有多个参数不同的构造函数,实例化时根据参数选择执行其中一个执行。
public class Exercise_4_9 : MonoBehaviour
{
public Exercise_4_9()
{
Debug.Log("Exercise_4_9 构造函数");
}
public Exercise_4_9(int num)
{
Debug.Log(num);
}
}
/* ... */
Exercise_4_9 myClass = new Exercise_4_9(); // 只执行第一个构造函数
Exercise_4_9 myClass1 = new Exercise_4_9(1); // 只执行第二个构造函数
- 构造函数的“访问修饰符”要设置为
public
,才可被调用,而在实例化时会调用,一般使用new
关键字。如果设置为私有private、protected等
则无法访问(如果不设置默认也是私有),也就无法实例化,会直接报错。重载时同理。
在unity中也可使用泛型
gameObject.AddComponent<>()
,另外使用泛型时,即使构造函数是私有也可以调用。不过使用泛型实例化不知如何传参,也就无法选择重载了。
- 构造函数还可以设置为静态的,使用关键字
static
;而且不能写访问修饰符;只会被调用一次;在实例化时,或访问静态内容时调用;不能有参数,也就意味着不能重载,只能有一个。
重点:
虽然没有写访问修饰符,默认为私有
private
,按理类中必须要再写一个public
的构造函数。但是这里是允许的,可以只有一个静态构造函数。毕竟实例化时也可被调用的,前提是静态构造函数没有调用过。
public class Exercise_4_9 : MonoBehaviour
{
public static int num = 0; // 静态内容(属性)
public Exercise_4_9() // 每次都会被调用
{
Debug.Log("Exercise_4_9 构造函数");
}
static Exercise_4_9() // 只会调用一次,而且比普通构造函数要先调用
{ // 不可以设置 访问修饰符
Debug.Log("Exercise_4_9 静态函数");
}
/*atic Exercise_4_9(int x) // 报错,静态不能有参数
{
}*/
}
/* ... */
Exercise_4_9.num = 1; // 调用一次静态构造函数,之后不会再调用
Exercise_4_9 myClass = new Exercise_4_9(); // 若没有上一行,这一行会先静态再普通
Exercise_4_9 myClass1 = new Exercise_4_9(); //
- 构造函数在继承时不会被覆盖,子父类的构造函数都会存在并依次调用。(先父类后子类)
/* 续上一个例子中的 Exercise_4_9 */
public class Exercise_4_10 : Exercise_4_9
{
public Exercise_4_10()
{
Debug.Log("Exercise_4_10 构造函数");
}
}
/* ... */
public class Exercise_4_11 : MonoBehaviour
{
void Start()
{
Exercise_4_10 myClass = new Exercise_4_10();
}
}
- 在微软手册中《构造函数 - C# 编程指南 | Microsoft Docs》,还提到,如果构造函数只有一句,则可以使用表达式主体定义。
封装
- C# 封装根据具体的需要,设置使用者的访问权限,并通过 访问修饰符 来实现。在类的继承中很重要的概念。
一个 访问修饰符 定义了一个类成员的范围和可见性。C# 支持的访问修饰符如下所示:
public
:所有对象都可以访问;private
:对象本身在对象内部可以访问;protected
:只有该类对象及其子类对象可以访问internal
:同一个程序集的对象可以访问;protected internal
:访问限于当前程序集或派生自包含类的类型。
- 具体例子结合下一个知识点——继承讲解。
继承
- 继承是面向对象程序设计中最重要的概念之一。
- 和python的形式不一样,不需要括号,只需要冒号分隔。
在unity中:
每个挂载到游戏对象的脚本,都必须继承父类
MonoBehaviour
。有个常用操作,如果想往一个类中添加内容方法或属性,可以基于此类新定义一个派生类。然后其他类都继承此派生类即可。比如:类① 继承了
MonoBehaviour
,那之后的脚本只需要继承 类① 即可。
脚本①:(父类)
public class Exercise_4_9 : MonoBehaviour
{
public static int num = 100; // 静态属性
public int num_0 = 10; // 公开
private int num_1 = 11; // 私有
protected int num_2 = 12; // 子类公开
public static void get_s() // 静态方法
{
Debug.Log("Exercise_4_9 的静态");
}
public int get_num_0()
{
return num_0;
}
private int get_num_1()
{
return num_1;
}
protected int get_num_2()
{
return num_2;
}
}
脚本②:(子类)
public class Exercise_4_10 : Exercise_4_9 // 父类已经继承 MonoBehaviour ,该类也相当于继承了
{
public static int num1 = 101;
public int num_01 = 20;
private int num_11 = 21;
protected int num_12 = 22;
public static void get_s0()
{
num = 1000; // 直接访问父类的静态属性
Debug.Log("Exercise_4_10 的静态" + num);
}
public int get_num_01()
{
Debug.Log(num_0); // public 直接继承父类,不用前缀即可访问。10
// Debug.Log(num_1); // private 不能外部访问,即使子类也不可。11
Debug.Log(num_2); // protected 限定子类。12
get_s(); // 静态方法也是直接访问
return num_01; // 20
}
public void get_all()
{
Debug.Log(get_num_0()); // 函数同理。10
// Debug.Log(get_num_1()); // 11
Debug.Log(get_num_2()); // 12
}
}
脚本③:(实例化)
public class Exercise_4_11 : MonoBehaviour
{
void Start()
{
Exercise_4_10 myClass = new Exercise_4_10();
Exercise_4_9.num = 233; // 父类的静态属性也继承,而且是共用
Debug.Log("Exercise_4_10.num1:" + Exercise_4_10.num1);
Debug.Log("Exercise_4_10.num:" + Exercise_4_10.num);
Exercise_4_10.get_s(); // 静态方法也是
Exercise_4_10.get_s0();
myClass.get_all();
Debug.Log(myClass.get_num_01()); // public 公开
// Debug.Log(myClass.get_num_11); // private 不能外部
// Debug.Log(myClass.get_num_12); // protected 只能子类
/* 更多打印调试不列举了 */
}
}
- 总结:
- 基于访问修饰符,父类(含静态)的属性和方法可直接在子类中访问。不需要前缀,宛如就是在子类中定义似的。
- 子类继承父类的静态后,属于引用。本质上还是父类的静态,如果子类修改了父类的静态,父类会同步修改;反之亦然。
还有覆写等知识点,下一篇再写,发现太多了。