Menu
Coddy logo textTech

Saf Sanal Fonksiyonlar

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

Saf sanal işlev, temel sınıfta uygulaması bulunmayan bir sanal işlevdir. İşlev bildirimine = 0 atanarak bildirilir. Bu, derleyiciye türetilmiş sınıfların kendi uygulamalarını zorunlu olarak sağlaması gerektiğini bildirir.

class Shape {
public:
    virtual double area() = 0;  // Saf sanal fonksiyon
    virtual ~Shape() = default;
};

Varsayılan bir davranış sağlayan normal sanal function’ların aksine, saf sanal function’lar bir sözleşme tanımlar: herhangi bir somut türetilmiş class’ın örneği oluşturulabilmek için bu function’ı uygulaması gerekir. Temel class yalnızca ne yapılması gerektiğini, nasıl yapılacağını değil, bildirir.

class Circle : public Shape {
    double radius;
public:
    Circle(double r) : radius(r) {}
    
    double area() override {
        return 3.14159 * radius * radius;
    }
};

class Rectangle : public Shape {
    double width, height;
public:
    Rectangle(double w, double h) : width(w), height(h) {}
    
    double area() override {
        return width * height;
    }
};

Hem Circle hem de Rectangle, Shape içinde saf sanal olduğu için area() işlevini uygulamalıdır. Türetilmiş bir sınıf tüm saf sanal işlevleri uygulamazsa o da soyut hâle gelir ve örneği oluşturulamaz.

Saf sanal işlevler, temel sınıf anlamlı bir varsayılan uygulama sağlayamadığında gereklidir. Her şeklin bir alanı vardır, ancak belirli şekil türünü bilmeden “genel şekil alanını” hesaplamanın mantıklı bir yolu yoktur.

challenge icon

Görev

Kolay

Farklı ödeme yöntemleri arasında saf sanal işlevlerin bir sözleşmeyi nasıl zorunlu kıldığını gösteren bir ödeme işleme sistemi oluşturalım. Tüm ödeme işlemcilerinin ne yapması gerektiğini tanımlayan soyut bir temel sınıf oluşturacak, ardından bu sözleşmeyi yerine getiren somut ödeme türlerini uygulayacaksınız.

Kodunuzu üç dosya arasında düzenleyeceksiniz:

  • PaymentProcessor.h: Tüm ödeme yöntemleri için şablon görevi gören soyut bir PaymentProcessor sınıfı tanımlayın. Bu sınıf şunlara sahip olmalıdır:
    • Korumalı bir std::string accountId üyesi
    • Hesap kimliğini başlatan bir oluşturucu
    • Saf sanal bir processPayment(double amount) yöntemi: her ödeme türü bunu farklı şekilde uygulamalıdır
    • getProcessorName() döndüren saf sanal bir std::string yöntemi
    • Sanal bir yok edici
  • PaymentMethods.h: PaymentProcessor'dan kalıtım alan iki somut ödeme işlemcisi uygulayın:

    CreditCardProcessor:

    • Özel bir double feePercentage üyesi (işlem ücreti oranı)
    • Hesap kimliği ve ücret yüzdesi alan bir oluşturucu
    • Ücreti (amount * feePercentage / 100) hesaplamak ve ardından şunu yazdırmak için processPayment() yöntemini uygulayın:
      Credit Card [<accountId>]: Charged $<amount> (Fee: $<fee>)
    • getProcessorName() döndürecek şekilde "CreditCard" yöntemini uygulayın

    BankTransferProcessor:

    • Özel bir std::string bankName üyesi
    • Hesap kimliği ve banka adı alan bir oluşturucu
    • Şunu yazdırmak için processPayment() yöntemini uygulayın:
      Bank Transfer [<accountId>] via <bankName>: Transferred $<amount>
    • getProcessorName() döndürecek şekilde "BankTransfer" yöntemini uygulayın
  • main.cpp: Dört girdi okuyun (her biri ayrı bir satırda):
    1. Kredi kartı hesap kimliği
    2. Kredi kartı ücret yüzdesi (double)
    3. Banka hesap kimliği
    4. Banka adı

    Her iki ödeme işlemcisini oluşturun ve bunları PaymentProcessor* işaretçilerinden oluşan bir dizide saklayın. Her işlemciden 100.0 tutarında bir ödeme geçirin ve her işlemden önce işlemci adını görüntüleyin:

    Processing with <processorName>:
    <processPayment output>

    İşlemciler arasında boş bir satır yazdırın. İşiniz bittiğinde dinamik olarak ayrılmış nesneleri temizleyin.

Örneğin CC-4521, 2.5, BA-7890 ve National Bank girdileriyle:

Processing with CreditCard:
Credit Card [CC-4521]: Charged $100 (Fee: $2.5)

Processing with BankTransfer:
Bank Transfer [BA-7890] via National Bank: Transferred $100

PaymentProcessor saf sanal işlevlere sahip olduğundan, onu doğrudan örnekleyemezsiniz: yalnızca sözleşmeyi yerine getiren somut uygulamalar oluşturulabilir. Bu, her ödeme yönteminin kendine özgü işleme mantığını sağlamasını garanti eder.

Kendin dene

#include <iostream>
#include <string>
#include "PaymentMethods.h"

using namespace std;

int main() {
    // Girdileri oku
    string ccAccountId;
    double feePercentage;
    string bankAccountId;
    string bankName;
    
    getline(cin, ccAccountId);
    cin >> feePercentage;
    cin.ignore();
    getline(cin, bankAccountId);
    getline(cin, bankName);
    
    // TODO: 2 elemanlı bir PaymentProcessor* işaretçi dizisi oluştur
    
    // TODO: CreditCardProcessor ve BankTransferProcessor nesneleri oluştur
    // ve bunları diziye yerleştir
    
    // TODO: Diziyi döngüyle gez ve her işlemci için:
    // 1. Print "Processing with <processorName>:"
    // 2. processPayment'ı 100.0 tutarıyla çağır
    // 3. İşlemciler arasında boş bir satır yazdır (sonuncudan sonra değil)
    
    // TODO: Dinamik olarak ayrılmış nesneleri 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