GNU/Linux >> Linux の 問題 >  >> Linux

方法:オブジェクト指向プログラミング–コンストラクターと継承

以前

オブジェクト指向プログラミング入門のこのボーナスラウンドを通じて、私たちは旅の終わりに近づいています!前回の記事では、クラス、オブジェクト、およびメソッドのレビューからふれあい動物園の例を開始しました。このシリーズの冒頭を見逃した場合は、ここで私たちに追いつくことができます。それ以外の場合は、戻ってみましょう!


建設業者

2つのDogを使用して演習を行った場合 オブジェクト、それは少し退屈でしたね?結局のところ、どの犬がどの樹皮を生産したかというソースコードを見ずに、犬を互いに分離することはできず、知る方法もありません。

前回の記事で、オブジェクトを作成するときに、コンストラクターと呼ばれる特別なメソッドを呼び出すことを説明しました。 。コンストラクターは、メソッドとして記述されたクラス名のように見えます。たとえば、Dogの場合 クラスの場合、コンストラクターはDog()と呼ばれます。 。

コンストラクターの特別な点は、コンストラクターが新しいオブジェクトへのパスであるため、オブジェクトをデフォルト値で初期化するコードを呼び出すのに最適な場所です。さらに、コンストラクターメソッドからの戻り値は常にクラス自体のオブジェクトであるため、作成するクラスのタイプの変数にコンストラクターの戻り値を割り当てることができます。

ただし、これまでのところ、実際にはコンストラクターをまったく作成していないので、なぜそのメソッドを呼び出すことができるのでしょうか。

C#を含む多くの言語では、この言語は何もしなくても無料で空のコンストラクターを提供します。コンストラクターが必要であることを意味します。そうでなければ、クラスを何かに使用する方法がないので、言語はあなたがクラスを書いたと仮定するだけです。

この目に見えない無料のコンストラクターは、デフォルトコンストラクターと呼ばれます。 、そして、この例では、次のようになります。

public Dog(){ }

この構文はSpeak()と非常によく似ていることに注意してください。 以前に作成したメソッド。ただし、値を明示的に返さず、メソッドの戻り型を宣言することもありません。前述したように、コンストラクターは常に、それが属するクラスのインスタンスを返します。

この場合、それはクラスDog 、そのため、Dog myDog = new Dog()を記述します。 、 myDogという名前の変数に新しいオブジェクトを割り当てることができます タイプはDog

それでは、デフォルトのコンストラクターをDogに追加しましょう。 クラス。上記の行をコピーするか、VisualStudioでショートカットを使用できます。ctorと入力します。 Tabを押します 2回。図9に示すように、デフォルトのコンストラクターが生成されます。

図9:「ctor」を使用したコンストラクターの追加

デフォルトのコンストラクターは、以前は暗黙的に行われていたことを明示的に実行しているため、実際には何も新しいものを提供しません。ただし、これはメソッドであるため、このコンストラクターを呼び出すたびに実行されるコンテンツを角かっこ内に追加できるようになりました。また、コンストラクターはオブジェクトの構築の最初のものとして実行されるため、初期化コードを追加するのに最適な場所です。

たとえば、Nameを設定できます 次のようなコードを追加して、オブジェクトのプロパティを何かに追加します。

public Dog()
{
    this.Name = "Snoopy";
}

この例では、Nameを設定します 「スヌーピー」への新しいオブジェクトのプロパティ。

もちろん、すべての犬が「スヌーピー」と呼ばれるわけではないため、これはあまり役に立ちません。代わりに、コンストラクターのメソッドシグネチャを変更して、パラメーターを受け入れるようにします。

メソッドの括弧は、見栄えを良くするためだけのものではありません。これらは、メソッドに値を渡すために使用できるパラメーターを含むのに役立ちます。この関数は、コンストラクターだけでなく、すべてのメソッドに適用されますが、最初にコンストラクターに対して実行しましょう。

デフォルトのコンストラクター署名を次のように変更します:

public Dog(string dogName)

この追加により、stringを送信できます パラメーターをコンストラクターに追加します。そうすると、そのパラメーターをdogNameという名前で参照できます。 。

次に、メソッドブロックに次の行を追加します。

this.Name = dogName;

この行は、このオブジェクトのプロパティNameを設定します コンストラクターに送信したパラメーターに。

コンストラクターの署名を変更すると、図10に示すように、Program.csファイルに赤い波線のケースが表示されることに注意してください。

図10:新しいコンストラクターからの赤い波線のケース

独自の明示的なコンストラクターを追加する場合、C#と.NETはデフォルトのコンストラクターを暗黙的に作成しません。 Program.csファイルでは、まだDogを作成しています デフォルトのパラメーターなしのコンストラクターを使用するオブジェクト。現在は存在しません。

この問題を修正するには、Program.csのコンストラクター呼び出しにパラメーターを追加する必要があります。たとえば、オブジェクト下書き線を次のように更新できます。

Dog myDog =new Dog(“ Snoopy”);

そうすることで、赤い波線が削除され、コードを再度実行できるようになります。最後のコード行の後にブレークポイントを残すか設定する場合は、[ローカル]パネルを見て、オブジェクトのNameを確認できます。 図11に示すように、プロパティは実際に設定されています。

図11:Nameプロパティが正しく設定されていることを確認する

とった?良い!犬に名前を付けることができるようになりましたが、犬をデバッグして私たちが何をしているかを確認する必要がある場合、これは実際には便利なプログラムではありません。それでは、コードを少し混ぜて、吠えている犬の名前が表示されるようにします。

Dogを更新します オブジェクトを変更し、Speak()を変更します そのような方法:

public void Speak() { Console.WriteLine(this.Name + " says: Woof"); }

これで行った変更により、WriteLineが通知されます。 このオブジェクトの名前をリテラル文字列「says:Woof」と連結するメソッド。これにより、作業をより適切に表示する出力が得られるはずです。今すぐプログラムを実行してみると、図12のようなものが表示されるはずです。

図12:スヌーピーのコメント:Woof

よくやった!これで、異なる名前の犬をたくさん作成することができ、それらはすべてあなたの命令で吠えます。

もちろん、犬だけのふれあい動物園はやや退屈です。つまり、私は犬が大好きですが、体験を少し盛り上げるために動物を追加することもできますか?

継承

新しいCatを追加することから始めましょう 私たちのAnimals.csファイルへのクラス。 Dogクラスの横に、ただしPettingZoo名前空間ブラケット内に次のコードを追加します。

class Cat
{
    public Cat(string catName)
    {
        this.Name = catName;
    }
    string Name;
    public void Speak() { Console.WriteLine(this.Name + " says: Meow!"); }
}

次に、Catを作成しましょう Program.csのオブジェクトを作成し、話してもらいます:

Cat myCat = new Cat("Garfield");
myCat.Speak();

このプログラムを今すぐ実行すると、図13のような出力が得られます。

図13:ガーフィールドのコメント:ニャー

私たちのプログラムは予測可能で機能しますが、2つのクラスが実際にどれほど似ているかに気づきましたか? 2つのクラス間で複製したコードの量を確認してください。オブジェクト指向は、コードを何度も書くことから私たちを救うはずではありませんでしたか?

答えはイエスです。このコードを単純化して、重複の量を減らすことができます。これから説明するのは、継承と呼ばれるOOの機能を示します。 。

オブジェクト指向の継承により、クラスの階層を作成し、各クラスに親クラスのプロパティとメソッドを継承させることができます。たとえば、ふれあい動物園の場合、親のAnimalを作成できます。 クラスとDogがあります およびCat そのクラスから継承します。次に、コードの一部をAnimalに移動できます。 両方のDogが およびCat クラスはそのコードを継承します。

ただし、コードの重複部分をこのAnimalに移動した場合 クラス、次にDog およびCat クラスはそれぞれ同じプロパティとメソッドを継承し、子を親クラスのクローンにします。この組織は、異なる種類の動物が必要なため、あまり役に立ちません。猫、犬、そして他のすべての動物が同じだったら、それはひどく退屈でしょう。実際、私たちのプログラムの目的上、それらを別のものと呼ぶことはまったく意味がありません。

さて、継承によって、親クラスと同一の子クラスしか作成できない場合、このすべての作業に取り組む意味はあまりありません。したがって、親クラスのすべての部分を継承する一方で、子クラスの親クラスの特定の部分をオーバーライドして、子クラスを区別することもできます。

これを見て、どのように機能するか見てみましょう。

親と子のクラスの作成

少し前に戻って、Dogを再作成します。 およびCat より良い方法でクラス。まず、子クラスの共有プロパティとメソッドを定義する親クラスが必要です。

Animals.csファイルで、Dogを削除します およびCat クラスを追加し、次のクラス定義を追加します。

class Animal
{
    public string Name;
    public string Sound;
    public void Speak() { Console.WriteLine(this.Name + " says " + this.Sound); }
}

このクラスは、当然のことながら、以前のDogと同じように見えます。 およびCat すべてのプロパティとメソッドを公開し、 Sound という新しいプロパティを導入したことを除いて、クラス。 タイプstring 。最後に、Speakを更新しました サウンドを使用するメソッド 変数。

この時点で、Program.csは機能しません。そのタブをクリックすると、いくつかのエラーメッセージが表示されます。これは、Catを削除したため当然です。 およびDog クラス。それらを再作成し、継承を使用して再作成しましょう。 Animals.csファイルで、Animalの直後 クラスには、次のコードを追加します:

class Dog : Animal { }
class Cat : Animal { }

これらの新しいクラスは以前よりもはるかに短く、コードを複製しません。ここでの新しい構文は、コロンの後にクラス名Animalが続くものです。 、C#にDogの両方が必要であることを通知します およびCat Animalから継承する クラス。事実上、Dog およびCat Animalの子クラスになります 図14に示す図に示すように。

図14:動物クラスの継承の図

注:私はプロパティという用語を使用しています これまでのところ、正しい用語は field であるため、少し不正確です。 図14の図からわかるように、フィールドはプログラミングの範囲外ではあまり明確ではないため、代わりにプロパティを使用しました。技術的には、プロパティはC#のフィールドのラッパーです。


ただし、作成したカスタムコンストラクターが原因で、Program.csファイルにまだ問題があります。プログラムを実行またはデバッグしようとすると、「「PettingZoo.Cat」には1つの引数を取るコンストラクターが含まれていません」というエラーメッセージと、「PettingZoo.Dog」の同様のコンストラクターが表示されます。

このエラーを修正するには、コンストラクターを再度追加する必要があります。ただし、今回は、継承を利用してコンストラクターを継承し、コンストラクターを拡張して親クラスの機能を変更する方法を示します。

まず、Animalのベースコンストラクターを作成する必要があります 、これは以前に作成した以前のコンストラクターに似ています。次のコードをAnimalに追加します クラス:

public Animal(string animalName)
{
    this.Name = animalName;
}

前と同じように、コンストラクターは動物の名前を渡したものに設定します。ただし、両方のDogにコンストラクターを追加する必要があるため、これだけでは不十分です。 およびCat クラス。これを使用して、各動物がどの音を出すかを定義します。

class Dog : Animal
{
    public Dog(string dogName) : base(dogName)
    {
        this.Sound = "Woof";
    }
}
class Cat : Animal
{
    public Cat(string catName) : base(catName)
    {
        this.Sound = "Meow";
    }
}

どちらのクラスにも、Nameを受け入れるコンストラクターを追加します パラメータ。このオブジェクトのSoundも設定します 動物に作ってもらいたい音の特性。

