【C#基礎概念】虛方法virtual


目錄:

    • 一、虛方法的概念
    • 二、虛方法的特點
    • 三、虛方法的作用
    • 四、虛方法的聲明
    • 五、虛方法的執行
    • 六、虛擬類的規則

一、虛方法的概念

在C#中,虛方法就是可以被子類重寫的方法,如果子類重寫了虛方法,則在運行時將運行重寫的邏輯;如果子類沒有重寫虛方法,則在運行時將運行父類的邏輯。虛函數在編譯期間是不被靜態編譯的,它的相對地址是不確定的,它會根據運行時期對象實例來動態判斷要調用的函數,其中那個申明時定義的類叫申明類,那個執行時實例化的類叫實例類。虛方法是用virtual關鍵字聲明的

A a = new B(); 其中A是申明類,B是實例類。

 

二、虛方法的特點

  1. 虛方法前不允許有static,abstract,或override修飾符(因為靜態的方法和抽象方法不能重寫)
  2. 虛方法不能是私有的(因為在子類中要進行重寫),所以不能使用private修飾符
  3. 不能在聲明虛方法的同時指定重寫虛方法,因為重寫方法只能重寫基類的虛方法,也就是要提前在基類中聲明虛方法,所以virtual關鍵字和override關鍵字不能同時使用。

三、虛方法的作用

  1. 允許派生類(即其子類)對父類進行擴展。
  2. 虛方法是多態特性的一種體現。
  3. 增加開發過程中的可維護性,條理清晰明了。

四、虛方法的聲明

在父類中:

1
2
3
4
public virtual 返回類型 方法名()
{
    方法體;
}

在子類中:

1
2
3
4
5
public override 返回值類型 方法名()
{
    base.父類方法;
    方法體;
}

五、虛方法的執行

一般方法在編譯時就靜態地編譯到了執行文件中,其相對地址在程序運行期間是不發生變化的,也就是寫死了的!

虛函數在編譯期間是不被靜態編譯的,它的相對地址是不確定的,它會根據運行時期對象實例來動態判斷要調用的函數。

具體的檢查流程如下:

  1. 當調用一個對象的方法時,系統會直接去檢查這個對象申明定義的類,即申明類,看所調用的方法是否為虛方法。
  2. 如果不是虛函數,那么它就直接執行該函數。如果有virtual關鍵字,也就是一個虛方法,那么這個時候它就不會立刻執行該函數了,而是轉去檢查對象的實例類。
  3. 在這個實例類里,它會檢查這個實例類的定義中是否有實現該虛方法(通過new關鍵字)或是否有重新實現該虛方法(通過override關鍵字),如果有,那么OK,它就不會再找了,而馬上執行該實例類中的這個重新實現的方法。而如果沒有的話,系統就會不停地往上找實例類的父類,並對父類重復剛才在實例類里的檢查,直到找到第一個重載了該虛方法的父類為止,然后執行該父類里重載后的方法。

下面我們通過具體實例看看:
例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    class A
    {
        public virtual void Getreturn()
        {
            Console.WriteLine("我是A類的虛方法");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            A a = new A();//定義一個a這個A類的對象,這個A就是a的申明類,實例化a對象,A是a的實例類
            a.Getreturn();
            Console.ReadLine();
        }
    }

過程:1.先檢查申明類A 2.檢查到是Getreturn是虛擬方法 3.轉去檢查實例類A,結果是它本身 4.執行實例類A中實現Getreturn的方法 5.輸出結果我是A類的虛方法

例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    class A
    {
        public virtual void Getreturn()
        {
            Console.WriteLine("我是A類的虛方法");
        }
    }
    class B : A
    {
        public override void Getreturn() //重新實現了虛方法
        {
            Console.WriteLine("我是B類重寫后的方法");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            A a = new B();//定義一個a這個A類的對象,這個A就是a的申明類,實例化a對象,B是a的實例類
            a.Getreturn();
            Console.ReadLine();
        }
    }

