פונקטורים וביטויי למבדה
חלק מהיחידה תכנות מונחה עצמים במסלול ה-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}אתגר
קלבואו נבנה מחשבון מחירים שמדגים גם פונקטורים וגם ביטויי למבדה להחלת אסטרטגיות הנחה שונות על מחירי מוצרים.
תארגן את הקוד שלך בשני קבצים:
Discounts.h: הגדר כאן את פונקטורי ההנחה ואת פונקציות העזר שלך.צור פונקטור בשם
PercentageDiscountששומר אחוז הנחה (כמספר שלם).operator()שלו צריך לקבל מחיר מסוגdoubleולהחזיר את המחיר לאחר ההנחה. לדוגמה, הנחה של 20% על $100 צריכה להחזיר $80.צור פונקטור נוסף בשם
FixedDiscountששומר סכום קבוע שיש להפחית (מסוגdouble).operator()שלו צריך לקבל מחיר ולהחזיר את המחיר פחות הסכום הקבוע (אך לעולם לא פחות מ-0).צור פונקציה בשם
printPricesשמקבלתconst std::vector<double>&ומדפיסה את כל המחירים מופרדים ברווחים, ואחריהם ירידת שורה. עצב כל מחיר עם שתי ספרות אחרי הנקודה העשרונית.main.cpp: קרא חמישה ערכי קלט (כל אחד בשורה נפרדת):- מחיר המוצר הראשון (double)
- מחיר המוצר השני (double)
- מחיר המוצר השלישי (double)
- אחוז ההנחה להחלה (מספר שלם, למשל 20 עבור 20%)
- סכום ההנחה הקבועה (double)
צור מערך עם שלושת המחירים והדגם את שתי הגישות:
- הדפס
Original prices:ואחריו המחירים - השתמש ב-
std::transformעם פונקטור ה-PercentageDiscountשלך כדי ליצור מערך חדש של מחירים לאחר הנחה. הדפסAfter percentage discount:ואחריו התוצאות - השתמש ב-
std::transformעם פונקטור ה-FixedDiscountשלך על המחירים המקוריים כדי ליצור מערך נוסף. הדפסAfter fixed discount:ואחריו התוצאות - השתמש ב-
std::transformעם ביטוי למבדה שמכפיל כל מחיר מקורי פי שניים. הדפסPremium prices (doubled):ואחריו התוצאות - השתמש ב-
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;
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות OOP
קבצים חיצונייםבנייה וקומפילציה של C++קובצי Header וקובצי מקורמרחבי שמות והיקףמבוא ל-OOP ב-C++מחלקות לעומת אובייקטיםמצביע thisמתודות (פונקציות איבר)תכונות (חברי נתונים)יסודות הבנאים וההורסיםסיכום – מחשבון פשוט4מאפייני מחלקה
חברי מופע לעומת חברים סטטייםגטרים וסטריםפונקציות איבר קבועותמילת המפתח mutableמתודות ומשתנים סטטייםפונקציות ומחלקות ידידותסיכום – מנהל חשבונות בנק7ירושה
ירושה בסיסיתרמות גישה בירושהסדר הקריאות לבנאי ולמפרקדריסת מתודותפונקציות וירטואליות ו־VTableירושה מרובהירושה וירטואליתסיכום – היררכיית עובדים10סקירה כללית של STL
סקירה כללית והפילוסופיה של STLקונטיינרים של STLאיטרטוריםאלגוריתמים של STLפונקטורים וביטויי למבדהסיכום – תדירות מילים2ניהול זיכרון
זיכרון Stack לעומת Heapמצביעים והפניותזיכרון דינמי (new/delete)מצביעים חכמים ב-C++RAII ב-C++סיכום – מנהל מערכים דינמיים5כימוס
מצייני גישה ב-C++מצייני גישה לעומקהסתרת מידעמבנה לעומת מחלקהמחלקות מקוננות ופנימיותסיכום – מערכת רשומות תלמידים8רב־צורתיות
רב־צורתיות בזמן קומפילציה לעומת בזמן ריצההעמסת פונקציותפונקציות וירטואליות — מבט נוסףפונקציות וירטואליות טהורותמחלקות מופשטותתכנון ממשקים ב־C++המרה דינמית ו־RTTIסיכום — מחשבון צורות3בנאים והורסים
בנאי ברירת מחדלבנאי עם פרמטריםבנאי העתקהבנאי העברהרשימות אתחול בבנאיםבנאים מאציליםמעמיקים בנושא הורסיםכלל השלושה / החמישה / האפססיכום – מחלקת String6העמסת אופרטורים
מבוא להעמסת אופרטוריםהעמסת אופרטורים אריתמטייםהעמסת אופרטורי השוואהאופרטורי זרםהעמסת אופרטור השמההעמסת האופרטורים [] ו־()אופרטורים להמרת טיפוסיםסיכום – מחלקת Matrix9תבניות
תבניות פונקציהתבניות מחלקההתמחות תבניותתבניות ארגומנטים משתנותיסודות SFINAE ותכונות טיפוסיםסיכום – מכל גנריתרגלו בעצמכם: קומפיילר C++ אונליין