Functor'lar ve Lambda İfadeleri
Coddy'nin C++ Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 74 / 104.
Birçok STL algoritması, davranışlarını özelleştiren çağrılabilir bir nesneyi kabul eder. std::transform ile lambda ifadelerinin kullanıldığını zaten gördün. Hem functor’ları hem de lambda ifadelerini — C++’ta çağrılabilir nesneler oluşturmanın iki yolunu — inceleyelim.
Functor (fonksiyon nesnesi), operator() işlecini aşırı yükleyen ve örneklerinin fonksiyonlar gibi çağrılmasına olanak tanıyan bir sınıftır:
#include <algorithm>
#include <vector>
#include <iostream>
struct MultiplyBy {
int factor;
MultiplyBy(int f) : factor(f) {}
int operator()(int x) const {
return x * factor;
}
};
int main() {
std::vector<int> nums = {1, 2, 3, 4};
std::vector<int> result(nums.size());
std::transform(nums.begin(), nums.end(), result.begin(), MultiplyBy(3));
// result: {3, 6, 9, 12}
}Her functor örneği, oluşturulurken ayarlanan üye değişkenler aracılığıyla kendi bağımsız durumunu taşıyabilir; sıradan bir işlev çağrısı bunu yapamaz. Ancak basit işlemler için bir sınıf tanımlamak ayrıntı gerektirir. Lambda ifadeleri kısa ve öz bir alternatif sunar:
int factor = 3;
std::transform(nums.begin(), nums.end(), result.begin(),
[factor](int x) { return x * factor; });Lambda sözdizimi [capture](parameters) { body } şeklindedir. Yakalama yan tümcesi, lambda'nın hangi dış değişkenlere erişebileceğini belirtir. Tüm değişkenleri değer yoluyla yakalamak için [=], tüm değişkenleri referans yoluyla yakalamak için [&] kullanın veya [factor] ya da [&factor] gibi belirli değişkenleri listeleyin.
Lambdalar, özel ölçütlerle sıralama gibi algoritmalarla tek seferlik işlemler için özellikle kullanışlıdır:
std::vector<int> nums = {5, -2, 8, -1};
std::sort(nums.begin(), nums.end(),
[](int a, int b) { return std::abs(a) < std::abs(b); });
// Mutlak değere göre sıralandı: {-1, -2, 5, 8}Görev
KolayÜrün fiyatlarına farklı indirim stratejileri uygulamak için hem functor'ları hem de lambda ifadelerini gösteren bir fiyat hesaplayıcı oluşturalım.
Kodunuzu iki dosyaya ayıracaksınız:
Discounts.h: İndirim functor'larınızı ve yardımcı işlevlerinizi burada tanımlayın.Bir indirim yüzdesini (tam sayı olarak) saklayan
PercentageDiscountadlı bir functor oluşturun.operator()işlevi birdoublefiyat almalı ve indirimli fiyatı döndürmelidir. Örneğin, $100 için %20 indirim $80 döndürmelidir.Çıkarılacak sabit bir miktarı (bir
FixedDiscountolarak) saklayandoubleadlı başka bir functor oluşturun.operator()işlevi bir fiyat almalı ve sabit miktarın çıkarıldığı fiyatı döndürmelidir (ancak sonuç hiçbir zaman 0'ın altında olmamalıdır).Bir
printPricesalan ve tüm fiyatları boşluklarla ayırarak, ardından bir satır sonu ekleyerek yazdıranconst std::vector<double>&adlı bir işlev oluşturun. Her fiyatı iki ondalık basamakla biçimlendirin.main.cpp: Beş girdi okuyun (her biri ayrı bir satırda):- Birinci ürün fiyatı (double)
- İkinci ürün fiyatı (double)
- Üçüncü ürün fiyatı (double)
- Uygulanacak yüzde indirimi (tam sayı; örneğin, %20 için 20)
- Sabit indirim miktarı (double)
Üç fiyatı içeren bir vektör oluşturun ve her iki yaklaşımı gösterin:
- Fiyatların önünde
Original prices:yazdırın - İndirimli fiyatlardan oluşan yeni bir vektör oluşturmak için
std::transformfunctor'ınızlaPercentageDiscountkullanın. Sonuçların önündeAfter percentage discount:yazdırın - Başka bir vektör oluşturmak için özgün fiyatlar üzerinde
std::transformfunctor'ınızlaFixedDiscountkullanın. Sonuçların önündeAfter fixed discount:yazdırın - Her özgün fiyatı iki katına çıkaran bir lambda ifadesiyle
std::transformkullanın. Sonuçların önündePremium prices (doubled):yazdırın - Özgün fiyatları azalan düzende sıralamak için bir lambda ile
std::sortkullanın. Sıralanmış fiyatların önündeSorted (high to low):yazdırın
Örneğin, girdiler 100.00, 50.00, 75.00, 20 ve 15.00 olduğunda:
Original prices: 100.00 50.00 75.00
After percentage discount: 80.00 40.00 60.00
After fixed discount: 85.00 35.00 60.00
Premium prices (doubled): 200.00 100.00 150.00
Sorted (high to low): 100.00 75.00 50.00 Bu alıştırma, functor'ları (indirim miktarı gibi durumu koruyan) lambda'larla (hızlı, satır içi işlemler için değişkenleri yakalayan) karşılaştırmanızı sağlar. Her iki yaklaşım da std::transform ve std::sort gibi STL algoritmalarıyla sorunsuz bir şekilde çalışır.
Kendin dene
#include <iostream>
#include <vector>
#include <algorithm>
#include "Discounts.h"
int main() {
// Girdileri oku
double price1, price2, price3;
int percentageDiscount;
double fixedDiscount;
std::cin >> price1;
std::cin >> price2;
std::cin >> price3;
std::cin >> percentageDiscount;
std::cin >> fixedDiscount;
// Üç fiyatla bir vektör oluştur
std::vector<double> prices = {price1, price2, price3};
// TODO: Print "Original prices:" followed by the prices using printPrices
// TODO: Use std::transform with PercentageDiscount functor
// Sonuçlar için yeni bir vektör oluştur
// Print "After percentage discount:" followed by the results
// TODO: Use std::transform with FixedDiscount functor on original prices
// Sonuçlar için yeni bir vektör oluştur
// Print "After fixed discount:" followed by the results
// TODO: Use std::transform with a lambda that doubles each original price
// Sonuçlar için yeni bir vektör oluştur
// Print "Premium prices (doubled):" followed by the results
// TODO: Use std::sort with a lambda to sort original prices in descending order
// Print "Sorted (high to low):" followed by the sorted prices
return 0;
}
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
1OOP Temelleri
Harici DosyalarC++ Build ve DerlemeBaşlık Dosyaları ve Kaynak DosyalarıAd Alanları ve KapsamC++'ta OOP'ye GirişSınıflar ve Nesneler'this' İşaretçisiMetotlar (Üye Fonksiyonlar)Öznitelikler (Veri Üyeleri)Ctor ve Dtor TemelleriÖzet - Basit Hesap Makinesi4Sınıf Özellikleri
Örnek ve Statik ÜyelerGetter ve Setter MetotlarıConst Üye FonksiyonlarMutable Anahtar KelimesiStatik Metotlar ve DeğişkenlerFriend Fonksiyonlar ve SınıflarÖzet - Banka Hesabı Yöneticisi7Kalıtım
Temel KalıtımKalıtım Erişim SeviyeleriCtor ve Dtor Çağrılma SırasıMetot Geçersiz KılmaSanal Fonksiyonlar ve VTableÇoklu KalıtımSanal KalıtımÖzet - Çalışan Hiyerarşisi10STL Genel Bakış
STL Genel Bakış ve FelsefesiSTL KonteynerleriİteratörlerSTL AlgoritmalarıFunctor'lar ve Lambda İfadeleriÖzet - Kelime Frekansı13Tasarım Kalıpları 1. Bölüm
Tasarım Kalıplarına GirişSingleton KalıbıFactory ve Abstract FactoryBuilder KalıbıObserver KalıbıStrategy Kalıbı2Bellek Yönetimi
Stack ve Heap Bellekİşaretçiler ve ReferanslarDinamik Bellek (new/delete)C++'ta Akıllı İşaretçilerC++'ta RAIIÖzet - Dinamik Dizi Yöneticisi5Kapsülleme
C++'da Erişim BelirleyicilerDerinlemesine Erişim BelirleyicilerBilgi GizlemeStruct vs Classİç İçe ve Dahili SınıflarÖzet - Öğrenci Kayıt Sistemi8Çok Biçimlilik
Derleme ve Çalışma Zamanı Çok BiçimliliğiFonksiyon Aşırı YüklemeSanal Fonksiyonlara Yeniden BakışSaf Sanal FonksiyonlarSoyut SınıflarC++'ta Arayüz TasarımıDynamic Casting ve RTTIÖzet - Şekil Hesaplayıcı3Yapıcılar ve Yıkıcılar
Varsayılan YapıcıParametreli YapıcıKopya YapıcıTaşıma YapıcısıYapıcı İlklendirme ListeleriTemsilci YapıcılarYıkıcılara Derinlemesine BakışÜç / Beş / Sıfır KuralıÖzet - String Sınıfı6Operatör Aşırı Yükleme
Operatör Aşırı Yüklemeye GirişAritmetik Operatör Aşırı YüklemeKarşılaştırma Operatörü Aşırı YüklemeStream OperatörleriAtama Operatörü Aşırı Yükleme[] ve () Operatör Aşırı YüklemeTip Dönüşüm OperatörleriÖzet - Matris Sınıfı9Şablonlar
Fonksiyon ŞablonlarıSınıf ŞablonlarıŞablon ÖzelleştirmeVariadic ŞablonlarSFINAE ve Type Traits TemelleriÖzet - Generic KonteynerKendi başına pratik yap: Online C++ derleyicisi