過程:1.先檢查申明類A 2.檢查到是虛擬方法 3.轉去檢查實例類B,有重寫的方法 4.執行實例類B中的方法 5.輸出結果我是B類重寫后的方法

例3:

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
    class A
    {
        public virtual void Getreturn()
        {
            Console.WriteLine("我是A類的虛方法");
        }
    }
    class B : A
    {
        public override void Getreturn() //重新實現了虛方法
        {
            Console.WriteLine("我是B類重寫后的方法");
        }
    }
    class C : B
    {
   
    }
    class Program
    {
        static void Main(string[] args)
        {
            A a = new C();//定義一個a這個A類的對象,這個A就是a的申明類,實例化a對象,C是a的實例類
            a.Getreturn();
            Console.ReadLine();
        }
    }

過程:1.先檢查申明類A 2.檢查到是虛擬方法 3.轉去檢查實例類C,無重寫的方法 4.轉去檢查類C的父類B,有重寫的方法5.執行父類B中的Getreturn方法 6.輸出結果我是B類重寫后的方法

例4:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    class A
    {
        public virtual void Getreturn()
        {
            Console.WriteLine("我是A類的虛方法");
        }
    }
    class B : A
    {
        public new void Getreturn() //覆蓋父類里的同名函數,而不是重新實現  
        {
            Console.WriteLine("我是B類New方法");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            A a = new B();//定義一個a這個A類的對象,這個A就是a的申明類,實例化a對象,B是a的實例類
            a.Getreturn();
            Console.ReadLine();
        }
    }

過程:1.先檢查申明類A 2.檢查到是虛擬方法 3.轉去檢查實例類B,無重寫的(這個地方要注意了,雖然B里有實現Getreturn(),但沒有使用override關鍵字,所以不會被認為是重寫) 4.轉去檢查類B的父類A,就是它本身 5.執行父類A中的Getreturn方法 6.輸出結果我是A類的虛方法

例5:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    class A
    {
        public virtual void Getreturn()
        {
            Console.WriteLine("我是A類的虛方法");
        }
    }
    class B : A
    {
        public new void Getreturn() //覆蓋父類里的同名函數,而不是重新實現  
        {
            Console.WriteLine("我是B類New方法");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            B b = new B();//定義一個b這個B類的對象,這個B就是b的申明類,實例化b對象,B是b的實例類
            b.Getreturn();
            Console.ReadLine();
        }
    }

過程:1.先檢查申明類B 2.檢查到不是虛擬方法 3.執行B類里的Getreturn() 4.輸出結果我是B類New方法

可以使用抽象方法重寫基類中的虛方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    class A
    {
        public virtual void Getreturn()
        {
            Console.WriteLine("A類的虛方法");  
        }  
    }
    abstract class B : A    
    {
        public abstract override void Getreturn();//使用override修飾符,表示抽象重寫了基類中該函數的實現
    }
    abstract class C : A
    {
        public abstract new void Getreturn();//使用new修飾符顯式聲明,表示隱藏了基類中該函數的實現
    }

密封類可以重寫基類中的虛方法(基類中的虛方法將隱式的轉化為非虛方法,但密封類本身不能再增加新的虛方法)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    class A
    {
        public virtual void Getreturn()
        {
            Console.WriteLine("A類的虛方法");
        }
    }
    sealed class Program:A
    {
        public override void Getreturn()
        {
            Console.WriteLine("Program類重寫后的方法");
        }
        static void Main(string[] args)
        {
            Program p = new Program();
            p.Getreturn();
            Console.ReadLine();
        }
    }

 虛方法和new

new關鍵用於隱藏父類的成員,所有可以用new關鍵字隱藏父類的虛擬方法。

abstract和虛擬方法

 抽象方法是隱式的虛擬方法,所有抽象類的非抽象子類可以用new 和override關鍵來重寫abstract 方法


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM