【原創】C#中級教程學習筆記002-面向對象編程

 其他路徑:

CSDN: https://blog.csdn.net/wodehao0808

微信公衆號:程序喵星人

 

更多資源和視頻教程,QQ:1902686547

 

2. 面向對象編程

        面向對象編程也叫做OOP編程。

        簡單來說面向對象編程就是結構化編程,對程序中的變量結構劃分,讓編程更清晰。

2.1 類和對象

2.1.1 類

        類實際上是創建對象的模板,每個對象都包含數據集合,並提供了處理和訪問數據的方法。

        類定義了類的每個對象(稱爲實例)可以包含什麼數據和功能。

        類中的數據和函數稱爲類的成員。

                數據成員

                函數成員

        數據成員:

                數據成員是包含類的數據--字段,常量和事件的成員。

        函數成員:

                函數成員提供了操作類中數據的某些功能。(方法,屬性,構造方法和終結器(析構方法),運算符,和索引器)。

         字段的聲明

                訪問修飾符 類型 字段名稱;

        方法的聲明

                訪問修飾符 返回值類型 方法名稱(參數)

                {

                        //方法體

                }

2.1.2 對象

        類創建的變量叫做對象。

        實例化一個對象:

                ClassName myClass = new ClassName();

        其中ClassName是我們定義的類的名字,myClass是我們聲明的變量(對象)的名字,後面的new是一個關鍵字,使用new 加上類型名()表示對該對象進行構造,如果不進行構造的話,這個對象是無法使用的。

2.1.3 Example: 類和對象

2.1.3.1 Customer.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

 

namespace Lesson_2_1

{

    // 定義一個新的類型(類):Customer

    class Customer

    {

        // 字段,數據成員

        public string name;

        public string address;

        public int age;

        public string buyTime;

 

        // 方法,函數成員

        public void Show()

        {

            Console.WriteLine("名字:" + name);

            Console.WriteLine("年齡:" + age);

            Console.WriteLine("地址:" + address);

            Console.WriteLine("購買時間:" + buyTime);

        }

    }

}

2.1.3.2 Program.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

 

// 類和對象

 

namespace Lesson_2_1

{

    class Program

    {

        static void Main(string[] args)

        {

            // 如果要使用一個類的話,要先引入它所在的命名空間;

            // 因爲Customer位於當前的命名空間下,所以不需要引入,就可以直接使用Customer類;

            Customer ctm;  // 使用 Customer 模板,聲明瞭一個變量(對象)

            ctm = new Customer();  // 對象初始化

            ctm.name = "張三";

            Console.WriteLine("ctm對象的name = " + ctm.name);

            ctm.Show();  // 調用對象的方法

 

            Console.ReadKey();

        }

    }

}

2.2 類的定義和聲明

        定義一個車輛(Vehicle)類,具有Run、Stop等方法,具有Speed(速度)、MaxSpeed(最大速度)、Weight(重量)等域(也叫做字段)。

        定義一個向量(Vector3)類,裏面有x,y,z三個字段,有取得長度的方法,有設置屬性(Set)的方法。

2.2.1 Example: 類的定義和聲明

2.2.1.1 Vehicle.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

 

namespace Lesson_2_2

{

    class Vehicle

    {

        public float speed;

        public float maxSpeed;

        public float weight;

 

        public void Run()

        {

            Console.WriteLine("這輛車正在以 {0}m/s 的速度行駛", speed);

        }

 

        public void Stop()

        {

            speed = 0;  // 車子停下來

            Console.WriteLine("這輛車已經停止了,當前速度是:" + speed);

        }

    }

}

2.2.1.2 Vector3.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

 

namespace Lesson_2_2

{

    class Vector3

    {

        public float x, y, z;

 

        public float GetLength()

        {

            return (float)Math.Sqrt(x * x + y * y + z * z);

        }

    }

}

2.2.1.3 Vector3_2.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

 

namespace Lesson_2_2

{

    class Vector3_2

    {

        // 一般情況下,都是將字段設爲 private 權限

        // private: 可以在類內部訪問,但不可以在外部通過對象直接訪問

        private float _fX, _fY, _fZ;

 

        // 通過提供公有方法去改變私有字段的值

        public void SetX(float p_fX)

        {

            _fX = p_fX;

        }

 

        public void SetY(float p_fY)

        {

            _fY = p_fY;

        }

 

        public void SetZ(float p_fZ)

        {

            _fZ = p_fZ;

        }

 

        public float GetLength()

        {

            return (float)Math.Sqrt(_fX * _fX + _fY * _fY + _fZ * _fZ);

        }

    }

}

