Menu
Coddy logo textTech

בנאי העתקה

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

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

בנאי ההעתקה מקבל הפניה קבועה לאובייקט מאותה מחלקה:

class Player {
    std::string name;
    int health;
public:
    Player(std::string n, int h) : name(n), health(h) {}
    
    // בנאי העתקה
    Player(const Player& other) {
        name = other.name;
        health = other.health;
    }
};

Player original("Hero", 100);
Player copy = original;    // בנאי ההעתקה נקרא
Player another(original);  // קורא גם לבנאי ההעתקה

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

class Buffer {
    int* data;
    size_t size;
public:
    Buffer(size_t s) : size(s) {
        data = new int[size];
    }
    
    // בנאי העתקה עמוקה
    Buffer(const Buffer& other) : size(other.size) {
        data = new int[size];              // הקצה זיכרון חדש
        for (size_t i = 0; i < size; i++)
            data[i] = other.data[i];       // העתק את התוכן
    }
    
    ~Buffer() { delete[] data; }
};

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

challenge icon

אתגר

קל

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

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

  • MessageLog.h: הגדירו מחלקה בשם MessageLog שמנהלת אוסף הודעות באמצעות זיכרון דינמי. למחלקה שלכם צריכים להיות:
    • חברים פרטיים: מצביע למערך מחרוזות לאחסון הודעות, capacity למספר ההודעות המרבי, ו-count למספר ההודעות הנוכחי
    • בנאי עם פרמטרים שמקבל קיבולת, מקצה את המערך בערימה ומאתחל את count ל-0
    • בנאי העתקה שמבצע העתקה עמוקה: מקצה זיכרון חדש ומעתיק את כל ההודעות מהאובייקט המקור
    • הורס שמשחרר את הזיכרון שהוקצה ומדפיס "MessageLog destroyed"
    • מתודה addMessage(string msg) שמוסיפה הודעה אם יש מקום
    • מתודה getCount() שמחזירה את מספר ההודעות הנוכחי
    • מתודה getMessage(int index) שמחזירה את ההודעה באינדקס הנתון
  • main.cpp: הדגימו שבנאי ההעתקה שלכם יוצר עותק עצמאי. קראו ערך קיבולת ושתי הודעות מהקלט, ואז:
    • צרו MessageLog בשם original עם הקיבולת שהתקבלה בקלט
    • הוסיפו את שתי ההודעות ל-original
    • צרו עותק בשם backup באמצעות בנאי ההעתקה
    • הוסיפו את ההודעה השלישית "New message" ל-original בלבד
    • הדפיסו "Original count: <count>"
    • הדפיסו "Backup count: <count>"
    • הדפיסו את כל ההודעות מתוך backup, הודעה אחת בכל שורה

פורמט הקלט יהיה:

  • שורה ראשונה: קיבולת (מספר שלם)
  • שורה שנייה: ההודעה הראשונה (מחרוזת)
  • שורה שלישית: ההודעה השנייה (מחרוזת)

אם ההעתקה העמוקה שלכם מומשה כראוי, העותק backup יכיל 2 הודעות, בעוד שהמקור יכיל 3: כך תוכיחו שיש להם זיכרון עצמאי. ללא בנאי העתקה מתאים, שניהם היו חולקים את אותו מערך, ושינויים באחד מהם היו משפיעים על השני!

כללו את קובץ הכותרת שלכם ב-main.cpp באמצעות #include "MessageLog.h".

נסו בעצמכם

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

int main() {
    // קרא את הקלט
    int capacity;
    cin >> capacity;
    cin.ignore();
    
    string msg1, msg2;
    getline(cin, msg1);
    getline(cin, msg2);

    // TODO: צור MessageLog בשם 'original' עם הקיבולת מהקלט

    // TODO: הוסף את שתי ההודעות ל-original

    // TODO: צור עותק בשם 'backup' באמצעות בנאי ההעתקה

    // TODO: הוסף את "New message" רק ל-original

    // TODO: הדפס "Original count: <count>"

    // TODO: הדפס "Backup count: <count>"

    // TODO: הדפס את כל ההודעות מ-backup, אחת בכל שורה

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

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

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

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