Menu
Coddy logo textTech

פונקטורים וביטויי למבדה

חלק מהיחידה תכנות מונחה עצמים במסלול ה-C++ של Coddy. שיעור 74 מתוך 104.

אלגוריתמים רבים ב-STL מקבלים אובייקט שניתן לקרוא לו, שמאפשר להתאים את ההתנהגות שלהם. כבר ראית למבדות בשימוש עם std::transform. בואו נבחן גם פונקטורים וגם ביטויי למבדה — שתי דרכים ליצור אובייקטים שניתן לקרוא להם ב-C++.

פונקטור (אובייקט פונקציה) הוא מחלקה שמבצעת העמסה של operator(), וכך מאפשרת לקרוא למופעים שלה כמו לפונקציות:

#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}
}

כל מופע של פונקטור יכול לשאת מצב עצמאי משלו באמצעות משתני איבר שנקבעים בעת הבנייה — דבר שקריאה רגילה לפונקציה אינה יכולה לעשות. עם זאת, הגדרת מחלקה עבור פעולות פשוטות היא מסורבלת. ביטויי למבדה מספקים חלופה תמציתית:

int factor = 3;
std::transform(nums.begin(), nums.end(), result.begin(),
               [factor](int x) { return x * factor; });
[capture](parameters) { body }. סעיף הלכידה מציין לאילו משתנים חיצוניים הלמבדא יכולה לגשת. השתמשו ב־[=] כדי ללכוד את כולם לפי ערך, ב־[&] כדי ללכוד את כולם לפי הפניה, או ציינו משתנים מסוימים כמו [factor] או [&factor].

ביטויי lambda שימושיים במיוחד לפעולות חד־פעמיות עם אלגוריתמים, כמו מיון לפי קריטריונים מותאמים אישית:

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); });
// ממוינים לפי ערך מוחלט: {-1, -2, 5, 8}
challenge icon

אתגר

קל

בואו נבנה מחשבון מחירים שמדגים גם פונקטורים וגם ביטויי למבדה להחלת אסטרטגיות הנחה שונות על מחירי מוצרים.

תארגן את הקוד שלך בשני קבצים:

  • Discounts.h: הגדר כאן את פונקטורי ההנחה ואת פונקציות העזר שלך.

    צור פונקטור בשם PercentageDiscount ששומר אחוז הנחה (כמספר שלם). operator() שלו צריך לקבל מחיר מסוג double ולהחזיר את המחיר לאחר ההנחה. לדוגמה, הנחה של 20% על $100 צריכה להחזיר $80.

    צור פונקטור נוסף בשם FixedDiscount ששומר סכום קבוע שיש להפחית (מסוג double). operator() שלו צריך לקבל מחיר ולהחזיר את המחיר פחות הסכום הקבוע (אך לעולם לא פחות מ-0).

    צור פונקציה בשם printPrices שמקבלת const std::vector<double>& ומדפיסה את כל המחירים מופרדים ברווחים, ואחריהם ירידת שורה. עצב כל מחיר עם שתי ספרות אחרי הנקודה העשרונית.

  • main.cpp: קרא חמישה ערכי קלט (כל אחד בשורה נפרדת):
    1. מחיר המוצר הראשון (double)
    2. מחיר המוצר השני (double)
    3. מחיר המוצר השלישי (double)
    4. אחוז ההנחה להחלה (מספר שלם, למשל 20 עבור 20%)
    5. סכום ההנחה הקבועה (double)

    צור מערך עם שלושת המחירים והדגם את שתי הגישות:

    1. הדפס Original prices: ואחריו המחירים
    2. השתמש ב-std::transform עם פונקטור ה-PercentageDiscount שלך כדי ליצור מערך חדש של מחירים לאחר הנחה. הדפס After percentage discount: ואחריו התוצאות
    3. השתמש ב-std::transform עם פונקטור ה-FixedDiscount שלך על המחירים המקוריים כדי ליצור מערך נוסף. הדפס After fixed discount: ואחריו התוצאות
    4. השתמש ב-std::transform עם ביטוי למבדה שמכפיל כל מחיר מקורי פי שניים. הדפס Premium prices (doubled): ואחריו התוצאות
    5. השתמש ב-std::sort עם למבדה כדי למיין את המחירים המקוריים בסדר יורד. הדפס Sorted (high to low): ואחריו המחירים הממוינים

לדוגמה, עם ערכי הקלט 100.00, 50.00, 75.00, 20 ו-15.00:

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 

האתגר הזה מאפשר לך להשוות בין פונקטורים (ששומרים מצב, כמו סכום ההנחה) לבין למבדות (שלוכדות משתנים לצורך פעולות מהירות ומוטמעות). שתי הגישות עובדות בצורה חלקה עם אלגוריתמים של STL כמו std::transform ו-std::sort.

נסו בעצמכם

#include <iostream>
#include <vector>
#include <algorithm>
#include "Discounts.h"

int main() {
    // קראו את הקלט
    double price1, price2, price3;
    int percentageDiscount;
    double fixedDiscount;
    
    std::cin >> price1;
    std::cin >> price2;
    std::cin >> price3;
    std::cin >> percentageDiscount;
    std::cin >> fixedDiscount;
    
    // צרו וקטור המכיל את שלושת המחירים
    std::vector<double> prices = {price1, price2, price3};
    
    // TODO: הדפיסו את "Original prices:" ואחריו את המחירים באמצעות printPrices
    
    // TODO: השתמשו ב-std::transform עם הפונקטור PercentageDiscount
    // צרו וקטור חדש עבור התוצאות
    // הדפיסו את "After percentage discount:" ואחריו את התוצאות
    
    // TODO: השתמשו ב-std::transform עם הפונקטור FixedDiscount על המחירים המקוריים
    // צרו וקטור חדש עבור התוצאות
    // הדפיסו את "After fixed discount:" ואחריו את התוצאות
    
    // TODO: השתמשו ב-std::transform עם פונקציית למבדה שמכפילה כל מחיר מקורי פי שניים
    // צרו וקטור חדש עבור התוצאות
    // הדפיסו את "Premium prices (doubled):" ואחריו את התוצאות
    
    // TODO: השתמשו ב-std::sort עם פונקציית למבדה כדי למיין את המחירים המקוריים בסדר יורד
    // הדפיסו את "Sorted (high to low):" ואחריו את המחירים הממוינים
    
    return 0;
}
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר C++ אונליין