C#での仮想関数の実際の使用法は何ですか? hereからCでの仮想関数の実際の使用#
答えて
:オブジェクト指向プログラミングにおいて
、 仮想関数または仮想メソッドが でその挙動 が同じで機能によって継承 クラス内でオーバーライドすることができる関数またはメソッド署名。
他の言語と同様に、多態性が必要です。これにはたくさんの使い方があります。たとえば、入力をコンソールやファイルなどのデバイスから読み取る方法を抽象化したいとします。ジェネリックリーダーインターフェイスと仮想関数を使用した複数の具体的な実装が可能です。
プロキシ方法。実行時にメソッドを上書きする。例えば、NHibernateはこれを使用して遅延ロードをサポートします。
たとえば、基本クラスParamsと派生クラスのセットがあります。 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':継承されたメンバ 'function2'を「仮想」、「抽象的な」、または「上書き」されていないためオーバーライドできません。
オーバーライドを使用しないと、 CS0108警告 'desc.Method()'は継承されたメンバー 'base.Method()を隠蔽します。隠蔽が意図されていれば、newキーワードを使用してください。
これを回避するには、方法の前にnew
というキーワードを入れて、を隠してにしてください。
new public double Area()
{
return 2*pi*x*x + 2*pi*x*y;
}
派生クラスの仮想メソッドをオーバーライドすることは必須ですか?
あなたがメソッドをオーバーライドしていない場合はNoを、子孫クラスは、それが継承されるメソッドを使用します。
これは、実行時ではなく、オブジェクトのメンバーが呼び出されます、コンパイル時に決定することを意味し、遅延バインディングを達成することができます。 Wikipediaを参照してください。
仮想関数の実用的な使用方法を理解する鍵は、特定のクラスのオブジェクトが最初のオブジェクトのクラスから派生したクラスの別のオブジェクトを割り当てることができることを心に留めておくことです。
例えば:
class Animal {
public void eat() {...}
}
class FlyingAnimal : Animal {
public void eat() {...}
}
Animal a = new FlyingAnimal();
Animal
クラスは、一般的に、動物(例えば口の中のオブジェクトを入れて飲み込む)食べるべきかを説明関数eat()
を有しています。
しかし、飛行動物には特別な食事方法があるため、FlyingAnimal
クラスには新しいeat()
メソッドを定義する必要があります。
だからここに頭に浮かぶ質問です:私はタイプAnimal
の変数a
を宣言し、それをタイプFlyingAnimal
の新しいオブジェクトをasignedた後、a.eat()
は何をしますか?どちらの方法のどちらを呼びますか?
答えはa
はAnimal
のタイプであるため、Animal
のメソッドを呼び出します。コンパイラはダムで、別のクラスのオブジェクトをa
変数に代入することは知られていません。
ここにvirtual
キーワードが現れます:メソッドをvirtual void eat() {...}
と宣言すると、基本的にはコンパイラに「賢明ではないので扱えないほど賢明なことをしています。 "したがって、コンパイラはa.eat()
という呼び出しを2つの方法のいずれかにリンクしようとしませんが、代わりに実行時にを実行するようにシステムに指示します!
だからのみのコードが実行されると、システムはa
を見てのコンテンツタイプないその宣言された型にしてFlyingAnimal
実行の方法をします。
あなたは不思議に思うかもしれません:地獄は、私はそれをしたいと思う理由は?なぜ始まりからちょうどいいと言わないのですかFlyingAnimal a = new FlyingAnimal()
?
Animal
から多くの派生クラスを持っていること、ということである
:FlyingAnimal
、SwimmingAnimal
、BigAnimal
、WhiteDog
など
Animal[] happy_friends = new Animal[100];
我々は100匹の幸せな動物で世界を持っている:そして、ある時点で、あなたが言うので、多くのAnimal
Sを含む世界を定義したいです。あなたはいくつかの点でそれらを初期化し :
...
happy_friends[2] = new AngryFish();
...
happy_friends[10] = new LoudSnake();
...
そして、一日の終わりに、あなたは彼らがスリープ状態に入る前に、誰もが食べたいです。だからあなたは言ってみたいと思う:
あなたが見ることができるように、各動物はそれ自身の食べ方を持っています。 仮想機能を使用することによってのみ、この機能を実現できます。そうでなければ、誰もが全く同じ方法で "食べる"ように強制されるでしょう:最も一般的なeat
関数に記載されているように、Animal
クラス内で機能します。
編集: この動作は、実際にはのデフォルトで、Javaなどの一般的な高級言語で行われます。 C#での仮想関数の
使用は
仮想関数はほとんど同じ署名で派生クラスの基底クラスのメソッドをオーバーライドするために使用されます。
派生クラスが基本クラスを継承する場合、派生クラスのオブジェクトは、派生クラスまたは基本クラスのいずれかへの参照です。
仮想関数が基底クラスで(つまり、実行時バインディング)の後半コンパイラによる
virtual
を解決され、機能のほとんどの派生クラスの実装は、参照されるオブジェクトの実際の型に応じて呼ばれています宣言されたポインタまたは参照の型にかかわらず。 virtual
でなければ、メソッドはearly
で解決され、呼び出された関数はポインタまたは参照の宣言された型に従って選択されます。
- 1. 仮想関数の使用
- 2. C++仮想関数の実装?
- 3. C++:非仮想関数で純粋仮想関数を使用する
- 4. 仮想関数を使用するC++
- 5. 仮想関数のリンカエラーC++
- 6. 仮想関数の実装
- 7. C++での純粋仮想関数の使用方法は?
- 8. C++での子関数で純粋仮想関数や未使用の引数
- 9. 仮想関数をリンクする際のC++の誤り
- 10. C++仮想関数とスレッド
- 11. C++(仮想)関数テーブル
- 12. 仮想関数オーバーライド仮想関数
- 13. C++の仮想関数の概念
- 14. C++ - 仮想関数の代わりにテンプレートを使用
- 15. C++仮想関数の単純な例
- 16. 仮想関数のないコマンドパターン(C++)
- 17. 仮想関数コンパイラの最適化C++
- 18. 継承クラスのC++仮想関数
- 19. C++仮想関数の問題が
- 20. C++仮想キーワードと関数のオーバーライド
- 21. C++仮想関数の出力
- 22. 仮想テンプレート関数の偽装C++
- 23. はCefRequesthandlerクラスの仮想関数C++
- 24. C++仮想関数テーブルの取得インデックス
- 25. C#での仮想メソッドの使用
- 26. C++の純粋仮想関数の実装とヘッダファイル
- 27. 純粋仮想関数でC++クラスを使用するには?
- 28. C++ - 仮想関数の実装を継承する
- 29. 仮想関数
- 30. C++親メンバー関数内の仮想関数の振る舞い
"で、基底クラスは派生クラスのメソッドを呼び出します。これはサンプルコードと対になるかなり混乱したステートメントです。テキストはbase.Drawによって派生クラスDrawメソッドが呼び出されることを示します(StackOverflowExceptionが発生すると思います)。私はあなたのポイントを得るが、新人はそうではないかもしれない。そのようなサンプルコードは本当に良いですが、それを実行すると、何が起こるかを明確に示します。 –