Menu
Coddy logo textTech

İlk Üye Kuralı

Coddy'nin C Journey'sinin Object Oriented Programming bölümünün bir parçası — ders 29 / 61.

Bir yapıyı (struct) başka bir yapının ilk üyesi olarak yerleştirdiğinizde, güçlü bir şey gerçekleşir: dıştaki yapının bellek adresi, ilk üyesinin bellek adresi ile aynıdır. Bu, C standardı tarafından garanti edilir.

Önceki örneğimizi ele alalım:

typedef struct {
    int id;
} Parent;

typedef struct {
    Parent parent;  // İlk üye
    int grade;
} Child;

Bir Child değişkeni oluşturduğunuzda, Parent üyesi Child'ın belleğinin en başında yer alır. Bu, Child'a işaret eden bir işaretçinin, onun Parent üyesine işaret eden bir işaretçiyle tam olarak aynı adresi gösterdiği anlamına gelir.

Child c;
Child* child_ptr = &c;
Parent* parent_ptr = (Parent*)child_ptr;  // Güvenli tür dönüşümü!

Her iki işaretçi de aynı adresi tutar. Bu, bir Parent* bekleyen herhangi bir fonksiyona bir Child* geçirmenize olanak tanır:

void print_id(Parent* p) {
    printf("ID: %d\n", p->id);
}

// main içinde:
Child c;
c.parent.id = 42;
print_id((Parent*)&c);  // Kusursuz çalışır

Bu teknik, C'deki kalıtımın temelidir. Temel tür (base type) için yazılmış bir fonksiyon, temel tür ilk sırada yerleştirildiği sürece, türetilmiş herhangi bir tür (derived type) üzerinde çalışabilir. Bellek düzenleri mükemmel bir şekilde hizalandığı için tür dönüşümü (cast) güvenlidir.

challenge icon

Görev

Kolay

Basit bir hayvan hiyerarşisi oluşturarak ilk üye kuralını (first member rule) keşfedelim. Temel bir Animal yapısı (struct) ve türetilmiş bir Dog yapısı oluşturacak, ardından bir Dog işaretçisinin (pointer) güvenli bir şekilde nasıl Animal işaretçisine dönüştürülebileceğini göstereceksiniz.

Uygulayacağınız temel bilgi şudur: Animal, Dog yapısının ilk üyesi olduğunda, her iki yapı da aynı başlangıç bellek adresini paylaşır. Bu, bir işaretçiyi dönüştürerek (casting), Animal* bekleyen herhangi bir fonksiyona Dog* geçirebileceğiniz anlamına gelir.

Kodunuzu üç dosya halinde düzenleyeceksiniz:

  • animal.h: Her iki yapıyı da include guard'lar ile tanımlayın. Animal yapınız tek bir alana sahip olmalıdır: legs (bacak sayısını temsil eden bir tam sayı). Dog yapınız, Animal yapısını ilk üye olarak içine almalı ve bir name alanı (50 karakterlik bir karakter dizisi) eklemelidir. Ayrıca Animal* parametresi alan bir print_animal fonksiyonu bildirin.
  • animal.c: print_animal fonksiyonunu uygulayın. Bu fonksiyon temel tiple çalışır; yalnızca Animal yapısını bilir ve hayvanın kaç bacağı olduğunu yazdırır.
  • main.c: Bir Dog değişkeni oluşturun ve alanlarını doldurun (hem iç içe geçmiş hayvanın bacak sayısını hem de köpeğin adını). Ardından Dog* işaretçinizi bir Animal* işaretçisine dönüştürüp print_animal fonksiyonuna göndererek ilk üye kuralını gösterin. Ayrıca resmin tamamını göstermek için köpeğin adını ayrı olarak yazdırın.

İki girdi alacaksınız: köpeğin adı (bir dize) ve bacak sayısı (bir tam sayı).

Çıktınız şu şekilde görünmelidir:

Dog: Buddy
Legs: 4

Burada Buddy köpeğin adı ve 4 bacak sayısıdır. Önce main.c içinden köpeğin adını yazdırın, ardından bacakları görüntülemek için dönüştürülmüş işaretçi ile print_animal fonksiyonunu çağırın.

bu, temel tip (Animal) için yazılmış bir fonksiyonun, işaretçi dönüşümü yoluyla türetilmiş bir tiple (Dog) nasıl sorunsuz bir şekilde çalışabileceğini gösterir; bu, C dilinde kalıtımın (inheritance) temelidir.

Kopya kağıdı

Bir struct, başka bir struct'ın ilk üyesi olarak gömüldüğünde, her iki struct da aynı başlangıç bellek adresini paylaşır. Bu, C standardı tarafından garanti edilir.

typedef struct {
    int id;
} Parent;

typedef struct {
    Parent parent;  // İlk üye
    int grade;
} Child;

Dıştaki struct'a ait bir pointer, güvenli bir şekilde ilk üyesine ait bir pointer'a dönüştürülebilir:

Child c;
Child* child_ptr = &c;
Parent* parent_ptr = (Parent*)child_ptr;  // Güvenli dönüştürme - aynı adres

Bu, temel türü (base type) bekleyen fonksiyonlara türetilmiş tür (derived type) pointer'ı gönderilmesine olanak tanır:

void print_id(Parent* p) {
    printf("ID: %d\n", p->id);
}

Child c;
c.parent.id = 42;
print_id((Parent*)&c);  // Bellek yerleşimleri hizalandığı için çalışır

Bu teknik, C'de kalıtımın (inheritance) temelidir ve temel türler için yazılmış fonksiyonların türetilmiş türler üzerinde çalışmasını sağlar.

Kendin dene

#include <stdio.h>
#include <string.h>
#include "animal.h"

int main() {
    // Girdiyi oku
    char name[50];
    int legs;
    scanf("%s", name);
    scanf("%d", &legs);
    
    // TODO: Bir Dog değişkeni oluşturun
    
    // TODO: strcpy kullanarak köpeğin adını ayarlayın
    
    // TODO: Bacak sayısını ayarlayın (gömülü Animal üzerinden erişin)
    
    // TODO: Köpeğin adını şu formatta yazdırın: "Dog: <name>"
    
    // TODO: Dog* tipini Animal* tipine dönüştürün ve print_animal fonksiyonunu çağırın
    // Bu, ilk üye kuralını (first member rule) gösterir!
    
    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