c#中虛函數的實際用法是什麼?c#中虛函數的實際用法
回答
從here:
在面向對象的編程中, 虛擬功能或者虛擬方法是 的函數或方法,其行爲 可以在繼承 類內由函數具有相同 被覆蓋簽名。
像任何其他語言..當你想多態。這有很多的用法。例如,您想要抽象從控制檯或文件或其他設備讀取輸入的方式。你可以有一個通用的閱讀器接口,然後是使用虛擬函數的多個具體實現。
例如代理方法。即在運行時重寫方法。例如,NHibernate使用它來支持延遲加載。
例如,您有一個基類Params和一組派生類。您希望能夠對存儲從params派生的所有可能的類的數組執行相同的操作。
沒問題 - 聲明虛方法,向派生類中添加一些基本實現,並在派生類中重寫它。現在,您可以遍歷數組並通過引用調用該方法 - 將調用正確的方法。
class Params {
public:
virtual void Manipulate() { //basic impl here }
}
class DerivedParams1 : public Params {
public:
override void Manipulate() {
base.Manipulate();
// other statements here
}
};
// more derived classes can do the same
void ManipulateAll(Params[] params)
{
for(int i = 0; i < params.Length; i++) {
params[i].Manipulate();
}
}
它用來告訴派生類,該函數可以被覆蓋。
MSDN有個很好的例子here。
基本上虛擬成員允許你表示多態,派生類可以擁有與其基類中的方法具有相同簽名的方法,並且基類將調用派生類的方法。
一個基本的例子:
public class Shape
{
// A few example members
public int X { get; private set; }
public int Y { get; private set; }
public int Height { get; set; }
public int Width { get; set; }
// Virtual method
public virtual void Draw()
{
Console.WriteLine("Performing base class drawing tasks");
}
}
class Circle : Shape
{
public override void Draw()
{
// Code to draw a circle...
Console.WriteLine("Drawing a circle");
base.Draw();
}
}
class Rectangle : Shape
{
public override void Draw()
{
// Code to draw a rectangle...
Console.WriteLine("Drawing a rectangle");
base.Draw();
}
}
class Triangle : Shape
{
public override void Draw()
{
// Code to draw a triangle...
Console.WriteLine("Drawing a triangle");
base.Draw();
}
}
所以基本上,如果你的祖先類,你要的方法的某些行爲。如果你的後代使用相同的方法,但有不同的實施,你可以覆蓋它,如果它有一個虛擬關鍵字。
using System;
class TestClass
{
public class Dimensions
{
public const double pi = Math.PI;
protected double x, y;
public Dimensions()
{
}
public Dimensions (double x, double y)
{
this.x = x;
this.y = y;
}
public virtual double Area()
{
return x*y;
}
}
public class Circle: Dimensions
{
public Circle(double r): base(r, 0)
{
}
public override double Area()
{
return pi * x * x;
}
}
class Sphere: Dimensions
{
public Sphere(double r): base(r, 0)
{
}
public override double Area()
{
return 4 * pi * x * x;
}
}
class Cylinder: Dimensions
{
public Cylinder(double r, double h): base(r, h)
{
}
public override double Area()
{
return 2*pi*x*x + 2*pi*x*y;
}
}
public static void Main()
{
double r = 3.0, h = 5.0;
Dimensions c = new Circle(r);
Dimensions s = new Sphere(r);
Dimensions l = new Cylinder(r, h);
// Display results:
Console.WriteLine("Area of Circle = {0:F2}", c.Area());
Console.WriteLine("Area of Sphere = {0:F2}", s.Area());
Console.WriteLine("Area of Cylinder = {0:F2}", l.Area());
}
}
編輯:問題在評論
如果我不使用基類的虛關鍵字,它是否行得通呢?
如果在後代類中使用override
關鍵字,則不起作用。您將生成編譯器錯誤CS0506'function1':由於未標記爲「virtual」,「abstract」或「override」,因此無法覆蓋繼承的成員'function2'
如果您不使用覆蓋您將獲得CS0108警告'desc.Method()'隱藏繼承的成員'base.Method()'如果隱藏的目的是使用新的關鍵字。
要解決這個問題,請將new
關鍵字放在您正在使用的方法之前隱藏。
例如
new public double Area()
{
return 2*pi*x*x + 2*pi*x*y;
}
..是否必須重寫派生類中的虛方法?
不,如果你不重寫方法,後代類將使用它繼承的方法。
如果我在基類中不使用virtual關鍵字,該怎麼辦?它會起作用嗎?在推導類中重寫虛方法是否強制? – Preeti 2010-08-20 08:16:54
@Pre我已經在評論中回答了您的問題 – 2010-08-20 12:11:57
這允許實現遲綁定,這意味着在運行時而不是在編譯時確定哪個對象的成員將被調用。見Wikipedia。
理解虛擬函數實際用法的關鍵是要記住,某個類的對象可以被賦予從第一個對象的類派生的類的另一個對象。
例如爲:
class Animal {
public void eat() {...}
}
class FlyingAnimal : Animal {
public void eat() {...}
}
Animal a = new FlyingAnimal();
的Animal
類具有如下功能:eat()
,其通常描述了一種動物應如何吃(例如放入口中的對象和吞)。
但是,FlyingAnimal
類應該定義一個新的eat()
方法,因爲飛行動物有特定的飲食方式。
這樣說到這裏介意的問題是:我宣佈Animal
類型的變量a
和asigned它FlyingAnimal
類型的新對象,什麼都會做a.eat()
後?這兩種方法中的哪一種被稱爲?
這裏的答案是:因爲a
是Animal
,它會調用Animal
的方法。編譯器是愚蠢的,不知道你打算將另一個類的對象指定給a
變量。
這裏是關鍵字virtual
的作用:如果你聲明方法爲virtual void eat() {...}
,你基本上是告訴編譯器「小心我在這裏做了一些聰明的事情,你不能處理,因爲你不聰明」。所以編譯器不會試圖將呼叫a.eat()
鏈接到兩種方法中的任何一種,而是它告訴系統在運行時在運行時!
因此,只有代碼執行時,系統會看a
的內容類型沒有在其聲明的類型和執行FlyingAnimal
的方法。
你可能會問:爲什麼我會想這麼做?爲什麼不從一開始就說對了FlyingAnimal a = new FlyingAnimal()
?
其原因是,例如,你可以有很多派生類從Animal
:FlyingAnimal
,SwimmingAnimal
,BigAnimal
,WhiteDog
等。在一個點要定義包含許多Animal
秒的世界,所以你說:
Animal[] happy_friends = new Animal[100];
我們有100只快樂動物世界。 你在某些時候對它們進行初始化:
...
happy_friends[2] = new AngryFish();
...
happy_friends[10] = new LoudSnake();
...
,並在一天結束時,你要讓大家吃的時候,睡覺前。所以你想說:
for (int i=0; i<100; i++) {
happy_friends[i].eat();
}
所以,你可以看到,每個動物都有自己的吃法。只有使用虛擬函數才能實現此功能。否則,每個人都將被迫以完全相同的方式「吃飯」:如Animal
類中最常用的eat
函數中所述。
編輯: 此行爲實際上是默認在常見的高級語言,如Java。
在c#使用的虛擬函數
虛擬功能大多用於覆蓋在派生類的基類的方法具有相同簽名。
當派生類繼承基類時,派生類的對象是對派生類或基類的引用。
虛擬函數是由編譯器晚解決(即運行時綁定)
在基類virtual
,最派生的類的實現的功能根據所提到的實際對象的類型被稱爲,而不管指針或引用的聲明類型如何。如果它不是virtual
,則該方法被解析爲early
,並且根據所聲明的指針或引用的類型選擇調用的函數。
- 1. C++虛函數的實現?
- 2. 從C++中的虛析構函數調用虛擬方法
- 3. 使用虛函數的C++
- 4. C++中的虛函數
- 5. C++中的虛函數
- 6. 虛函數(C++)
- 7. 虛函數C++
- 8. C++:在非虛函數中使用純虛函數
- 9. C++ - 繼承虛函數實現
- 10. 虛擬函數的用法
- 11. C# - 將字符串(包含方法或函數)轉換爲C#中的實際函數或方法#
- 12. PHP中函數metaphone()和soundex()的實際用法是什麼?
- 13. swift中嵌套函數的實際用法是什麼?
- 14. 如何更改傳遞給C中函數的實際參數?
- 15. C++調用從虛函數
- 16. C++ - 純虛函數
- 17. 虛擬函數C++
- 18. 虛擬函數C#
- 19. C++純虛函數
- 20. 函數調用與實際的代碼
- 21. C中的函數指針實際上是如何工作的?
- 22. 如何使用虛函數在C++中實現多態行爲?
- 23. C#實際使用
- 24. 虛函數中的默認參數C++
- 25. 構造函數中的C++調用虛擬方法
- 26. PHP函數實際PARAMS
- 27. PHP函數實際上
- 28. 在非純虛函數中使用純虛函數的C++抽象類
- 29. 改變在C#中的實際參數
- 30. Jasmine:用函數參考後調用spyOn後的實際函數
「,基類將調用派生類的方法。」這是一個令人困惑的聲明與示例代碼配對;該文本指示base.Draw將導致派生類Draw方法被調用(這將導致StackOverflowException,我認爲)。我明白你的觀點,但新人可能不會。這樣的示例代碼確實很好,運行它將清楚地顯示發生了什麼。 – 2009-06-30 07:23:00