Temel Sınıf Referansları ve Türetilmiş Nesneler [10]

Bildiğiniz gibi, C# veri tiplerine sıkı sıkıya bağlı bir dildir. Standart dönüşümler ve basit tiplere uygulanan otomatik terfiler bir yana, tip uyumluluğu kesinlikle zorlanır. Bu yüzden, bir sınıf tipindeki bir referans değişkeni normalde bir başka sınıf tipindeki nesneye referans bulunamaz. Örneğin, aşağıdaki programı ele alın:

// Bu program calismayacaktir.
class X {
int a;
public X(int i){ a=i; }
}
class Y {
int a;
public Y(int i) { a=i; }
}

class IncompatibleRef {
public static void Main() {
X x=new X(10);
X x2;
Y y=new Y(5);

x2=x; // OK, her ikiside ayni tipte
x2=y; // Hata, ayni tipte degiller
}
}

Bu örnekte, X ve Y sınıfları fiziksel olarak aynı olmalarına rağmen bir y nesnesini bir X referans değişkenine atamak mümkün değildir, çünkü tipleri farklıdır. Genel olarak, bir nesne referans değişkeni yalnızca kendi tipindeki neslere referansta bulunabilir. Ancak, C#ın tipler üzzerindeki katı baskısının önemli bir istisnası mevcuttur. Bir temel sınıfa ait referans değişkenine, bu temel sınıftan türetilmiş herhangi bir sınıfa ait bir nesnenin referansı değer olarak atanabilir. İşte bir örnek:

// temel sinif referansi, turetilmis sinif nesnesine referansta bulunabilir.
using System;
class X {
public int a;
public X(int i) {
a=i;
}
}

class Y : X {
public int b;
public Y (int i, int j) : base (j) {
b=i;
}
}

class BaseRef {
public static void Main() {
X x=new X(10);
X x2;
Y y=new Y(5, 6);
x2=x; // OK, her ikisi de ayni tipte
Console.WriteLine("x2.a: " + x2.a);
x2=y; // bu da tamam cunku Y, X'ten turetiliyor
Console.WriteLine("x2.a: " + x2.a);
// X referansları yalnızca X'in uyeleri hakkinda bilgi sahibi
x2.a=19; // OK
x2.b=27; // Hata, X'in b adinda bir uyesi yok
}
}

Bu örnekte Y artık X'ten türetilmektedir. Böylece, x2'ye bir Y nesnesini gösteren referans değer olarak atanabilir. Hangi üyelerin erişebileceğinibelirleyen referans değişkeninin tipidir; referans değişkeninin referansta bulunduğu nesnenin tipi değildir. Yani, bir türetilmiş sınıf nesnesine referans olarak bir temel sınıf referans değişkeni atanırken söz konusu nesnenin yalnızca temel sınıf tarafından tanımlanan parçalarına erişim iznine sahip olacaksınız. x2'nin bir Y nesnesine referansta bulunmasına rağmen b değerine erişemiyor olmasının nedeni budur. Çünkü türetilmiş sınıfın kendi içinde temel sınıfa neler eklediğinden, temel sınıfın haberi yoktur. Programın son satırının açıklama şeklinde programdan çıkarılması da işte bu sebeptendir.
Yukarıda anlatılanlar, deyim yerindeyse bir parça "uçuk" görünüyor olsa da, bunların bazı önemli pratik uygulamaları mevcuttur. Bu uygulamalardan biri burada anlatılmaktadır. Diğeri ise sanal metotlar anlatılırken ele alınacaktır. Türetilmiş sınıf referanslarına temel sınıf değişkenlerinin atandığı önemli yerlerden biri, bir sınıf hiyerarşisi içinde yapılandırıcılar çağrıldığı zamandır.
Aşağıdaki TwoDShape ve Triangle'ın versiyonlarını ele alın. Bu sınıfların her ikisi de parametre olarak bir nesne alan yapılandırıcı eklemektedir.

