Bagikan melalui


Mengetahui Waktu untuk Menggunakan Ambil Alih dan Kata Kunci yang Baru (Panduan Pemrograman C#)

Dalam C#, metode dalam kelas turunan dapat memiliki nama yang sama dengan metode di kelas dasar. Anda dapat menentukan cara metode berinteraksi dengan menggunakan kata kunci baru dan ambil alih. Pemodifikasi overridememperluas metode kelas dasar virtual, dan pemodifikasi newmenyembunyikan metode kelas dasar yang dapat diakses. Perbedaannya diilustrasikan dalam contoh dalam topik ini.

Dalam aplikasi konsol, deklarasikan kedua kelas berikut, BaseClass dan DerivedClass. DerivedClass mewarisi dari BaseClass.

class BaseClass  
{  
    public void Method1()  
    {  
        Console.WriteLine("Base - Method1");  
    }  
}  
  
class DerivedClass : BaseClass  
{  
    public void Method2()  
    {  
        Console.WriteLine("Derived - Method2");  
    }  
}  

Dalam metode Main, deklarasikan variabel bc, dc, dan bcdc.

  • bc berjenis BaseClass, dan nilainya berjenis BaseClass.

  • dc berjenis DerivedClass, dan nilainya berjenis DerivedClass.

  • bcdc berjenis BaseClass, dan nilainya berjenis DerivedClass. Ini adalah variabel yang perlu diperhatikan.

Karena bc dan bcdc memiliki jenis BaseClass, mereka hanya dapat langsung mengakses Method1, kecuali Anda menggunakan casting. Variabel dc dapat mengakses Method1 dan Method2. Relasi ini ditunjukkan di dalam kode berikut.

class Program  
{  
    static void Main(string[] args)  
    {  
        BaseClass bc = new BaseClass();  
        DerivedClass dc = new DerivedClass();  
        BaseClass bcdc = new DerivedClass();  
  
        bc.Method1();  
        dc.Method1();  
        dc.Method2();  
        bcdc.Method1();  
    }  
    // Output:  
    // Base - Method1  
    // Base - Method1  
    // Derived - Method2  
    // Base - Method1  
}  

Berikutnya, tambahkan metode Method2 berikut ke BaseClass. Tanda tangan metode ini cocok dengan tanda tangan metode Method2 di DerivedClass.

public void Method2()  
{  
    Console.WriteLine("Base - Method2");  
}  

Karena BaseClass sekarang memiliki metode Method2, pernyataan panggilan kedua dapat ditambahkan untuk BaseClass variabel bc dan bcdc, seperti yang ditunjukkan dalam kode berikut.

bc.Method1();  
bc.Method2();  
dc.Method1();  
dc.Method2();  
bcdc.Method1();  
bcdc.Method2();  

Saat Anda membangun proyek, Anda melihat bahwa penambahan metode Method2 dalam BaseClass menyebabkan peringatan. Peringatan mengatakan bahwa metode Method2 dalam DerivedClass menyembunyikan metode Method2 di BaseClass. Anda disarankan untuk menggunakan kata kunci new dalam definisi Method2 jika Anda berniat untuk menyebabkan hasil tersebut. Atau, Anda dapat mengganti nama salah satu metode Method2 untuk menyelesaikan peringatan, namun itu tidak selalu praktis.

Sebelum menambahkan new, jalankan program untuk melihat output yang dihasilkan oleh pernyataan panggilan tambahan. Hasil berikut ini ditampilkan.

// Output:  
// Base - Method1  
// Base - Method2  
// Base - Method1  
// Derived - Method2  
// Base - Method1  
// Base - Method2  

Kata kunci new mempertahankan hubungan yang menghasilkan output tersebut, tetapi menekan peringatan. Variabel yang memiliki jenis BaseClass terus mengakses anggota BaseClass, dan variabel yang memiliki jenis DerivedClass terus mengakses anggota DerivedClass terlebih dahulu, dan kemudian untuk mempertimbangkan anggota yang diwarisi dari BaseClass.

Untuk menekan peringatan, tambahkan pemodifikasi new ke definisi Method2 dalam DerivedClass, seperti yang ditunjukkan dalam kode berikut. Pemodifikasi dapat ditambahkan sebelum atau sesudah public.

public new void Method2()  
{  
    Console.WriteLine("Derived - Method2");  
}  

Jalankan program lagi untuk memverifikasi bahwa output tidak berubah. Verifikasi juga bahwa peringatan tidak lagi muncul. Dengan menggunakan new, Anda menegaskan bahwa Anda menyadari bahwa anggota yang dimodifikasi menyembunyikan anggota yang diwarisi dari kelas dasar. Untuk informasi selengkapnya tentang nama yang bersembunyi melalui pewarisan, lihat Pemodifikasi baru.

Untuk membedakan perilaku ini dengan efek dari menggunakan override, tambahkan metode berikut ke DerivedClass. Pemodifikasi override dapat ditambahkan sebelum atau sesudah public.

public override void Method1()  
{  
    Console.WriteLine("Derived - Method1");  
}  

Tambahkan pemodifikasi virtual ke definisi Method1 di dalam BaseClass. Pemodifikasi virtual dapat ditambahkan sebelum atau sesudah public.

public virtual void Method1()  
{  
    Console.WriteLine("Base - Method1");  
}  

Menjalankan proyek lagi. Perhatikan terutama dua baris terakhir dari output berikut ini.

// Output:  
// Base - Method1  
// Base - Method2  
// Derived - Method1  
// Derived - Method2  
// Derived - Method1  
// Base - Method2  

Penggunaan pemodifikasi override memungkinkan bcdc untuk mengakses metode Method1, yang ditentukan di dalam DerivedClass. Biasanya, itu adalah perilaku yang diinginkan dalam hierarki warisan. Anda ingin objek yang memiliki nilai yang dibuat dari kelas turunan menggunakan metode yang ditentukan di dalam kelas turunan. Anda mencapai perilaku tersebut dengan menggunakan override untuk memperluas metode kelas dasar.

Kode berikut berisi contoh lengkap.

using System;  
using System.Text;  
  
namespace OverrideAndNew  
{  
    class Program  
    {  
        static void Main(string[] args)  
        {  
            BaseClass bc = new BaseClass();  
            DerivedClass dc = new DerivedClass();  
            BaseClass bcdc = new DerivedClass();  
  
            // The following two calls do what you would expect. They call  
            // the methods that are defined in BaseClass.  
            bc.Method1();  
            bc.Method2();  
            // Output:  
            // Base - Method1  
            // Base - Method2  
  
            // The following two calls do what you would expect. They call  
            // the methods that are defined in DerivedClass.  
            dc.Method1();  
            dc.Method2();  
            // Output:  
            // Derived - Method1  
            // Derived - Method2  
  
            // The following two calls produce different results, depending
            // on whether override (Method1) or new (Method2) is used.  
            bcdc.Method1();  
            bcdc.Method2();  
            // Output:  
            // Derived - Method1  
            // Base - Method2  
        }  
    }  
  
    class BaseClass  
    {  
        public virtual void Method1()  
        {  
            Console.WriteLine("Base - Method1");  
        }  
  
        public virtual void Method2()  
        {  
            Console.WriteLine("Base - Method2");  
        }  
    }  
  
    class DerivedClass : BaseClass  
    {  
        public override void Method1()  
        {  
            Console.WriteLine("Derived - Method1");  
        }  
  
        public new void Method2()  
        {  
            Console.WriteLine("Derived - Method2");  
        }  
    }  
}  

Contoh berikut ini mengilustrasikan perilaku yang serupa dalam konteks yang berbeda. Contohnya menentukan tiga kelas: kelas dasar bernama Car, dan dua kelas yang berasal darinya, ConvertibleCar dan Minivan. Kelas dasar berisi metode DescribeCar. Metode ini menampilkan deskripsi dasar sebuah mobil, lalu memanggil ShowDetails untuk menyediakan informasi tambahan. Masing-masing dari tiga kelas menentukan metode ShowDetails. Pemodifikasi new digunakan untuk menentukan ShowDetails di dalam kelas ConvertibleCar. Pemodifikasi override digunakan untuk menentukan ShowDetails di dalam kelas Minivan.

// Define the base class, Car. The class defines two methods,  
// DescribeCar and ShowDetails. DescribeCar calls ShowDetails, and each derived  
// class also defines a ShowDetails method. The example tests which version of  
// ShowDetails is selected, the base class method or the derived class method.  
class Car  
{  
    public void DescribeCar()  
    {  
        System.Console.WriteLine("Four wheels and an engine.");  
        ShowDetails();  
    }  
  
    public virtual void ShowDetails()  
    {  
        System.Console.WriteLine("Standard transportation.");  
    }  
}  
  
// Define the derived classes.  
  
// Class ConvertibleCar uses the new modifier to acknowledge that ShowDetails  
// hides the base class method.  
class ConvertibleCar : Car  
{  
    public new void ShowDetails()  
    {  
        System.Console.WriteLine("A roof that opens up.");  
    }  
}  
  
// Class Minivan uses the override modifier to specify that ShowDetails  
// extends the base class method.  
class Minivan : Car  
{  
    public override void ShowDetails()  
    {  
        System.Console.WriteLine("Carries seven people.");  
    }  
}  

Contoh ini menguji versi ShowDetails mana yang dipanggil. Metode berikut ini, TestCars1, mendeklarasikan instans dari setiap kelas, lalu memanggil DescribeCar pada setiap instans.

public static void TestCars1()  
{  
    System.Console.WriteLine("\nTestCars1");  
    System.Console.WriteLine("----------");  
  
    Car car1 = new Car();  
    car1.DescribeCar();  
    System.Console.WriteLine("----------");  
  
    // Notice the output from this test case. The new modifier is  
    // used in the definition of ShowDetails in the ConvertibleCar  
    // class.
  
    ConvertibleCar car2 = new ConvertibleCar();  
    car2.DescribeCar();  
    System.Console.WriteLine("----------");  
  
    Minivan car3 = new Minivan();  
    car3.DescribeCar();  
    System.Console.WriteLine("----------");  
}  

TestCars1 menghasilkan output berikut ini. Perhatikan terutama hasil untuk car2, yang mungkin bukan yang Anda harapkan. Jenis objek adalah ConvertibleCar, tetapi DescribeCar tidak mengakses versi ShowDetails yang ditentukan di kelas ConvertibleCar, karena metode tersebut dideklarasikan dengan pemodifikasi new, bukan pemodifikasi override. Akibatnya, objek ConvertibleCar menampilkan deskripsi yang sama dengan objek Car. Membedakan hasil untuk car3, yang merupakan objek Minivan. Dalam hal ini, ShowDetails metode yang dideklarasikan dalam kelas Minivan mengambil alih metode ShowDetails yang dideklarasikan di kelas Car, dan deskripsi yang ditampilkan menggambarkan minivan.

// TestCars1  
// ----------  
// Four wheels and an engine.  
// Standard transportation.  
// ----------  
// Four wheels and an engine.  
// Standard transportation.  
// ----------  
// Four wheels and an engine.  
// Carries seven people.  
// ----------  

TestCars2 membuat daftar objek yang memiliki jenis Car. Nilai objek dibuat dari Car, ConvertibleCar, dan Minivan. DescribeCar dipanggil pada setiap elemen daftar. Kode berikut ini menunjukkan definisi TestCars2.

public static void TestCars2()  
{  
    System.Console.WriteLine("\nTestCars2");  
    System.Console.WriteLine("----------");  
  
    var cars = new List<Car> { new Car(), new ConvertibleCar(),
        new Minivan() };  
  
    foreach (var car in cars)  
    {  
        car.DescribeCar();  
        System.Console.WriteLine("----------");  
    }  
}  

Output berikut ini ditampilkan. Perhatikan bahwa itu sama dengan output yang ditampilkan oleh TestCars1. Metode ShowDetails kelas ConvertibleCar tidak dipanggil, terlepas dari apakah jenis objek adalah ConvertibleCar, seperti di dalam TestCars1, atau Car, seperti di dalam TestCars2. Sebaliknya, car3 memanggil metode ShowDetails dari kelas Minivan dalam kedua kasus, apakah memiliki jenis Minivan atau jenis Car.

// TestCars2  
// ----------  
// Four wheels and an engine.  
// Standard transportation.  
// ----------  
// Four wheels and an engine.  
// Standard transportation.  
// ----------  
// Four wheels and an engine.  
// Carries seven people.  
// ----------  

Metode TestCars3 dan TestCars4 melengkapi contohnya. Metode ini memanggil ShowDetails secara langsung, pertama-tama dari objek yang dideklarasikan memiliki jenis ConvertibleCar dan Minivan (TestCars3), kemudian dari objek yang dideklarasikan memiliki jenis Car (TestCars4). Kode berikut menentukan dua metode tersebut.

public static void TestCars3()  
{  
    System.Console.WriteLine("\nTestCars3");  
    System.Console.WriteLine("----------");  
    ConvertibleCar car2 = new ConvertibleCar();  
    Minivan car3 = new Minivan();  
    car2.ShowDetails();  
    car3.ShowDetails();  
}  
  
public static void TestCars4()  
{  
    System.Console.WriteLine("\nTestCars4");  
    System.Console.WriteLine("----------");  
    Car car2 = new ConvertibleCar();  
    Car car3 = new Minivan();  
    car2.ShowDetails();  
    car3.ShowDetails();  
}  

Metode menghasilkan output berikut, yang sesuai dengan hasil dari contoh pertama dalam topik ini.

// TestCars3  
// ----------  
// A roof that opens up.  
// Carries seven people.  
  
// TestCars4  
// ----------  
// Standard transportation.  
// Carries seven people.  

Kode berikut menunjukkan proyek lengkap dan outputnya.

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;  
  
namespace OverrideAndNew2  
{  
    class Program  
    {  
        static void Main(string[] args)  
        {  
            // Declare objects of the derived classes and test which version  
            // of ShowDetails is run, base or derived.  
            TestCars1();  
  
            // Declare objects of the base class, instantiated with the  
            // derived classes, and repeat the tests.  
            TestCars2();  
  
            // Declare objects of the derived classes and call ShowDetails  
            // directly.  
            TestCars3();  
  
            // Declare objects of the base class, instantiated with the  
            // derived classes, and repeat the tests.  
            TestCars4();  
        }  
  
        public static void TestCars1()  
        {  
            System.Console.WriteLine("\nTestCars1");  
            System.Console.WriteLine("----------");  
  
            Car car1 = new Car();  
            car1.DescribeCar();  
            System.Console.WriteLine("----------");  
  
            // Notice the output from this test case. The new modifier is  
            // used in the definition of ShowDetails in the ConvertibleCar  
            // class.
            ConvertibleCar car2 = new ConvertibleCar();  
            car2.DescribeCar();  
            System.Console.WriteLine("----------");  
  
            Minivan car3 = new Minivan();  
            car3.DescribeCar();  
            System.Console.WriteLine("----------");  
        }  
        // Output:  
        // TestCars1  
        // ----------  
        // Four wheels and an engine.  
        // Standard transportation.  
        // ----------  
        // Four wheels and an engine.  
        // Standard transportation.  
        // ----------  
        // Four wheels and an engine.  
        // Carries seven people.  
        // ----------  
  
        public static void TestCars2()  
        {  
            System.Console.WriteLine("\nTestCars2");  
            System.Console.WriteLine("----------");  
  
            var cars = new List<Car> { new Car(), new ConvertibleCar(),
                new Minivan() };  
  
            foreach (var car in cars)  
            {  
                car.DescribeCar();  
                System.Console.WriteLine("----------");  
            }  
        }  
        // Output:  
        // TestCars2  
        // ----------  
        // Four wheels and an engine.  
        // Standard transportation.  
        // ----------  
        // Four wheels and an engine.  
        // Standard transportation.  
        // ----------  
        // Four wheels and an engine.  
        // Carries seven people.  
        // ----------  
  
        public static void TestCars3()  
        {  
            System.Console.WriteLine("\nTestCars3");  
            System.Console.WriteLine("----------");  
            ConvertibleCar car2 = new ConvertibleCar();  
            Minivan car3 = new Minivan();  
            car2.ShowDetails();  
            car3.ShowDetails();  
        }  
        // Output:  
        // TestCars3  
        // ----------  
        // A roof that opens up.  
        // Carries seven people.  
  
        public static void TestCars4()  
        {  
            System.Console.WriteLine("\nTestCars4");  
            System.Console.WriteLine("----------");  
            Car car2 = new ConvertibleCar();  
            Car car3 = new Minivan();  
            car2.ShowDetails();  
            car3.ShowDetails();  
        }  
        // Output:  
        // TestCars4  
        // ----------  
        // Standard transportation.  
        // Carries seven people.  
    }  
  
    // Define the base class, Car. The class defines two virtual methods,  
    // DescribeCar and ShowDetails. DescribeCar calls ShowDetails, and each derived  
    // class also defines a ShowDetails method. The example tests which version of  
    // ShowDetails is used, the base class method or the derived class method.  
    class Car  
    {  
        public virtual void DescribeCar()  
        {  
            System.Console.WriteLine("Four wheels and an engine.");  
            ShowDetails();  
        }  
  
        public virtual void ShowDetails()  
        {  
            System.Console.WriteLine("Standard transportation.");  
        }  
    }  
  
    // Define the derived classes.  
  
    // Class ConvertibleCar uses the new modifier to acknowledge that ShowDetails  
    // hides the base class method.  
    class ConvertibleCar : Car  
    {  
        public new void ShowDetails()  
        {  
            System.Console.WriteLine("A roof that opens up.");  
        }  
    }  
  
    // Class Minivan uses the override modifier to specify that ShowDetails  
    // extends the base class method.  
    class Minivan : Car  
    {  
        public override void ShowDetails()  
        {  
            System.Console.WriteLine("Carries seven people.");  
        }  
    }  
  
}  

Lihat juga