web-dev-qa-db-ja.com

C#でのオーバーライドと継承

わかりました、私が学んでいる間、私と一緒に男と女に耐えてください。これが私の質問です。

親クラスのメソッドをオーバーライドできない理由がわかりません。これが基本クラスのコードです(そうです、Java OOP本からのコードで、C#で書き直そうとしています)を盗みました)。

using System;

public class MoodyObject
{
    protected String getMood()
    {
        return "moody";
    }

    public void queryMood()
    {
        Console.WriteLine("I feel " + getMood() + " today!");
    }
}

ここに、基本クラス(MoodyObject)を継承する他の2つのオブジェクトがあります。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    public class SadObject: MoodyObject
    {
        protected String getMood()
        {
            return "sad";
        }

        //specialization
        public void cry()
        {
            Console.WriteLine("wah...boohoo");
        }
    }
}

そして:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    public class HappyObject: MoodyObject
    {
        protected String getMood()
        {
            return "happy";
        }

        public void laugh()
        {
            Console.WriteLine("hehehehehehe.");
        }
    }
}

ここに私のメインがあります:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            MoodyObject moodyObject = new MoodyObject();
            SadObject sadObject = new SadObject();
            HappyObject happyObject = new HappyObject();

            Console.WriteLine("How does the moody object feel today?");
            moodyObject.queryMood();
            Console.WriteLine("");
            Console.WriteLine("How does the sad object feel today?");
            sadObject.queryMood();
            sadObject.cry();
            Console.WriteLine("");
            Console.WriteLine("How does the happy object feel today?");
            happyObject.queryMood();
            happyObject.laugh();
        }
    }
}

ご覧のとおり、かなり基本的なものですが、出力は次のとおりです。

今日の不機嫌そうなオブジェクトはどのように感じますか?今日は気分が悪い!

悲しい対象は今日どのように感じますか?今日は気分が悪い!ワウ...ブーフー

幸せなオブジェクトは今日どのように感じますか?今日は気分が悪い!へへへへへへ。何かキーを押すと続行します 。 。 。

思ったほどではなかった。ベースメソッドを仮想化してオーバーライドを呼び出そうとしたときにオーバーライドを呼び出しましたが、「継承されたメンバー 'MoodyObject.getMood()'は、仮想、抽象、またはオーバーライドとしてマークされていないため、オーバーライドできません」というエラーが表示されるだけです。私は仮想とオーバーライドなしで試してみましたが、ベースメソッドを隠そうとしているようです。繰り返しますが、私はOOPに不慣れです。ガイダンスをいただければ幸いです。

編集済み:見つかりました!MoodyObject.csは、ソリューションエクスプローラーでは「ソリューションアイテム」でしたが、「ConsoleApplication1」アイテムではありませんでした。ソリューションエクスプローラーに属していた場所までドラッグしました。 !動作しました。解決したところにたどり着くために必要な支援を提供してくれたので、以下にLucの回答を回答としてマークしました...私はここで多くのことを学んでいます。

24
GregD

C#では、メソッドはデフォルトでは仮想ではないため、一部のメソッドをオーバーライド可能として設計する場合は、仮想として指定する必要があります。

class Base 
{
  protected virtual string GetMood() {...}
}

次に、派生クラスの基本クラスのメソッドをオーバーライドすることを指定する必要があります。

class Derived : Base
{
  protected override string GetMood() {...}
}

「override」キーワードを指定しない場合、基本型を非表示にするメソッドを取得します(また、メソッドに「new」キーワードを明示的に指定するように警告するコンパイラからの警告)。

継承チェーンを停止してメソッドのオーバーライドを禁止する場合は、次のようにメソッドをシール済みとしてマークする必要があります。

  protected sealed override string GetMood() {...}
62
Ilya Ryzhenkov

仮想をオーバーライドしたり、抽象メソッドを実装したりするには、overrideキーワードを使用する必要があります。

public class MoodyObject
{
    protected virtual String getMood() 
    { 
        return "moody"; 
    }    
    public void queryMood() 
    { 
        Console.WriteLine("I feel " + getMood() + " today!"); 
    }
}

public class HappyObject : MoodyObject
{
    protected override string getMood()
    {
        return "happy";
    }
}