// Bir turetilmis sinif referansini bir temel sinif referansina aktarmak.
using System;
class TwoDShape {
double pri_width; // ozel
double pri_height; // ozel
// Varsayilan yapilandirici
public TwoDShape() {
width=height=0.0;
}
// TwoDShape için yapilandirici.
public TwoDShape (double w, double h) {
width=w;
height=h;
}
// Esit width ve height degerlerine sahip bir nesne yapilandir.
public TwoDShape(double x) {
width=height=x;
}
// Bir nesneden bir baska nesne yapilandir.
public TwoDShape(TwoDShape ob) {
width=ob.width;
height=ob.height;
}
// width height icin ozellikler.
public double width {
get { return pri_width; }
set { pri_width=value; }
}
public double height {
get { return pri_height; }
set { pri_height=value; }
}
public void showDim() {
Console.WriteLine("Width and height are " + width + " and " + height);
}
}

// Ucgenler icin TwoDShape'ten turetilen bir sinif.
class Triangle : TwoDShape {
string style; // ozel
// Varsayilan yapilandirici.
public Triangle() {
style="null";
}
// Triangle icin yapilandirici.
public Triangle(string s, double w, double h) : base(w, h) {
style=s;
}
// Bir ikizkenar ucgen yapilandir.
public Triangle(double x) : base(x) {
style="isosceles";
}
// Bir nesneden baska bir nesne yapilandir.
public Triangle(Triangle ob) : base(ob) {
style=ob.style;
}
// Ucgenin alanini dondur.
public double area() {
return width*height/2;
}
// Ucgenin seklini soster.
public void showStyle() {
Console.WriteLine("Triangle is " + style);
}
}

class Shapes7 {
public static void Main() {
Triangle t1=new Triangle("right", 8.0, 12.0);
// t1'in kopyasini cikart
Triangle t2=new Triangle(t1);
Console.WriteLine("Info for t1: ");
t1.showStyle();
t1.showDim();
Console.WriteLine("Area is " + t1.area());
Console.WriteLine();
Console.WriteLine("Info for t2: ");
t2.showStyle();
t2.showDim();
Console.WriteLine("Area is " + t2.area());
}
}

Bu programda t2, t1 kullanılarak kurulmuştur. Bu nedenle, her ikisi de aynıdır.

Info for t1:
Triangle is right
Width and height are 8 and 12
Area is 48

Info for t1:
Triangle is right
Width and height are 8 and 12
Area is 48

Bu Triangle yapılandırıcına özellikler dikkat edin:

// Bir nesneden baska bir nesne yapilandir.
public Triangle(Triangle ob) : base(ob) {
style=ob.style;
}

Bu yapılandırıcı Triangle tipinde bir nesne alır ve bu nesneyi (base aracılığıyla) aşağıda gösterilen TwoDShape yapılandırıcısına aktarır:

// Bir nesneden bir baska nesne yapilandir.
public TwoDShape(TwoDShape ob) {
width=ob.width;
height=ob.height;
}

Buradaki en önemli nokta, TwoDShape()'in bir TwoDShape() nesnesi bekliyor olmasıdır. Ancak Triangle(), bir Triangle nesnesi aktarır. Önceden açıklandığı gibi, bu kod çalışır. çünkü temel sınıf tipindeki bir referans, bir türetilmiş sınıf nesnesine referansta bulunabilir. Bu nedenle, TwoDShape() tipinde bir referansı, TwoDShape'ten türerilmiş bir sınıfın nesnesine aktarmak kesinlikle kabul edilebilir bir yaklaşımdır. TwoDShape() yapılandırıcısı, türerilmiş sınıf nesnesinin yalnızca TwoDShape üyesi olan kısımlarına ilk değer atadığı için, söz konusu nesnenin türerilmiş sınıflar tarafından eklenmiş nbaşka üyeler de içerebilecek olması önemli değildir.

Kaynak: Herbert Schildt
Herkes için C#

Hiç yorum yok:

Yorum Gönder