2.2.1.4 Program.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

 

// 類的定義和聲明

 

namespace Lesson_2_2

{

    class Program

    {

        static void Main(string[] args)

        {

            // 車輛

            Vehicle vh = new Vehicle();

            vh.speed = 60;

            vh.Run();

            vh.Stop();

 

            // 向量Vector3

            Vector3 vec = new Vector3();

            vec.x = 1;

            vec.y = 1;

            vec.z = 1;

            Console.WriteLine("向量Vector3的長度 = " + vec.GetLength());

 

            // 向量Vector3_2

            Vector3_2 vec2 = new Vector3_2();

            // vec2._fX = 1;  // private字段,不能在類外部通過對象直接訪問

            // vec2._fY = 1;

            // vec2._fZ = 1;

            vec2.SetX(1);

            vec2.SetY(1);

            vec2.SetZ(1);

            Console.WriteLine("向量Vector3_2的長度 = " + vec2.GetLength());

 

            Console.ReadKey();           

        }

    }

}

2.3 構造函數

        構造函數就是用於初始化數據的函數。

        聲明基本的構造函數的語法就是聲明一個和所在類同名的方法,但是該方法沒有返回類型。

        public class MyClass

        {

                public MyClass()  // 構造函數

                {

                        這個構造函數的函數體

                }

        }

        當我們使用new關鍵字創建類的時候,就會調用構造方法。

        我們一般會使用構造方法進行初始化數據的一些操作。

        構造函數可以進行重載,跟普通函數重載是一樣的規則。

        注意:

                當我們不寫,任何構造函數的時候,編譯器會提供給我們一個默認的 無參的構造函數,但是如果我們定義了一個或者多個構造函數,編譯器就不會再提供默認的構造函數。

2.3.1 Example:構造函數

2.3.1.1 Vector3.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

 

namespace Lesson_2_3

{

    class Vector3

    {

        private float _fX, _fY, _fZ;

 

        // 當我們聲明一個構造函數後,編譯器不會再爲我們提供一個默認的構造函數了

        public Vector3()

        {

            Console.WriteLine("這是一個無參的構造函數");

        }

 

        // 構造函數重載

        public Vector3(float p_fX, float p_fY, float p_fZ)

        {

            Console.WriteLine("這是一個有參的構造函數");

            this._fX = p_fX;  // 也可以 _fX = p_fX;

            this._fY = p_fY;  // 也可以 _fY = p_fY;

            this._fZ = p_fZ;  // 也可以 _fZ = p_fZ;

            // this 就是調用該方法的對象

        }

 

        public float GetLength()

        {

            // this 就是調用該方法的對象

            return (float)Math.Sqrt(this._fX * this._fX + this._fY * this._fY + this._fZ * this._fZ);

        }

 

        public void SetX(float p_fX)

        {

            this._fX = p_fX;

        }

 

        public void SetY(float p_fY)

        {

            this._fY = p_fY;

        }

 

        public void SetZ(float p_fZ)

        {

            this._fZ = p_fZ;

        }

    }

}

2.3.1.2 Program.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

 

// 構造函數

 

namespace Lesson_2_3

{

    class Program

    {

        static void Main(string[] args)

        {

            // 使用無參構造函數

            Vector3 vec = new Vector3();

            vec.SetX(1);

            vec.SetY(1);

            vec.SetZ(1);

            Console.WriteLine("無參構造函數,向量長度 = " + vec.GetLength());

 

            // 有參構造函數

            Vector3 vec2 = new Vector3(1, 1, 1);  // 可以發現,使用有參構造函數,可以對字段進行初始化;構造函數的主要作用,也是用於初始化數據;

            Console.WriteLine("有參構造函數,向量長度 = " + vec2.GetLength());

 

            Console.ReadKey();

        }

    }

}

2.4 屬性的定義

2.4.1 屬性的定義

        屬性的定義結構:

        public int MyIntProp{

                get{

                        // get code

                }

                set{

                        //set code

                }

        }

        1,定義屬性需要名字和類型

        2,屬性包含兩個塊 get塊和set塊

        3,訪問屬性和訪問字段一樣。當取得屬性的值的時候,就會調用屬性中的get塊,所以get塊,需要一個返回值,返回值的類型就是屬性的類型;當我們去給屬性設置值的時候,就會調用屬性中的set塊,我們可以在set塊中通過value訪問到我們設置的值。

2.4.2 只讀或只寫屬性

        private string name;

        public string name{

               get{

                      return name;

               }

        }

        屬性可以只提供一個set塊或者get塊。

        只讀:只提供 get 塊。

        只寫:只提供 set 塊。