ただし、以前とは異なり、親クラスコンストラクターを呼び出してNameを渡すようになりました。 親コンストラクターからのパラメーター。この呼び出しは、: base()を介して行われます。 メソッドを使用し、受信したdogNameを追加します またはcatName 括弧内のパラメータ。

注:この: base() 構文はコンストラクターに固有です。ケースの機能を変更または拡張する他の方法については、後で説明します。


これらのコードの更新により、プログラムを再度実行して、図15のような結果を確認できます。

図15:継承を使用して話す動物

Soundもありません。 Nameでもありません Dogのいずれかで定義されたプロパティ またはCat クラス。 Speak()もありません 方法。代わりに、それらは親のAnimalに存在します クラス、およびDog およびCat クラスはこれらのプロパティとメソッドを継承します。

同様に、他のクラスを作成できます。どのタイプの動物でも、Dogのパターンを複製するだけで済みます。 およびCat クラス。たとえば、次のクラスを作成できます。

class Parrot : Animal
{
    public Parrot(string parrotName)
        : base(parrotName)
    {
        this.Sound = "I want a cracker!";
    }
}
class Pig : Animal
{
    public Pig(string pigName)
        : base(pigName)
    {
        this.Sound = "Oink";
    }
}

次に、Program.csでこれらのクラスをインスタンス化できます:

Parrot myParrot = new Parrot("Polly");
myParrot.Speak();

Pig myPig = new Pig("Bacon");
myPig.Speak();

これで、図16に示すように、プログラムを実行すると、真の動物園が手に入ります。

図16:話す4匹の動物の動物園

既存の子クラスのサブ子クラスをさらに作成することもできます。たとえば、Dogを分離することができます Beagleにクラス分けする およびPointer またはParrot クラスは親から継承しますBird 次に、Animalから継承するクラス 。ただし、この種の階層を作成することはこの記事の範囲を超えているため、次に進んで、最後に、子クラスの親クラスの機能をオーバーライド、変更、または拡張する方法を見てみましょう。

継承の変更

オーバーライドと呼ばれる手法を使用して、親クラスのメソッドを変更できます。 。オーバーライドの構文は言語によって異なる場合がありますが、子クラスで親のメソッドを変更する原則は同じです。

C#では、キーワードoverrideを追加します その後に、オーバーライドするメソッドシグネチャが続きます。また、親クラスで、virtualを追加して子がメソッドをオーバーライドできるようにすることを宣言する必要があります。 親クラスのメソッドシグネチャへのキーワード。 (他の言語では、この追加の表示は必要ない場合があります。)

このプログラムでは、Speak()を更新する必要があります Animalのメソッド クラス。

public virtual void Speak() { Console.WriteLine(this.Name + " says " + this.Sound); }

これで、Speak()のオーバーライドを挿入できます。 Dogのメソッド このクラスのコードブロックの先頭にあるクラス。

