Menu
Coddy logo textTech

פונקציות איבר קבועות

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

ראית את מילת המפתח const בשיטות getter בשיעור הקודם. אבל מה בדיוק המשמעות של הופעת const אחרי רשימת הפרמטרים של פונקציה? פונקציית חברה const מתחייבת לא לשנות אף אחד מהמשתנים החברים של האובייקט.

class Rectangle {
    int width;
    int height;
public:
    Rectangle(int w, int h) : width(w), height(h) {}
    
    int getArea() const {      // פונקציית חבר מסוג const
        return width * height;  // מותר לקרוא את שדות המחלקה
    }
    
    void setWidth(int w) {     // לא const - משנה את האובייקט
        width = w;
    }
};

ה-const שמופיע אחרי רשימת הפרמטרים אומר לקומפיילר: "הפונקציה הזו לא תשנה את מצב האובייקט." אם תנסה לשנות משתנה חבר בתוך פונקציית const, הקומפיילר יפיק שגיאה.

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

void printArea(const Rectangle& rect) {
    std::cout << rect.getArea();    // OK - getArea() היא פונקציית const
    // rect.setWidth(10);           // ERROR - setWidth() אינה פונקציית const
}

סימון פונקציות כ-const כשהן לא משנות את האובייקט הוא נוהג טוב. הוא מתעד את הכוונה שלך, מאפשר לפונקציה לעבוד עם אובייקטים מסוג const ועוזר למהדר לזהות שינויים מקריים. יש לסמן const כל פונקציית איבר שרק קוראת נתונים.

challenge icon

אתגר

קל

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

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

  • Temperature.h: הגדירו מחלקה בשם Temperature ששומרת ערך טמפרטורה ומספקת דרכים שונות לקרוא אותו ולשנות אותו. המחלקה שלכם צריכה לכלול:
    • איבר פרטי celsius (double) לשמירת הטמפרטורה
    • בנאי שמקבל ערך התחלתי במעלות צלזיוס
    • מתודת getCelsius() שמחזירה את הערך השמור. היא צריכה להיות const, מכיוון שהיא רק קוראת נתונים
    • מתודת getFahrenheit() שמחשבת ומחזירה את הטמפרטורה במעלות פרנהייט באמצעות הנוסחה celsius * 9.0 / 5.0 + 32.0, וגם היא const מכיוון שהיא אינה משנה דבר
    • מתודת getKelvin() שמחזירה את הטמפרטורה בקלווין באמצעות celsius + 273.15: גם היא צריכה להיות const
    • מתודת setCelsius(double value) שמעדכנת את הטמפרטורה השמורה. היא לא יכולה להיות const מכיוון שהיא משנה את האובייקט
    • מתודת adjustBy(double delta) שמוסיפה את ההפרש לטמפרטורה הנוכחית; גם היא לא const
  • main.cpp: הדגימו כיצד פועלות פונקציות איבר מסוג const עם אובייקטים רגילים וגם עם אובייקטים מסוג const. קראו ערך טמפרטורה התחלתי מהקלט, ואז:
    • צרו אובייקט Temperature עם ערך הקלט
    • הדפיסו "Initial: <celsius>C = <fahrenheit>F = <kelvin>K"
    • כווננו את הטמפרטורה ב-10.0 מעלות
    • הדפיסו "After adjustment: <celsius>C"
    • צרו פונקציית עזר void printReadings(const Temperature& temp) שמקבלת הפניה קבועה ומדפיסה "Reading: <celsius>C, <fahrenheit>F". הפונקציה הזאת יכולה לקרוא רק למתודות const של temp
    • קראו ל-printReadings() עם אובייקט הטמפרטורה שלכם
    • קבעו את הטמפרטורה ל-0.0 (נקודת הקיפאון)
    • הדפיסו "Freezing point: <celsius>C = <fahrenheit>F"

עצבו את כל ערכי הטמפרטורה עם ספרה אחת אחרי הנקודה העשרונית באמצעות std::fixed ו-std::setprecision(1) מתוך <iomanip>.

התובנה המרכזית כאן היא ש-printReadings() מקבלת הפניה קבועה, ולכן היא יכולה לקרוא רק למתודות שמסומנות כ-const. לכן חשוב לסמן כראוי את מתודות האחזור שלכם כ-const. כך הן יכולות לפעול בהקשרים שבהם אי אפשר לשנות את האובייקט.

נסו בעצמכם

#include <iostream>
#include <iomanip>
#include "Temperature.h"
using namespace std;

// TODO: ממשו כאן את המתודות של המחלקה Temperature
// בנאי
Temperature::Temperature(double initialCelsius) {
    // TODO: אתחלו את celsius
}

// TODO: ממשו את getCelsius() כמתודה מסוג const

// TODO: ממשו את getFahrenheit() כמתודה מסוג const

// TODO: ממשו את getKelvin() כמתודה מסוג const

// TODO: ממשו את setCelsius(double value)

// TODO: ממשו את adjustBy(double delta)


// TODO: צרו פונקציית עזר printReadings שמקבלת const Temperature& 
// ומדפיסה "Reading: <celsius>C, <fahrenheit>F"
// הערה: פונקציה זו יכולה לקרוא רק למתודות מסוג const של temp!


int main() {
    double initialTemp;
    cin >> initialTemp;

    // הגדירו את תבנית הפלט
    cout << fixed << setprecision(1);

    // TODO: צור אובייקט Temperature עם ערך הקלט

    // TODO: הדפס "Initial: <celsius>C = <fahrenheit>F = <kelvin>K"

    // TODO: שנה את הטמפרטורה ב-10.0 מעלות

    // TODO: הדפס "After adjustment: <celsius>C"

    // TODO: קרא ל-printReadings() עם אובייקט הטמפרטורה שלך

    // TODO: הגדר את הטמפרטורה ל-0.0 (נקודת הקיפאון)

    // TODO: הדפס "Freezing point: <celsius>C = <fahrenheit>F"

    return 0;
}
quiz iconבחנו את עצמכם

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

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

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