2.4.3 屬性的訪問修飾符

        public string name{

               get{

                      return name;

               }

            // private 修改了屬性的訪問權限

               private set{ 

                      name = value;

               }

        }

2.4.4 自動實現的屬性

        public int Age{get;set;}

        編譯器會自動創建private int age字段。

2.4.5 Example:屬性的定義

2.4.5.1 Vector3.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

 

namespace Lesson_2_4

{

    class Vector3

    {

        // C#一般把字段定義爲private,然後通過屬性訪問和修改字段值

        private float _fX, _fY, _fZ;

 

        // 屬性

        public float X  // 屬性和函數,一般都是使用大寫字母開頭

        {

            get { return _fX; }  // get塊中的返回值類型,需要跟屬性類型保持一致

            set { _fX = value; }  // set塊中,默認變量value,訪問我們設置的值

        }

 

        public float Y

        {

            get { return _fY; }

            set { _fY = value; }

        }

 

        public float Z

        {

            get { return _fZ; }

            set { _fZ = value > 0 ? value : 0; }  // 增加修改保護,例如銀行餘額不能負數等

        }

 

        public Vector3()

        {

        }

 

        public Vector3(float p_fX, float p_fY, float p_fZ)

        {

            X = p_fX;  // 使用屬性的set塊,修改對應字段的值

            Y = p_fY;

            Z = p_fZ;

        }

 

        public float GetLength()

        {

            return (float)Math.Sqrt(X * X + Y * Y + Z * Z);  // 使用屬性的get塊,獲得對應的值

        }

 

        // 只讀屬性

        private int _iNum = 10;

        public int Num

        {

            get { return _iNum; }

            // 沒有set塊,表示這個屬性是隻讀的

        }

 

        // 只寫屬性

        private int _iCount;

        public int Count

        {

            set { _iCount = value; Console.WriteLine("Count寫入的值是:" + value); }

            // 沒有get塊,表示這個屬性是隻寫的

        }

 

        // 屬性的訪問修飾符

        private string _strName;

        public string Name

        {

            get { return _strName; }

            private set { _strName = value; }  // private 修飾符,表示set塊是隻能在類內部調用,外部無效

        }

        public void SetName(string p_strName)

        {

            Name = p_strName;  // 類內部,可以使用屬性Name的set塊

        }

 

        // 自動實現的屬性

        public string School { get; set; }  // 編譯器,會自動爲 屬性School 生成相對應的字段 private string school;

    }

}

2.4.5.2 Program.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

 

// 屬性

 

namespace Lesson_2_4

{

    class Program

    {

        static void Main(string[] args)

        {

            Vector3 vec = new Vector3(1, 1, 1);

            Console.WriteLine("vec的x是:" + vec.X);

            Console.WriteLine("vec的y是:" + vec.Y);

            Console.WriteLine("vec的z是:" + vec.Z);

            Console.WriteLine("vec的長度是:" + vec.GetLength());

 

            // 只讀

            // vec.Num = 10; // 無法通過屬性設置值,因爲屬性是隻讀的,沒有set塊

            Console.WriteLine("vec的只讀屬性:" + vec.Num);

 

            // 只寫

            // int i = vec.Count;  // 無法通過屬性讀取屬性值,因爲屬性是隻寫的,沒有get塊

            vec.Count = 100;

 

            // 屬性的訪問權限

            // vec.Name = "張三";  // 無法通過屬性設置值,因爲屬性的 set塊 的權限是private,外部無法直接訪問

            vec.SetName("張三");  // 通過額外的函數,在函數中(類內部)去訪問該屬性的 set塊(private權限)

            Console.WriteLine("vec的name是:" + vec.Name);

 

            // 自動實現的屬性

            vec.School = "中學";

            Console.WriteLine("vec的shcool是:" + vec.School);

 

            Console.ReadKey();

        }

    }

}

2.5 匿名類型

        我們創建變量(對象的時候),必須指定類型,其實我們也可以不去指定類型,這個就是匿名類型,我們可以使用var聲明一個匿名類型。

        使用var聲明的匿名類型,當初始化的時候,這個變量的類型就被確定下來,並且以後不可以修改。

                var var1 = 34;

2.5.1 Example:匿名類型

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

 

// 匿名類型

 

namespace Lesson_2_5

{

    class Program

    {

        static void Main(string[] args)

