Menu
Coddy logo textTech

Derleme ve Çalışma Zamanı Çok Biçimliliği

Coddy'nin C++ Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 56 / 104.

Çok biçimlilik, "çok biçim" anlamına gelir ve nesnelerin farklı davranırken tek tipmiş gibi ele alınmasını sağlayan temel bir OOP kavramıdır. C++, her biri program yürütmesinin farklı bir aşamasında çözümlenen iki farklı çok biçimlilik türünü destekler.

Derleme zamanı polimorfizmi (statik polimorfizm olarak da adlandırılır), program çalışmadan önce derleyici tarafından çözümlenir. Derleyici, fonksiyon imzasına göre hangi fonksiyonun çağrılacağını tam olarak belirler. Buna fonksiyon aşırı yükleme ve şablonlar dahildir:

void print(int x) { std::cout << "Integer: " << x << std::endl; }
void print(double x) { std::cout << "Double: " << x << std::endl; }

print(5);      // Derleyici print(int) seçer
print(3.14);   // Derleyici print(double) seçer

Çalışma zamanı çok biçimliliği (dinamik çok biçimlilik olarak da adlandırılır), program çalışırken çözümlenir. Hangi fonksiyonun çağrılacağına ilişkin karar, işaretçi veya başvuru türüne değil, gerçek nesne türüne bağlıdır. Bu, sanal fonksiyonlar aracılığıyla gerçekleştirilir:

class Shape {
public:
    virtual void draw() { std::cout << "Drawing shape" << std::endl; }
};

class Circle : public Shape {
public:
    void draw() override { std::cout << "Drawing circle" << std::endl; }
};

Shape* s = new Circle();
s->draw();  // Çalışma zamanında karar verildi: "Drawing circle"

Temel ödünleşim şudur: derleme zamanı çok biçimliliği, kararlar derleme sırasında verildiği için çalışma zamanı ek yükü oluşturmazken, çalışma zamanı çok biçimliliği küçük bir maliyet ekler (vtable araması) ancak türleri yürütme zamanına kadar bilinmeyen nesnelerle çalışırken daha fazla esneklik sağlar.

challenge icon

Görev

Kolay

Her iki çok biçimlilik türünü yan yana gösteren bir hesap makinesi sistemi oluşturalım. Derleme zamanı çok biçimliliğinin farklı girdi türlerini işlev aşırı yükleme yoluyla ele aldığı, çalışma zamanı çok biçimliliğinin ise farklı hesaplama stratejilerinin dinamik olarak değiştirilmesine olanak tanıdığı bir sistem oluşturacaksın.

Kodunu üç dosyaya ayıracaksın:

  • Calculator.h: Herhangi bir hesaplama stratejisini temsil eden temel bir Calculator sınıfı tanımla:
    • calculate(int a, int b) döndüren ve int yazdıran (0 döndüren) sanal bir Base calculation: <a> ? <b> metodu
    • Sanal bir yıkıcı
  • Operations.h: Hesaplama davranışını geçersiz kılan, türetilmiş iki hesap makinesi sınıfı tanımla:
    • Adder: calculate() metodunu geçersiz kılarak Adding: <a> + <b> yazdır ve toplamı döndür
    • Multiplier: calculate() metodunu geçersiz kılarak Multiplying: <a> * <b> yazdır ve çarpımı döndür
    Her iki sınıf da override anahtar sözcüğünü kullanmalıdır.
  • main.cpp: Her iki çok biçimlilik türünü sergileyen bir sistem oluştur. İki tamsayı girdisi oku (her biri ayrı bir satırda).

    İlk olarak, üç aşırı yüklenmiş display() işlevi oluşturarak derleme zamanı çok biçimliliğini göster:

    • display(int x) şunu yazdırır: Integer value: <x>
    • display(double x) şunu yazdırır: Double value: <x>
    • display(const std::string& x) şunu yazdırır: String value: <x>

    Ardından, temel bir Calculator*, bir Calculator ve bir Adder içeren Multiplier işaretçilerinden oluşan bir dizi oluşturarak çalışma zamanı çok biçimliliğini göster. Döngüyle her birinin üzerinde calculate() metodunu girdi değerlerinle çağır ve her hesaplamadan sonra sonucu yazdır.

    Çıktını aşağıdaki gibi yapılandır:

    === Compile-Time Polymorphism ===
    <display outputs for int, double, string>
    
    === Runtime Polymorphism ===
    <calculate outputs with results>

    Derleme zamanı bölümü için display() metodunu önce ilk girdiyi tamsayı olarak, ardından double olarak (aynı değere .5 eklenmiş hâliyle), sonra da "Result" dizesi olarak çağır. İşin bittiğinde dinamik olarak ayrılmış hesap makinelerinin belleğini temizle.

Örneğin, girdiler 10 ve 3 olduğunda:

=== Compile-Time Polymorphism ===
Integer value: 10
Double value: 10.5
String value: Result

=== Runtime Polymorphism ===
Base calculation: 10 ? 3
Result: 0
Adding: 10 + 3
Result: 13
Multiplying: 10 * 3
Result: 30

Derleyicinin, bağımsız değişken türüne göre doğru display() aşırı yüklemesini (derleme zamanı kararı) seçtiğine, doğru calculate() metodunun ise vtable mekanizması aracılığıyla çalışma zamanında gerçek nesne türü tarafından belirlendiğine dikkat et.

Kendin dene

#include <iostream>
#include <string>
#include "Calculator.h"
#include "Operations.h"

// TODO: Üç aşırı yüklenmiş display() fonksiyonu oluşturun:
// 1. display(int x) - prints "Integer value: <x>"
// 2. display(double x) - "Double value: <x>" yazdırır
// 3. display(const std::string& x) - "String value: <x>" yazdırır



int main() {
    // İki tamsayı girdisi oku
    int a, b;
    std::cin >> a;
    std::cin >> b;
    
    // === Compile-Time Polymorphism ===
    std::cout << "=== Compile-Time Polymorphism ===" << std::endl;
    // TODO: display() fonksiyonunu şunlarla çağırın:
    // - a bir tamsayı olarak
    // - a bir double olarak (0.5 ekleyin)
    // - "Result" dizesi
    
    
    std::cout << std::endl;
    
    // === Runtime Polymorphism ===
    std::cout << "=== Runtime Polymorphism ===" << std::endl;
    // TODO: 3 elemanlı Calculator* işaretçilerinden bir dizi oluşturun:
    // - a base Calculator
    // - bir Adder
    // - bir Multiplier
    
    // TODO: Diziyi döngüyle dolaşın, her birinde calculate(a, b) çağırın,
    // ve her hesaplamadan sonra "Result: <return_value>" yazdır
    
    
    // TODO: Dinamik olarak ayrılmış belleği temizle
    
    
    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.

Nesne Yönelimli Programlama bölümündeki tüm dersler

Kendi başına pratik yap: Online C++ derleyicisi