class Dog : Animal
{
    public override void Speak()
    {
        base.Speak();
        Console.WriteLine("...and then runs around, chasing his tail");
    }
[remaining code omitted]

このコードは、親メソッドSpeak()で発生することをオーバーライドすることを示しています。 。 base.Speak()を使用して親メソッドを実行します 直後に追加の行を出力する前に呼び出します。

なぜあなたはそうしたいのですか?ええと、おそらく私達は私達の犬が彼らが直接会うことができるのと同じくらい熱狂的であることを望みます。プログラムを実行して、自分の目で確かめてください:

図17:私たちの犬は彼のクラスメソッドをオーバーライドします

まず、スヌーピーは通常どおり吠えます:base.Speak() メソッドはSpeak()を呼び出します 親のAnimalからのメソッド クラス。次に、残りのコードは2行目をコンソールに出力します。事実上、子クラスにのみ新しい機能を追加することにより、親クラスを拡張します。 Catの様子をご覧ください クラスは影響を受けません。

もちろん、猫は思い通りに行動するのが難しいことで有名なので、それをコードに反映させましょう。 Catを更新します クラスを作成し、Dogと同様に、次のメソッドオーバーライドを追加します クラス。

class Cat : Animal
{
    public override void Speak()
    {
        Console.WriteLine(Name + " doesn't speak but just sits there wondering when you will feed it.");
    }
[remaining code omitted]

Dogで行ったこととは異なり オーバーライドします。base.Speak()は呼び出しません。 今回はメソッド。その呼び出しがなければ、Animalを実行することはありません。 Speak() メソッドとこのメソッドで何が起こるかを完全に変更します。自分の目で確かめてください:

図18:猫もクラスメソッドをオーバーライドします

また、クラスを再構築したため、Program.csコードを変更していないことにも注意してください。これらの変更は、オブジェクト指向が非常に強力な手法である理由の良い例として役立ちます。そのコードを使用するプログラムに触れることなく、基礎となるコードを完全に変更しました。 [オブジェクト指向により、実装の詳細の多くを分離し、プログラムが対話する必要のあるインターフェイスの小さなセットを公開することができました。]

ルールを曲げた場所

まとめる前に、いくつかのこと、主に私たちが行った「悪い」ことを指摘したいと思います。

まず、クラスでは、Console.WriteLine()を呼び出します。 直接メソッド。クラスはクラスの結果を出力する方法に依存しないため、この使用法は適切な設計上の決定ではありません。

より良いアプローチは、代わりにクラスからデータを返し、それをプログラムの一部として出力することです。次に、プログラムがクラスではなく出力をどう処理するかを決定できるようにし、Webページ、Windowsフォーム、QT、コンソールアプリケーションなど、さまざまな種類のプログラムで同じクラスを使用できるようにします。

次に、後の例では、すべてのプロパティがpublicでした。 。これらのプロパティを公開すると、オブジェクト指向のセキュリティ面が弱まります。オブジェクト指向では、クラス内のデータを外部からの操作から保護しようとします。ただし、継承を処理する場合、プロパティとメソッドの保護はすぐに複雑になるため、少なくともこの導入段階では、その複雑さを避けたかったのです。

最後に、Soundを使用しても意味がありません。 そのコードも複製していたので、子コンストラクターの一部として設定しました。名前とサウンドの両方を受け入れる親クラスにコンストラクターを作成し、それを子コンストラクターの一部として呼び出す方がよい設計です。ただし、簡単にするために、この段階では異なるコンストラクター署名を導入したくありませんでした。

したがって、このボーナスチュートリアルでは多くのことを学びましたが、さらに学ぶべきことがあることがわかります。ただし、まだあまり心配する必要はありません。ずっと続いたことを祝福するために少し時間をとることができます。すべての手順を実行した場合は、次のことを学習しました。

  • オブジェクト指向を使用する理由
  • クラスの作成方法
  • プロパティとメソッドを作成する方法
  • コンストラクターの作成方法とその機能
  • 継承を利用する方法と、それがオブジェクト指向の強力な機能である理由

この追加のレッスンを楽しんでいただき、さらに探索することに興味を持っていただければ幸いです。 Atlantic.Netブログで新しいコンテンツを確認し、業界をリードする仮想プライベートホスティングサーバーの1つを検討してください。


Linux
  1. Linuxでサービスを管理および一覧表示する方法

  2. 方法:DRBDのレプリケーションと構成

  3. 方法:Pythonでのソケットプログラミング

  1. LinuxとWindowsをデュアルブートする方法

  2. LinuxにElasticsearchとKibanaをインストールする方法

  3. Linuxでドライブをパーティション分割してフォーマットする方法

  1. chroot jailとは何ですか?その使用方法は?

  2. KubernetesにHelmをインストールして使用する方法

  3. Linux Screenをインストールして使用する方法は?