Upcasting
Coddy'nin C Journey'sinin Object Oriented Programming bölümünün bir parçası — ders 31 / 61.
Upcasting, belirli bir (türetilmiş) türü daha genel (temel) türüymüş gibi ele alma eylemidir. C'nin kompozisyon modelinde bu, bir temel türü barındıran bir struct yapısına ait bir işaretçiyi, temel türü bekleyen bir fonksiyona iletmek anlamına gelir.
Bir Vehicle temel yapısını (struct) ve onu içeren bir Car yapısını ele alalım:
typedef struct {
int speed;
} Vehicle;
typedef struct {
Vehicle vehicle; // İlk üye olarak temel yapı
int doors;
} Car;Şimdi herhangi bir araçla çalışan genel bir fonksiyon hayal edin:
void accelerate(Vehicle* v, int amount) {
v->speed += amount;
}İlk üye kuralı sayesinde, bir Car* nesnesini Vehicle* türüne dönüştürerek bu fonksiyona geçirebiliriz:
Car my_car = {{0}, 4}; // hız=0, kapılar=4
accelerate((Vehicle*)&my_car, 50);
printf("Speed: %d\n", my_car.vehicle.speed); // Çıktı: 50Bu, yukarı çevrimdir (upcasting) — belirli bir türden genel bir türe doğru "yukarı" hareket ediyoruz. accelerate fonksiyonu bir Car ile çalıştığını bilmez; sadece bir Vehicle görür. Bu, onu gömen herhangi bir türetilmiş türü kabul ederken, temel tür üzerinde çalışan yeniden kullanılabilir kodlar yazmanıza olanak tanır.
Görev
KolayYukarı çevrim (upcasting) işlemini uygulamalı olarak gösteren basit bir ulaşım sistemi inşa edelim. Temel bir Vehicle türü ve daha spesifik bir Motorcycle türü oluşturacak, ardından genel bir fonksiyonun işaretçi dönüştürme (pointer casting) yoluyla her ikisiyle de nasıl çalışabileceğini göstereceksiniz.
Yukarı çevrimin gücü, temel tür için fonksiyonlar yazabilmeniz ve bu fonksiyonların onu barındıran herhangi bir türetilmiş türle sorunsuz bir şekilde çalışabilmesidir. Motosikletiniz bir taşıttır ("is a" vehicle), bu nedenle Vehicle* bekleyen herhangi bir fonksiyon onu işleyebilmelidir.
Kodunuzu üç dosya halinde düzenleyeceksiniz:
vehicle.h: Yapı (struct) hiyerarşinizi "include guard" kullanarak tanımlayın. İki alanı olan birVehicleyapısı oluşturun:speed(mevcut hız için bir tam sayı) vemax_speed(taşıtın en yüksek hızı için bir tam sayı). Ardından, ilk üyesi olarakVehicleyapısını barındıran ve birhas_sidecaralanı (1 evet, 0 hayır anlamına gelen bir tam sayı) ekleyen birMotorcycleyapısı tanımlayın. İki fonksiyon bildirin: BirVehicle*ve hızı artırmak için bir miktar alanboostfonksiyonu ve birMotorcycle*alanprint_motorcyclefonksiyonu.vehicle.c: Her iki fonksiyonu da uygulayın.boostfonksiyonunuz taşıtın hızını verilen miktar kadar artırmalı, ancak bunumax_speedile sınırlandırmalıdır; eğer yeni hız maksimumu aşarsa, hızımax_speeddeğerine eşitleyin.print_motorcyclefonksiyonunuz, barındırılan taşıt verileri de dahil olmak üzere motosikletin tüm bilgilerini görüntülemelidir.main.c: BirMotorcycleoluşturun ve tüm alanlarını başlatın. Ardındanboostfonksiyonunu çağırarak yukarı çevrimi gösterin; bu genel fonksiyona iletmek içinMotorcycle*işaretçinizi birVehicle*işaretçisine dönüştürün. Hız artırma işleminden sonra, sonucu görmek için motosikletin bilgilerini yazdırın.
Dört girdi alacaksınız: motosikletin ilk hızı, maksimum hızı, sepeti olup olmadığı (1 veya 0) ve hız artırma miktarı.
Çıktınız şu şekilde görünmelidir:
Speed: 75
Max Speed: 120
Sidecar: YesBurada 75 hız artırma sonrası hızı (ilk 50 + artış 25), 120 maksimum hızı temsil eder ve Yes veya No motosikletin sepeti olup olmadığını belirtir. Eğer hız artışı hızı max_speed değerinin üzerine çıkarırsa, hız max_speed değerinde sabitlenmelidir.
Buradaki temel öğrenme noktası, boost fonksiyonunun motosikletler hakkında hiçbir şey bilmemesidir; o sadece Vehicle ile çalışır. Yine de yukarı çevrim sayesinde, motosikletiniz barındırdığı taşıt verilerini değiştirmek için bu genel fonksiyonu kullanabilir.
Kopya kağıdı
Upcasting, bir temel türü (base type) gömen bir struct'a ait işaretçiyi, o temel türü bekleyen bir fonksiyona geçirerek, belirli bir (türetilmiş - derived) türü daha genel (temel) türüymüş gibi ele alır.
Bir temel struct ve onu ilk üye olarak gömen türetilmiş bir struct tanımlayın:
typedef struct {
int speed;
} Vehicle;
typedef struct {
Vehicle vehicle; // İlk üye olarak temel yapı
int doors;
} Car;Temel tür ile çalışan bir fonksiyon oluşturun:
void accelerate(Vehicle* v, int amount) {
v->speed += amount;
}Fonksiyonu çağırmak için türetilmiş tür işaretçisini temel tür işaretçisine dönüştürün (cast):
Car my_car = {{0}, 4}; // speed=0, doors=4
accelerate((Vehicle*)&my_car, 50);
printf("Speed: %d\n", my_car.vehicle.speed); // Çıktı: 50Bu, onu gömen herhangi bir türetilmiş türü kabul ederken, temel tür üzerinde işlem yapan yeniden kullanılabilir kodlar yazmanıza olanak tanır.
Kendin dene
#include <stdio.h>
#include "vehicle.h"
int main() {
int initial_speed, max_speed, has_sidecar, boost_amount;
// Girdileri oku
scanf("%d", &initial_speed);
scanf("%d", &max_speed);
scanf("%d", &has_sidecar);
scanf("%d", &boost_amount);
// TODO: Bir Motorcycle oluşturun ve tüm alanlarını ilklendirin
// Unutmayın: Motorcycle, ilk üyesi olarak Vehicle yapısını barındırır
// TODO: boost fonksiyonunu çağırarak upcasting işlemini gösterin
// boost fonksiyonuna iletmek için Motorcycle* türünü Vehicle* türüne dönüştürün (cast)
// TODO: Motosikletin bilgilerini yazdırın
return 0;
}
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Object Oriented Programming bölümündeki tüm dersler
1Modüler Programlama Temelleri
Başlık DosyalarıInclude Guard'larKaynak DosyalarıStatik FonksiyonlarÖzet: Modüler Hesap Makinesi4Kapsülleme
Opaque Pointer KavramıOpaque Struct TanımlamaGetter ve Setter MetotlarıSetter Metotlarında DoğrulamaÖzet: Gizli Kutu2Nesneler ve Metotlar
Nesne Olarak Struct'lar'Self' İşaretçisiConst Doğruluğuİşaretçi vs DeğerYardımcı MetotlarÖzet: Point Manager5Proje: Basit Banka Hesabı
Proje KurulumuHesabın Oluşturulması3Nesne Yaşam Döngüsü
Constructor DeseniDestructor DeseniStack İlklendirmeDerin KopyalamaÖzet: String Wrapper6Kompozisyon Yoluyla Kalıtım
Struct Gömmeİlk Üye KuralıÜst Üyelere ErişimUpcastingÖzet: Şekil Hiyerarşisi