Home [C# 筆記] 物件導向(面向對象)語法和繼承-複習
Post
Cancel

[C# 筆記] 物件導向(面向對象)語法和繼承-複習

TODO: 單例模式,只能創建一個物件(對象)

物件導向(面向對象)的複習

  • 封裝、繼承、多型(多態)

Class類別的成員

  • Class類別的成員:屬性、欄位/字段、構造函數、方法、介面/接口
  • Field(欄位/字段):儲存數據,訪問修飾符應該設置為private私有的。
  • 屬性:保護Field(欄位/字段),對Field的取值和賦值進行限定。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
internal class Person
{
    //field(欄位/字段)、屬性、構造函數、方法、介面/接口

    private string _name; //field(欄位/字段)
    public string Name //屬性,用來保護field(欄位/字段)
    {
        get { return _name; } //外部要取值的時候會執行get
        set { _name = value; } //外部要賦值的時候會執行set
    }

    private int _age;
    public int Age
    {
        get { return _age; }
        set { _age = value; }
    }

    private char _gender;
    public char Gender
    {
        get { return _gender; }
        set { _gender = value; }
    }
    public Person() { }

    public void SayHello()
    {
        //this在這裡代表當前類的這個對象
        Console.WriteLine($"{this.Name}---{this.Age}---{this.Gender}");
    }
}

new 關鍵字

new關鍵字:

  1. 在heap(堆積/堆)當中開闢空間
  2. 在開闢的空間中創建物件(對象)
  3. 調用物件(對象)構造函數
    • 引用類型的值都是在heap(堆積/堆)當中

this

  1. 代表當前類的物件(對象)
  2. 調用自己的構造函數

1. 代表當前類的物件(對象)

1
2
3
4
5
6
7
8
9
public void SayHello()
{
    //this在這裡代表當前類的這個對象

    //如果這個方法裡也有個變數Name, 
    //string Name = "王五";
    //如果沒有加this,Name就變成"王五"了,而不是屬性值的Name
    Console.WriteLine($"{this.Name}---{this.Age}---{this.Gender}");
}

2. this調用自己的構造函數

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//全參構造函數
public Person(string name, int age, char gender, int math, int english)
{
    this.Name = name;
    this.Age = age;
    this.Gender = gender;
    this.Math = math;
    this.English = english;
}

//在執行這個構造函數的時候,調的是自己的全參構造函數
public Person(string name, int age, char gender) 
    : this(name, age, gender, 0, 0) //繼承自己的構造函數
{
    //有調用自己類別的全參構造函數,這三行就不用寫了
    //this.Name = name;
    //this.Age = age;
    //this.Gender = gender;
}

base

一切類型的父類

構造函數

  • 構造函數就是一個特殊的方法
    • 沒有返回值
    • 他是public公有的
    • 名稱跟類名一樣
  • 構造函數的作用是什麼?初始化物件(對象),當創建物件(對象)的時候,會調用構造函數。
1
2
3
4
class Person {
    public Person() {
    }
}

創建物件&初始化物件

  • 寫好一個類,要使用它必須先創建它的物件(對象),除了靜態類、抽象類
  • 給物件(對象)的每個屬性賦值的過程,稱之為物件(對象)的初始化
1
2
3
4
5
Person p = new Person(); //創建Person物件
//給物件(對象)的每個屬性賦值的過程,稱之為物件(對象)的初始化
p.Name = "張三";
p.Age = 10;
p.Gender = '男';

靜態成員&實體成員

  • static關鍵字代表靜態成員,靜態方法怎麼調用?直接類名.方法
  • 沒有static關鍵字稱之為實體成員、非靜態成員
1
2
3
4
5
6
7
//靜態成員 => 有static關鍵字
public static int count;
public static void SayHi() { }

//非靜態成員(實體成員) => 沒有static關鍵字
public int count;
public void SayHi() { }

對Field(欄位/字段)的保護方法:

  1. get()
  2. set()
  3. 構造函數

1.get()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private string _name; //field(欄位/字段)
public string Name //屬性,用來保護field(欄位/字段)
{
    //外部要取值的時候會執行get
    get { return _name; }
    //外部要賦值的時候會執行set
    set
    {
        //賦值的時候,對名字做限定
        if (value != "李四") {
            value = "李四";
        }
        _name = value;
    }
}

2.set()

1
2
3
4
5
6
7
8
9
10
11
12
13
private int _age;
public int Age
{
    get
    {
        //取值的時候,對年齡做限定
        if (_age < 0 || _age > 100) {
            return _age = 0;
        }
        return _age;
    }
    set { _age = value; }
}

3.構造函數

1
2
3
4
5
6
public Person(char gender) {
    if (gender != '男' && gender != '女') {
        gender = '男';
    }
    this.Gender = gender;
}

return

  1. 立即結束本次方法(立即離開方法)
  2. 在方法中返回要返回的值return age = 0;

總結

  • 封裝、繼承、多型(多態)

Class類別的成員

  • Class類別的成員:屬性、欄位/字段、構造函數、方法、介面/接口
  • Field(欄位/字段):儲存數據,訪問修飾符應該設置為private私有的。
  • 屬性:保護Field(欄位/字段),對Field的取值和賦值進行限定。

new關鍵字

new關鍵字:

  1. 在heap(堆積/堆)當中開闢空間
  2. 在開闢的空間中創建物件(對象)
  3. 調用物件(對象)構造函數

    引用類型的值都是在heap(堆積/堆)當中

this

  1. 代表當前類的物件(對象)
  2. 調用自己類的構造函數

base

  • 一切類型的父類
  • 繼承父類的構造函數

構造函數

  • 構造函數就是一個特殊的方法
    • 沒有返回值
    • 他是public公有的
    • 名稱跟類名一樣
  • 構造函數的作用是什麼?初始化物件(對象),當創建物件(對象)的時候,會調用構造函數

創建物件&初始化物件

  • 寫好一個類,要使用它必須先創建它的物件(對象),除了靜態類、抽象類
  • 給物件(對象)的每個屬性賦值的過程,稱之為物件(對象)的初始化

靜態成員&實體成員

  • static關鍵字代表靜態成員,靜態方法怎麼調用?直接類名.方法
  • 沒有static關鍵字稱之為實體成員、非靜態成員

對Field(欄位/字段)的保護方法:

  1. get()
  2. set()
  3. 構造函數

return

  1. 立即結束本次方法(立即離開方法)
  2. 在方法中返回要返回的值return age = 0;

繼承複習

解決代碼的冗餘,實現多形(多態),增加了代碼的擴展素,便於維護。

繼承有兩個很重要的特性:

  1. 單根性:
    單根性指的是,一個類只能有一個父類,所以我們說,類是單繼承的, 誰是多繼承的?介面(接口),介面才能多繼承。
  2. 傳遞性:
    子類可以使用父類的成員,一個類繼承了一個父類,繼承了屬性和方法,沒有繼承Field(欄位/字段)。

子類並沒有繼承父類的構造函數,而是會默認調用父類的那個無參數的構造函數。

子類為什麼調用父類的構造函數?

因為子類最終要使用父類的成員,父類沒有物件(對象)的話,你能訪問他的成員嗎?不能,所以子類會先在內部會先創建父類的物件(對象),當無參的構造函數沒有了,還能創建嗎?

解決這個問題有兩個辦法:

  1. 父類再加一個無參的構造函數
  2. 在子類中調用父類的構造函數,使用關鍵字base

Code-物件導向複習-程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
Person p = new Person('中'); //創建person物件
//給對象的每個屬性賦值的過程,稱之為物件(對象)的初始化
p.Name = "張三";
p.Age = -10;
//p.Gender = '中';

namespace _03_物件導向複習
{
    internal class Person
    {
        //field(欄位/字段)、屬性、構造函數、方法、介面/接口

        private string _name; //field(欄位/字段)
        public string Name //屬性,用來保護field(欄位/字段)
        {
            //外部要取值的時候會執行get
            get { return _name; }
            //外部要賦值的時候會執行set
            set
            {
                //賦值的時候,對名字做限定
                if (value != "李四")
                {
                    value = "李四";
                }
                _name = value;
            }
        }

        private int _age;
        public int Age
        {
            get
            {
                //取值的時候,對年齡做限定
                if (_age < 0 || _age > 100)
                {
                    return _age = 0;
                }
                return _age;
            }
            set { _age = value; }
        }

        private char _gender;
        public char Gender
        {
            get { return _gender; }
            set { _gender = value; }
        }

        private int _math;
        public int Math
        {
            get { return _math; }
            set { _math = value; }
        }

        private int _english;
        public int English
        {
            get { return _english; }
            set { _english = value; }
        }

        public Person() { }
        public Person(char gender)
        {
            if (gender != '男' && gender != '女')
            {
                gender = '男';
            }
            this.Gender = gender;
        }
        //全參構造函數
        public Person(string name, int age, char gender, int math, int english)
        {
            this.Name = name;
            this.Age = age;
            this.Gender = gender;
            this.Math = math;
            this.English = english;
        }

        //在執行這個構造函數的時候,調的是自己的全參構造函數
        public Person(string name, int age, char gender) 
            : this(name, age, gender, 0, 0) 
        {
            //有調用自己類別的全參構造函數,這三行就不用寫了
            //this.Name = name;
            //this.Age = age;
            //this.Gender = gender;
        }

        public void SayHello()
        {
            //this在這裡代表當前類的這個對象
            Console.WriteLine($"{this.Name}---{this.Age}---{this.Gender}");
        }
    }
}

繼承複習

解決代碼的冗餘,實現多形(多態),增加了代碼的擴展素,便於維護。

繼承有兩個很重要的特性:

  1. 單根性:
    單根性指的是,一個類只能有一個父類,所以我們說,類是單繼承的, 誰是多繼承的?介面(接口),介面才能多繼承。
  2. 傳遞性:
    子類可以使用父類的成員,一個類繼承了一個父類,繼承了屬性和方法,沒有繼承Field(欄位/字段)。

子類並沒有繼承父類的構造函數,而是會默認調用父類的那個無參數的構造函數。

子類為什麼調用父類的構造函數?

因為子類最終要使用父類的成員,父類沒有物件(對象)的話,你能訪問他的成員嗎?不能,所以子類會先在內部會先創建父類的物件(對象),當無參的構造函數沒有了,還能創建嗎?

解決這個問題有兩個辦法:

  1. 父類再加一個無參的構造函數
  2. 在子類中調用父類的構造函數,使用關鍵字base

Code-繼承複習-程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
namespace 繼承
{
    //把Student&Teacher相同的代碼提出來成父類
    public class Person
    {
        public Person(string name, int age, char gender)
        {
            this.Name = name;
            this.Age = age;
            this.Gender = gender;
        }

        public string Name { get; set; } //自動屬性
        public int Age { get; set; }
        public char Gender { get; set; }

        public void CHLSS()
        {
        }
    }

    //子類
    public class Student : Person
    {
        //父類沒有無參的構造函數會報錯,
        //解決這個問題有兩個方法:1.父類加上無參的構造函數
        //2.在子類中調用父類的構造函數,使用關鍵字base
        public Student(string name, int age, char gender, int id) 
            : base(name, age, gender)
        {
            this.ID = id;
        }

        public int ID { get; set; }
    }
    public class Teacher : Person
    {
        //在子類中調用父類的構造函數,使用關鍵字base
        public Teacher(string name, int age, char gender, decimal salary)
            : base(name, age, gender)
        {
            this.Salary = salary;
        }
        public decimal Salary { get; set; }
    }
}

https://www.bilibili.com/video/BV1vG411A7my?p=30

This post is licensed under CC BY 4.0 by the author.