Menu
Coddy logo textTech

פונקציות ומחלקות ידידות

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

לפעמים פונקציה או מחלקה מחוץ למחלקה שלך זקוקה לגישה לחברים הפרטיים שלה. במקום להפוך את החברים האלה לציבוריים, C++ מספקת את מילת המפתח friend כדי להעניק גישה סלקטיבית תוך שמירה על הכימוס.

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

class Box {
    double width;
    
public:
    Box(double w) : width(w) {}
    
    // הכרז על printWidth כפונקציה ידידה
    friend void printWidth(const Box& b);
};

// הגדרה של פונקציה ידידה - אינה פונקציית מחלקה
void printWidth(const Box& b) {
    std::cout << b.width;    // יכולה לגשת לחבר פרטי במחלקה
}

שימו לב ש-printWidth מוגדרת מחוץ למחלקה ללא אופרטור פתרון תחום. זו פונקציה רגילה שיש לה במקרה הרשאות גישה מיוחדות.

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

class Engine {
    int horsepower;
    
    friend class Mechanic;    // למחלקה Mechanic יש גישה לחברים פרטיים
    
public:
    Engine(int hp) : horsepower(hp) {}
};

class Mechanic {
public:
    void diagnose(const Engine& e) {
        std::cout << e.horsepower;    // מותר - Mechanic היא מחלקה ידידה
    }
};

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

challenge icon

אתגר

קל

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

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

  • SecureMessage.h: הגדירו מחלקה SecureMessage שמאחסנת נתוני הודעה פרטיים ומעניקה גישה סלקטיבית לגורמים מהימנים. המחלקה שלכם צריכה לכלול:
    • חברים פרטיים: content (מחרוזת) ו-secretKey (מספר שלם)
    • בנאי שמקבל את התוכן ואת המפתח הסודי
    • הצהירו על MessageReader כמחלקה ידידותית כדי שתוכל לגשת לחברים פרטיים
    • הצהירו על פונקציה ידידותית decryptMessage(const SecureMessage& msg, int key) שמחזירה את התוכן רק אם המפתח שסופק תואם למפתח הסודי, ובאחרת מחזירה "Access Denied"

    לאחר מכן הגדירו את המחלקה MessageReader באותו קובץ כותרת:

    • מתודה readContent(const SecureMessage& msg) שניגשת ישירות ל-content הפרטי של ההודעה ומחזירה אותו
    • מתודה verifyKey(const SecureMessage& msg, int key) שבודקת אם המפתח שסופק תואם ל-secretKey של ההודעה ומחזירה "Valid" או "Invalid"

    לבסוף, הגדירו את הפונקציה הידידותית decryptMessage אחרי המחלקות.

  • main.cpp: הדגימו את פעולתן של פונקציות ידידותיות ומחלקות ידידותיות. קראו קלט של תוכן הודעה, מפתח סודי ומפתח בדיקה (כל אחד בשורה נפרדת), ואז:
    • צרו SecureMessage עם התוכן והמפתח הסודי
    • צרו אובייקט MessageReader
    • הדפיסו "Reader access: <content>" באמצעות המתודה readContent() של הקורא
    • הדפיסו "Key verification: <result>" באמצעות verifyKey() עם מפתח הבדיקה
    • הדפיסו "Decrypt with test key: <result>" באמצעות הפונקציה הידידותית עם מפתח הבדיקה
    • הדפיסו "Decrypt with correct key: <result>" באמצעות הפונקציה הידידותית עם המפתח הסודי המקורי

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

המירו את קלטי המפתחות ממחרוזות למספרים שלמים באמצעות std::stoi(). כללו את קובץ הכותרת שלכם ב-main.cpp באמצעות #include "SecureMessage.h".

נסו בעצמכם

#include <iostream>
#include <string>
#include "SecureMessage.h"
using namespace std;

int main() {
    // קרא את הקלט
    string messageContent;
    string secretKeyStr;
    string testKeyStr;
    
    getline(cin, messageContent);
    getline(cin, secretKeyStr);
    getline(cin, testKeyStr);
    
    int secretKey = stoi(secretKeyStr);
    int testKey = stoi(testKeyStr);
    
    // TODO: צור SecureMessage עם התוכן והמפתח הסודי
    
    // TODO: צור אובייקט MessageReader
    
    // TODO: הדפס "Reader access: <content>" באמצעות readContent()
    
    // TODO: הדפס "Key verification: <result>" באמצעות verifyKey() עם מפתח הבדיקה
    
    // TODO: הדפס "Decrypt with test key: <result>" באמצעות decryptMessage עם מפתח הבדיקה
    
    // TODO: הדפס "Decrypt with correct key: <result>" באמצעות decryptMessage עם המפתח הסודי
    
    return 0;
}
quiz iconבחנו את עצמכם

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

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

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