        {

            // 使用 var 聲明匿名類型

            var v1 = 12;  // 根據初始化的值,推導出v1的類型;類型確定後,就不能更改

            //v1 = "張三";  // v1的類型,已經推導確定了,不能再更改

            var pi = 3.14;

            var name = "張三";

 

            Console.WriteLine("請輸入:");

            var s = Console.ReadLine();

 

            Console.WriteLine("v1 = " + v1);

            Console.WriteLine("pi = " + pi);

            Console.WriteLine("name = " + name);

            Console.WriteLine("s = " + s);

 

            Console.ReadKey();

        }

    }

}

2.6 堆和棧

        堆和棧 : 程序運行時的內存區域。

        我們把內存分爲 堆空間 和 棧空間。

        棧空間 比較小,但是讀取速度快。

        堆空間 比較大,但是讀取速度慢。

2.6.1 棧

        棧的特徵:

               數據只能從棧的頂端插入和刪除。

        把數據放入棧頂稱爲入棧(push)。

        從棧頂刪除數據稱爲出棧(pop)。

 

 

 

2.6.2 堆

        堆是一塊內存區域,與棧不同,堆裏的內存能夠以任意順序存入和移除。

 

 

 

2.6.3 GC垃圾回收

        GC Garbage Collector垃圾回收器。

        CLR的GC就是內存管理機制,我們寫程序不需要關心內存的使用,因爲這些都是CLR幫我們做了。

 

 

 

2.6.4 值類型和引用類型

        類型被分爲兩種:值類型(整數,bool struct char 小數等) 和 引用類型(string 數組 自定義的類,內置的類等)。

        值類型只需要一段單獨的內存,用於存儲實際的數據,(單獨定義的時候放在棧中)。

        引用類型需要兩段內存:

               第一段存儲實際的數據,它總是位於堆中。

               第二段是一個引用,指向數據在堆中的存放位置。

 

 

  

        當我們使用引用類型賦值的時候,其實是賦值給引用類型的引用(即在堆中的地址)。

         如果數組是一個值類型的數組,那麼數組中直接存儲值。如果是一個引用類型的數組(數組中存儲的是引用類型),那麼數組中存儲的是引用(內存地址)。

2.6.4.1 Example:值類型和引用類型
2.6.4.1.1 Vector3.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

 

namespace Lesson_2_6

{

    class Vector3

    {

        public float x, y, z;

    }

}

2.6.4.1.2 Program.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

 

// 值類型和引用類型

 

namespace Lesson_2_6

{

    class Program

    {

        static void Main(string[] args)

        {

            Test1();

            Test2();

            Test3();

            Test4();

            Test5();

 

            Console.ReadKey();

        }

 

        static void Test1()

        {

            int i = 34;     // 值類型,在棧中存儲值:34

            int j = 34;     // 值類型,在棧中存儲值:34

            int temp = 34;  // 值類型,在棧中存儲值:34

            char c = 'a';   // 值類型,在棧中存儲值:a

            bool b = true;  // 值類型,在棧中存儲值:true110

        }

 

        static void Test2()

        {

            int i = 34;   // 值類型,在棧中存儲值:34

            int j = 234;  // 值類型,在棧中存儲值:34

            string name = "my";  // 引用類型,在堆中存儲值:my;在棧中存儲(即name的值):my在堆中的地址。

        }

 

        static void Test3()

        {

            string name = "my";

            string name2 = "you";

            name = name2;    // name保存:you在堆中的地址

            name = "baidu";  // name保存:baidu在堆中的地址

            Console.WriteLine("name = {0}, name2 = {1}", name, name2);  

        }

 

        static void Test4()

        {

            Vector3 v = new Vector3();  // v指向堆1

            v.x = 100;

            v.y = 100;

            v.z = 100;

            Vector3 v2 = new Vector3();  // v2指向堆2

            v2.x = 200;

            v2.y = 200;

            v2.z = 200;

            v2 = v;  // v2指向堆1

            v2.x = 300;  // 將堆1中的變量x的值改爲300

            Console.WriteLine("v.x = " + v.x);  // v也是指向堆1的,所以,輸出的值是 300

        }

 

        static void Test5()

        {

            // 如果數組是一個值類型的數組,那麼數組中直接存儲值;

            // 如果數組是一個引用類型的數組(數組中存儲的是引用類型),MAME數組中存儲的是引用(即內存地址)

            Vector3[] vArray = new Vector3[] { new Vector3(), new Vector3(), new Vector3() };

            Vector3 v1 = vArray[0];  // v1指向堆1

            vArray[0].x = 100;  // 修改堆1中的x的值

            v1.x = 200;  // 修改堆1中的x的值

            Console.WriteLine("vArray[0].x = " + vArray[0].x);  // vArray[0]是指向堆1的,所以輸出值是200

        }

    }

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章