ここで私がお勧めするのは、おそらくMoodyObjectを抽象クラスにすることを意図しているということです。 (これを行う場合は、メインの方法を変更する必要がありますが、検討する必要があります)不機嫌そうなモードであることは本当に意味がありますか?上記での問題は、あなたのHappyObjectがgetMoodの実装を提供する必要がないことです。クラスを抽象化することにより、いくつかのことを行います。

  1. 抽象クラスのインスタンスを新しくすることはできません。子クラスを使用する必要があります。
  2. 派生した子に特定のメソッドを実装させることができます。

これを行うには、次のようになります。

public abstract class MoodyObject
{
    protected abstract String getMood();

    public void queryMood() 
    { 
        Console.WriteLine("I feel " + getMood() + " today!"); 
    }
}

GetMoodの実装を提供しなくなったことに注意してください。

7
JoshBerke

私の知る限り、Javaのすべてのメソッドはデフォルトで仮想です。これはC#の場合とは異なります。したがって、基本クラスのメソッドを「仮想」でマークする必要があります。たとえば、protected virtual string getMood() ...と "override"によるオーバーライド、たとえばprotected override string getMood()...

5
Dan C.

基本クラスのメソッドをオーバーライドする場合は、virtualとして宣言する必要があります。派生クラスのオーバーライドメソッドは、overrideとして明示的に宣言する必要があります。これはうまくいくはずです:

public class BaseObject
{
    protected virtual String getMood()
    {
        return "Base mood";
    }

    //...
}

public class DerivedObject: BaseObject
{
    protected override String getMood()
    {
        return "Derived mood";
    }
    //...
}

編集: C#コンソールアプリケーションで試したところ、コンパイルされました。そのため、使用するソースコードは、ここに投稿したものとは少し異なりますが重要な部分が異なる必要があります。

私のprogram.csはこれです:

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {    
            // leaving out your implementation to save space...    
        }
    }    

    public class SadObject : MoodyObject
    {
        protected override String getMood()
        {
            return "sad";
        }

        //specialization
        public void cry()
        {
            Console.WriteLine("wah...boohoo");
        }
    }

    public class HappyObject : MoodyObject
    {
        protected override String getMood()
        {
            return "happy";
        }

        public void laugh()
        {
            Console.WriteLine("hehehehehehe.");
        }
    }
}
3
Treb

メソッドをGetMood virtualをMoodyに、overrideを派生クラスにすると、コードは機能するはずです。これらのキーワードが属している場所に配置しましたか?コンパイルして問題なく実行できる完全なコードを次に示します。

public class MoodyObject
{
    protected virtual String getMood()
    {
        return "moody";
    }

    public void queryMood()
    {
        Console.WriteLine("I feel " + getMood() + " today!");
    }
}

public class SadObject : MoodyObject
{
    protected override String getMood()
    {
        return "sad";
    }

    //specialization
    public void cry()
    {
        Console.WriteLine("wah...boohoo");
    }
}

public class HappyObject : MoodyObject
{
    protected override String getMood()
    {
        return "happy";
    }

    public void laugh()
    {
        Console.WriteLine("hehehehehehe.");
    }
}

class Program
{
    static void Main(string[] args)
    {
        MoodyObject moodyObject = new MoodyObject();
        SadObject sadObject = new SadObject();
        HappyObject happyObject = new HappyObject();

        Console.WriteLine("How does the moody object feel today?");
        moodyObject.queryMood();
        Console.WriteLine("");
        Console.WriteLine("How does the sad object feel today?");
        sadObject.queryMood();
        sadObject.cry();
        Console.WriteLine("");
        Console.WriteLine("How does the happy object feel today?");
        happyObject.queryMood();
        happyObject.laugh();

        Console.Read();
    }
}

多分あなたの間違いはJavaではすべてのメソッドが仮想であるという事実から来ているかもしれません、それはC#ではそうではありません(Dan Cによって指摘されたように)。

2
Luc Touraille

オブジェクトが基本クラスの関数をオーバーライドしていることをC#に伝える必要があります。

必要な構文に関するMSDNの記事は次のとおりです。 http://msdn.Microsoft.com/en-us/library/ebca9ah3(VS.71).aspx

public class SadObject: MoodyObject    
{        
    override String getMood()
2
Jeremiah
public class SadObject: MoodyObject
    {
        override String getMood()
1
James Curran

GetMoodのオーバーライドを「override」キーワードでマークする必要があります。また、ベースとなるgetMoodメソッドを「virtual」キーワードでマークする必要があります。

0
Kevin Tighe