C#多態;父類引用指向子類對象;new和override的區別;new、abstract、virtual、override,sealed關鍵字區別和使用代碼示例;c#類的初始化順序

關於父類引用指向子類對象c#

例如: 有如下2個類ide

public  class  Father
        {
            public int age = 70;                       
            public static string name = "父親";        
        }

        public class Son : Father
        {
            public int age = 30;                    
            public static string name = "兒子";    
            
        }

Father f=new Son(); 函數

這種用法叫作「父類引用指向子類對象,或者叫「父類指針指向子類對象」,指的是定義一個父類的引用,而它實際指向的是子類建立的對象。測試

好處是什麼?spa

下面作幾個測試, 指針

第一種  ,父類變量,調用 屬性  例以下面的  f.age   是一個父類的變量調用了屬性,問題是這裏的屬性是父類的?仍是子類的? 答案是父類的屬性code

class Program
    {
        static void Main(string[] args)
        {
            Father f=new Son();
            Console.WriteLine(f.age);   //這裏輸出的是父類的年齡?仍是子類的年齡? 答案是父親的年齡 70 ,由於這裏的f是個父類類型,因此是調用父類的屬性

            Son s = f as Son;
            Console.WriteLine(s.age);  //這裏輸出的父類的年齡?仍是子類的年齡? 答案是子類的年齡 30

            Console.ReadKey();
        }

        public  class  Father
        {
            public int age = 70;                      //第4執行
            public static string name = "父親";       //第3執行
        }

        public class Son : Father
        {
            public int age = 30;                    //第2執行
            public static string name = "兒子";    //第1執行
            
        }
    }

小結論(1): 當用父類的變量調用屬性的時候,取決於聲明的類型(「=」左邊是什麼類型),而不是後面實例化的類型orm

第二種 ,父類變量,調用 方法 (父類的方法和子類的方法  如出一轍,子類並沒有重寫) 對象

public  class  Father
        {
            public int age = 70;                      //第4執行
            public static string name = "父親";       //第3執行

            public void SayHi()
            {
                Console.WriteLine(string.Format("父親說,年齡{0},名字是{1}",age,name));
            }

        }

        public class Son : Father
        {
            public int age = 30;                    //第2執行
            public static string name = "兒子";    //第1執行

            public void SayHi()
            {
                Console.WriteLine(string.Format("兒子說,年齡{0},名字是{1}", age, name));
            }
        }

 

static void Main(string[] args)
        {
            
            Father f = new Son();
            f.SayHi();   //這裏調用的是父類的方法,由於f是父類,而且子類,壓根就沒有重寫   父親說,年齡是70,名字是父親

            Son s = f as Son;
            s.SayHi();   //這裏調用的是父類的方法?仍是子類的方法?  答案是子類的方法,由於s是子類   兒子說,年齡是30,名字是兒子
            Console.ReadKey();
        }

小結論(2): 當子類和父類的方法徹底相同時,調用的時候取決於聲明的類型(「=」左邊),而不是後面實例化的類型。blog

第三種 ,父類變量,調用 方法 (父類的方法和子類的方法 如出一轍 ,可是父類的方法加 Virtual , 子類不重寫)

image

小結論(3):若是父類有virtual虛方法,可是子類並無重寫的話,那麼  同上面的小結論(2)同樣,調用的時候,取決於聲明的類型(「=」的左邊),而不是實例化的類型

第四種 ,父類變量,調用 方法 (父類的方法和子類的方法 如出一轍 ,可是父類的方法加 Virtual , 子類重寫)

image

小結論(4):重寫之後,調用哪一個類的方法取決於實例化的類型(「=」右邊)或者是轉換後最終的類型

第五種 ,父類變量,調用 方法 (父類的方法和子類的方法 如出一轍 ,可是父類的方法加 Virtual , 子類重寫)

父類變量指向子類的實例,可是咱們直接調用父類變量下的屬性,會輸出子類的屬性?仍是父類的屬性?答案是父類的屬性.

那若是再繼續調用方法的話,是調用父類的方法?仍是子類的方法?答案是,若是是虛方法,子類有重寫,就調用子類的,子類沒有重寫,就調用父類的.

image

小結論(5) : 若是子類方法裏面想調用父類的屬性或者是方法,使用 base 關鍵字

 

結論:

1:當用父類的變量調用屬性的時候,取決於聲明的類型(「=」左邊是什麼類型),而不是後面實例化的類型

例如 輸出 f.age 就是輸出父類的屬性 ,而不是子類的屬性

2:當子類和父類的方法徹底相同時,調用的時候取決於聲明的類型(「=」左邊),而不是後面實例化的類型。

也就是子類沒有重寫的時候. f.sayhi 就是調用的父類的sayhi ,而不是子類的sayhi

3 若是子類有重寫(override)父類的方法,那麼 父類變量調用方法的時候,就變成使用 子類的方法.

也就是子類有override的時候,f.sayhi 就是調用子類的sayhi

4:若是想在子類裏面訪問父類的屬性或者是方法,使用 base 關鍵字

 

C#中new和override的區別;abstract

當父類裏面有 virtual 方法的時候,子類可使用 override 進行重寫.  那麼  f.sayhi  就變成調用子類的sayhi

不論父類的方法有沒有virtual,子類均可以在同名的方法上加一個new表示這是子類本身的方法,那麼父類的方法就會被隱藏起來, f.sayhi 就會變成 調用父類的sayhi,由於子類並無override. 若是這個時候,把new去掉,效果也是同樣的,f.sayhi 也是調用父類的sayhi, 判斷是否調用子類的方法,就看子類是否有override重寫.

//在C#中,override和new都會覆蓋父類中的方法。那它們二者以前有什麼區別呢? //override是指「覆蓋」,是指子類覆蓋了父類的方法。子類的對象沒法再訪問父類中的該方法(固然了,在子類的方法中仍是能夠經過base訪問到父類的方法的)。

//new是指「隱藏」,是指子類隱藏了父類的方法,固然,經過必定的轉換,能夠在子類的對象中訪問父類的方法。

 

c#類的初始化順序

子類的靜態成員變量,子類的普通成員,父類的靜態成員,父類的普通成員

namespace 類的初始化順序
{
    class Program
    {
        static void Main(string[] args)
        {
            Father f=new Son();   
            Console.ReadKey();
        }

        public  class  Father
        {
                 public int age = 70;                            //第4執行
            public static string name = "父親";       //第3執行
        }

        public class Son : Father
        {
                 public int age = 30;                         //第2執行
            public static string name = "兒子";    //第1執行
            
        }
    }
}

 

首次訪問:(在此沒有顯示的寫出類中的構造方法) 順序:子類的靜態字段==》子類靜態構造==》子類非靜態字段==》父類的靜態字段==》父類的靜態構造==》父類的非靜態字段 ==》父類的構造函數==》子類的構造函數 非首次訪問:順序是同樣的,只不過少了中間靜態字段和構造的過程 對於靜態變量與靜態構造函數而言, 不管對一個類建立多少個實例,它的靜態成員都只有一個副本。 也就是說,靜態變量與靜態構造函數只初始化一次(在類第一次實例化時)

相關文章
相關標籤/搜索