Menu
Coddy logo textTech

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ı: 50

Bu, 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.

challenge icon

Görev

Kolay

Yukarı ç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 bir Vehicle yapısı oluşturun: speed (mevcut hız için bir tam sayı) ve max_speed (taşıtın en yüksek hızı için bir tam sayı). Ardından, ilk üyesi olarak Vehicle yapısını barındıran ve bir has_sidecar alanı (1 evet, 0 hayır anlamına gelen bir tam sayı) ekleyen bir Motorcycle yapısı tanımlayın. İki fonksiyon bildirin: Bir Vehicle* ve hızı artırmak için bir miktar alan boost fonksiyonu ve bir Motorcycle* alan print_motorcycle fonksiyonu.
  • vehicle.c: Her iki fonksiyonu da uygulayın. boost fonksiyonunuz taşıtın hızını verilen miktar kadar artırmalı, ancak bunu max_speed ile sınırlandırmalıdır; eğer yeni hız maksimumu aşarsa, hızı max_speed değerine eşitleyin. print_motorcycle fonksiyonunuz, barındırılan taşıt verileri de dahil olmak üzere motosikletin tüm bilgilerini görüntülemelidir.
  • main.c: Bir Motorcycle oluşturun ve tüm alanlarını başlatın. Ardından boost fonksiyonunu çağırarak yukarı çevrimi gösterin; bu genel fonksiyona iletmek için Motorcycle* işaretçinizi bir Vehicle* 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: Yes

Burada 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ı: 50

Bu, 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;
}
quiz iconKendini test et

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